Package com.szuppe.jakub.controller

Source Code of com.szuppe.jakub.controller.Controller$NonGameStrategy

/**
*
*/
package com.szuppe.jakub.controller;

import java.util.concurrent.BlockingQueue;

import com.szuppe.jakub.common.ReschedulableTimer;
import com.szuppe.jakub.events.*;
import com.szuppe.jakub.model.AllBricksDestroyedException;
import com.szuppe.jakub.model.Model;
import com.szuppe.jakub.model.NoMoreMapsException;
import com.szuppe.jakub.model.PlayerDiedException;
import com.szuppe.jakub.view.View;
import java.util.HashMap;
import java.util.Map;

/**
* Kontroler jest trzonem aplikacji "Vaus". Zarządza modelem oraz widokiem,
* a także organizuje komunikacje.
*
* @author Jakub Szuppe <j.szuppe at gmail.com>
*/
public class Controller
{
  /** Model. Symuluje świat gry. */
  private final Model                      model;
  /** Widok. Odpowiada za wyświetlanie stanu modelu. */
  private final View                      view;
  /** Kolejka blokująca zdarzeń aplikacji {@link AppEvent} */
  private final BlockingQueue<AppEvent>            eventsBlockingQueue;
  /** Mapa strategii. Każdemu zdarzeniu aplikacji odpowiada strategia. */
  private final Map<Class<? extends AppEvent>, AppStrategy>  strategyMap;
  /** Timer aplikacji. */
  private final ReschedulableTimer              modelTimer;
  /** Zadanie obudzenia modelu, gdy minął czas poprawności jego stanu. */
  private final Runnable                    validTimePassedTask;

  /**
   * Konstruktor. Tworzy obiekt typu {@link Controller}, który jest trzonem aplikacji i
   * zarządza podanym modelem oraz widokiem. Aplikacja nie startuje do czasu wykonania
   * metody {@link #init()}.
   *
   * @param model - model, nad którym odbywa się kontrola.
   * @param view - widok, do który będzie wyświetlał stan modelu.
   * @param eventsBlockingQueue - kolejka blokująca zdarzeń aplikacji.
   */
  public Controller(final Model model, final View view,
      final BlockingQueue<AppEvent> eventsBlockingQueue)
  {
    this.model = model;
    this.view = view;
    this.eventsBlockingQueue = eventsBlockingQueue;
    this.strategyMap = new HashMap<Class<? extends AppEvent>, AppStrategy>();
    this.modelTimer = new ReschedulableTimer();
    this.validTimePassedTask = new Runnable()
    {
      @Override
      public void run()
      {
        eventsBlockingQueue.add(new ValidTimePassedEvent());
      }
    };
    initStrategyMap();
  }

  /**
   * Uruchamia aplikacje.
   */
  public void init()
  {
    view.init();

    // Główną pętla gry.
    while (true)
    {
      AppEvent nextAppEvent = null;

      try
      {
        // Jeżeli nie ma zdarzenia, to usypia.
        nextAppEvent = eventsBlockingQueue.take();
       } catch (InterruptedException e)
      {
        // Nie powinno się zdarzyć.
         throw new RuntimeException();
      }

      strategyMap.get(nextAppEvent.getClass()).process(nextAppEvent);
    }
  }

  /**
   * Wypełnia {@link #strategyMap} strategiami, które odpowiadają wszystkim zdarzeniom,
   * występującym w aplikacji.
   */
  private void initStrategyMap()
  {
    strategyMap.clear();
    strategyMap.put(StartGameEvent.class, new StartGameStrategy());
    strategyMap.put(BallReleaseEvent.class, new BallReleaseStrategy());
    strategyMap.put(MovePaddleEvent.class, new MovePaddleStrategy());
    strategyMap.put(ValidTimePassedEvent.class, new ValidTimePassedStrategy());
    strategyMap.put(LoadNextLevelEvent.class, new LoadNextMapStrategy());
    strategyMap.put(GameWinEvent.class, new GameWinStrategy());
    strategyMap.put(GameLostEvent.class, new GameLostStrategy());
  }

  /**
   * Abstrakcyjna klasa zdarzenia aplikacji. Wszystkie zdarzenia aplikacji powinny
   * rozszerzać tą klasę.
   *
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private abstract class AppStrategy
  {
    public abstract void process(AppEvent appEvent);
  }

  /**
   * Abstrakcyjna klasa zdarzenia zachodzącego w czasie aktywnej rozgrywki. Wszystkie
   * zdarzenia, które zachodzą podczas rozgrywki powinny rozszerzać właśnie tą klasę.
   *
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private abstract class GameStrategy extends AppStrategy
  {

  }

  /**
   * Abstrakcyjna klasa zdarzenia zachodzącego, gdy rozgrywka jest nieaktywna (menu).
   * Wszystkie zdarzenia, które zachodzą podczas rozgrywki powinny rozszerzać właśnie tą
   * klasę.
   *
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private abstract class NonGameStrategy extends AppStrategy
  {

  }

  /**
   * Strategia zarządzająca rozpoczęciem gry.
   * <li>Model: Rozpoczęcie gry.</li>
   * <li>Widok: Przejście z menu, do widoku gry. Przekazanie stanu modelu.</li>
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com> 
   */
  class StartGameStrategy extends NonGameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      if (!model.gameStarted())
      {
        model.startGame();
        view.startGame(model.getGameMockup());
      }
    }
  }

  /**
   * Strategia uruchamiana, gdy piłka zostanie wypuszczona przez gracza.
   * <li>Model: Wypuszczenie piłki.</li>
   * <li>Widok: Przekazanie nowego stanu modelu.</li>
   * <br/>
   * Strategia dba o to, żeby model został pobudzony do przeliczenia nowego stanu, kiedy
   * jest stan przestanie być ważny.
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class BallReleaseStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      if (!model.ballIsBouncing() && model.gameStarted())
      {
        try
        {
          // Przeliczenie stanu modelu
          model.recalculateValidTime();
          // Wypuszczenie piłki
          model.releaseBall();
          // Przeliczenie stanu modelu.
          model.recalculateValidTime();
         
          // Przesłanie danych o piłce.
          view.setGameUsingMockup(model.getGameMockup());
         
          // Jeżeli model jest bezterminowo ważny nie kasujemy
          // zadanie, czyścimy timer.
          // WPP:
          // Ustawienie operacji validTimePassedTask
          // na timerze aplikacji. Aby stan modelu przeliczył się
          // po czasie validTime.
          // Patrz: ValidTimePassedEvent, ValidTimePassedStrategy
          if(!model.isValidWithoutTimeLimit())
          {
            long validTime = model.getValidTime();
            modelTimer.reschedule(validTimePassedTask, validTime);
          }
          else
          {
            modelTimer.cancelTask();
          }
        } catch (AllBricksDestroyedException e)
        {
          // Model poinformował, że wszystkie klocki zostały zbite
          eventsBlockingQueue.add(new LoadNextLevelEvent());
        } catch (PlayerDiedException e)
        {
          // Model poinformował, że gracz umarł.
          eventsBlockingQueue.add(new GameLostEvent());
        }
      }
    }
  }

  /**
   * Strategia wykonywana, gdy użytkownik chce poruszyć paletką.
   * <li>Model: Odpowiednie przesunięcie paletki.</li>
   * <li>Widok: Przekazanie nowego stanu modelu.</li>
   * <br/>
   * Strategia dba o to, żeby model został pobudzony do przeliczenia nowego stanu, kiedy
   * jest stan przestanie być ważny.
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class MovePaddleStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.AppStrategy#process(com.szuppe.jakub.events.AppEvent
     * , com.szuppe.jakub.model.Model, com.szuppe.jakub.view.View,
     * java.util.concurrent.BlockingQueue, java.util.Timer)
     */
    public void process(AppEvent appEvent)
    {
      try
      {
        MovePaddleEvent movePaddleEvent = (MovePaddleEvent) appEvent;
        // Przeliczenie stanu modelu
        model.recalculateValidTime();
        // Wykonanie
        model.acceleratePaddle(movePaddleEvent.getDirection());
        // Ponowne przeliczenie stanu modelu.
        model.recalculateValidTime();
       
        // Pobranie makiet z modelu i przesłanie do widoku.       
        view.setGameUsingMockup(model.getGameMockup());
       
        // Jeżeli model jest bezterminowo ważny nie kasujemy
        // zadanie, czyścimy timer.
        // WPP:
        // Ustawienie operacji validTimePassedTask
        // na timerze aplikacji. Aby stan modelu przeliczył się
        // po czasie validTime.
        // Patrz: ValidTimePassedEvent, ValidTimePassedStrategy
        if(!model.isValidWithoutTimeLimit())
        {
          long validTime = model.getValidTime();
          modelTimer.reschedule(validTimePassedTask, validTime);
        }
        else
        {
          modelTimer.cancelTask();
        }
      } catch (AllBricksDestroyedException e)
      {
        // Model poinformował, że wszystkie klocki zostały zbite
        eventsBlockingQueue.add(new LoadNextLevelEvent());
      } catch (PlayerDiedException e)
      {
        // Model poinformował, że gracz umarł.
        eventsBlockingQueue.add(new GameLostEvent());
      }
    }
  }

  /**
   * Strategia wykonywana, gdy minie okres poprawności stanu modelu. Model musi obliczyć nowy stan.
   * <li>Model: Przeliczenie nowego stanu.</li>
   * <li>Widok: Przekazanie nowego stanu modelu.</li>
   * <br/>
   * Strategia dba o to, żeby model został pobudzony do przeliczenia nowego stanu, kiedy
   * jest stan przestanie być ważny.
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class ValidTimePassedStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      try
      {
        model.recalculateValidTime();
        view.setGameUsingMockup(model.getGameMockup());

        // Jeżeli model jest bezterminowo ważny nie kasujemy
        // zadanie, czyścimy timer.
        // WPP:
        // Ustawienie operacji validTimePassedTask
        // na timerze aplikacji. Aby stan modelu przeliczył się
        // po czasie validTime.
        // Patrz: ValidTimePassedEvent, ValidTimePassedStrategy
        if(!model.isValidWithoutTimeLimit())
        {
          long validTime = model.getValidTime();
          modelTimer.reschedule(validTimePassedTask, validTime);
        }
        else
        {
          modelTimer.cancelTask();
        }
      } catch (AllBricksDestroyedException e)
      {
        // Model poinformował, że wszystkie klocki zostały zbite
        eventsBlockingQueue.add(new LoadNextLevelEvent());
      } catch (PlayerDiedException e)
      {
        // Model poinformował, że gracz umarł.
        eventsBlockingQueue.add(new GameLostEvent());
      }
    }
  }

 
  /**
   * Strategia wykonywana, gdy potrzeba załadować kolejną plansze/mapę gry.
   * <li>Model: Wczytanie nowej mapy. Ustawienie piłeczki i platformy
   * na startowych pozycjach.</li>
   * <li>Widok: Przekazanie nowego stanu modelu.</li>
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class LoadNextMapStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      try
      {
        // Zatrzymanie zadania ValidTimePassedTask
        // No bo i tak zmieniam stan modelu poprzez załadowanie
        // nowej mapy i ustawienie obiektów na pozycjach startowych
        modelTimer.cancelTask();
        model.loadNextMap();
        // Wysłanie całego stanu, stan zawiera nowe elementy
        // Zatem trzeba wykonać revalidate na gamePanel.
        view.setGameUsingMockupAndRevalidate(model.getGameMockup());
      } catch (NoMoreMapsException e)
      {
        // Nie ma już map, tj. gracz wygrał.
        eventsBlockingQueue.add(new GameWinEvent());
      }
    }
  }

  /**
   * Strategia wykonywana, gdy gra została wygrana.
   * <li>Model: Zakończenie gry.</li>
   * <li>Widok: Przejście to ekranu z gratulacjami.</li>
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class GameWinStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      model.endGame();
      view.endGame(true);
    }
  }

  /**
   * Strategia wykonywana, gdy gracz stracił wszystkie życia i przegrał.
   * <li>Model: Zakończenie gry.</li>
   * <li>Widok: Przejście to ekranu z propozycją ponownej gry.</li>
   * <br/>
   * @author Jakub Szuppe <j.szuppe at gmail.com>
   */
  private class GameLostStrategy extends GameStrategy
  {
    /*
     * (non-Javadoc)
     * @see
     * com.szuppe.jakub.controller.Controller.AppStrategy#process(com.szuppe.jakub
     * .events.AppEvent)
     */
    public void process(AppEvent appEvent)
    {
      model.endGame();
      view.endGame(false);
    }
  }
}
TOP

Related Classes of com.szuppe.jakub.controller.Controller$NonGameStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.