|
|
Zeile 58: |
Zeile 58: |
| == Beispielimplementierung == | | == Beispielimplementierung == |
| | | |
− | === State ===
| + | TODO: erst, wenn die Theorie festgehalten ist. |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>C++</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang="cpp" tab="4">
| + | |
− | class State
| + | |
− | {
| + | |
− | public:
| + | |
− | virtual ~State() { };
| + | |
− | virtual void OnEnter() = 0;
| + | |
− | virtual void OnLeave() = 0;
| + | |
− | virtual bool OnUpdate(float elapsedTime) = 0;
| + | |
− | virtual void OnRender() = 0;
| + | |
− | virtual std::string NextState() = 0;
| + | |
− | };
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>C#</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang="csharp" tab="4">
| + | |
− | public interface State
| + | |
− | {
| + | |
− | void OnEnter();
| + | |
− | void OnLeave();
| + | |
− | bool OnUpdate(float elapsedTime);
| + | |
− | void OnRender();
| + | |
− | string NextState { get; }
| + | |
− | }
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>Java</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang="java" tab="4">
| + | |
− | public interface State
| + | |
− | {
| + | |
− | void onEnter();
| + | |
− | void onLeave();
| + | |
− | boolean onUpdate(float elapsedTime);
| + | |
− | void onRender();
| + | |
− | String getNextState();
| + | |
− | }
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
− | | + | |
− | === StateManager ===
| + | |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>C++</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang=cpp tab=4>/* h-Datei: StateManager.h*/
| + | |
− | class StateManager
| + | |
− | {
| + | |
− | private:
| + | |
− | //Speichert alle Zustände als Assoziatives Array
| + | |
− | std::map<std::string, State*> _statesById;
| + | |
− | //Aktueller Zustand
| + | |
− | State *_currentState;
| + | |
− |
| + | |
− | public:
| + | |
− | StateManager();
| + | |
− | ~StateManager();
| + | |
− |
| + | |
− | void AddState(const std::string &id, State *state);
| + | |
− | void SetState(const std::string &id);
| + | |
− | bool Update(float elapsedTime);
| + | |
− | void Render();
| + | |
− | };
| + | |
− | | + | |
− | /* cpp-Datei: StateManager.cpp */
| + | |
− | | + | |
− | //erzeugt ein StateManager-Objekt
| + | |
− | StateManager::StateManager():
| + | |
− | _currentState(NULL)
| + | |
− | {
| + | |
− | }
| + | |
− | | + | |
− | //Löscht das StateManager-objekt mit allen Zuständen.
| + | |
− | StateManager::~StateManager()
| + | |
− | {
| + | |
− | for(std::map<std::string, State*>::iterator it = _statesById.Begin(); it != _statesById.end(); ++it)
| + | |
− | {
| + | |
− | delete (*it);
| + | |
− | }
| + | |
− | }
| + | |
− | | + | |
− | //Registriert einen Zustand für den Manager an Hand der ID. Diese muss
| + | |
− | //eindeutig und nicht leer sein.
| + | |
− | void StateManager::AddState(const std::string &id, State *state)
| + | |
− | {
| + | |
− | if (id.length() == 0)
| + | |
− | throw std::exception("Id has to be a valid string");
| + | |
− | if (state == NULL)
| + | |
− | throw std::exception("State must not be null");
| + | |
− |
| + | |
− | std::map<std::string, State*>::iterator it = _statesById.find(id);
| + | |
− | if (it != _statesById.end())
| + | |
− | {
| + | |
− | std::string error("State with ID ");
| + | |
− | error.append(id);
| + | |
− | error.append(" already exist.");
| + | |
− | throw std::exception(error.c_str());
| + | |
− | }
| + | |
− |
| + | |
− | _statesById[id] = state;
| + | |
− | }
| + | |
− |
| + | |
− | //Setzt den aktuellen Zustand
| + | |
− | void StateManager::SetState(const std::string &id)
| + | |
− | {
| + | |
− | std::map<std::string, State*>::iterator nextStateIt = _statesById.find(id);
| + | |
− |
| + | |
− | //Wenn der Zustand im Manager registriert ist
| + | |
− | if (nextStateIt != _statesById.end())
| + | |
− | {
| + | |
− | //und nicht der aktuelle ist
| + | |
− | if (*nextStateIt != _currentState)
| + | |
− | {
| + | |
− | //Rufe OnLeave() vom alten Zustand auf, falls es einen gab
| + | |
− | if (_currentState != NULL)
| + | |
− | _currentState->OnLeave();
| + | |
− |
| + | |
− | //setze den neuen aktuellen Zustand
| + | |
− | _currentState = *nextStateIt;
| + | |
− |
| + | |
− | //Da zu einem neuen Zustand gewechselt worden ist, rufe das Eingangsereignis auf
| + | |
− | _currentState->OnEnter();
| + | |
− | }
| + | |
− | }
| + | |
− | else
| + | |
− | //ansonsten gibt es diesen Zustand nicht!
| + | |
− | throw new InvalidOperationException(string.Format("State with Id {0} does not exist.", id));
| + | |
− | }
| + | |
− |
| + | |
− | //Aktualisert den Spielzustand. der Rückgabewert gibt an, ob das Programm weiterläuft.
| + | |
− | //Es läuft nicht weiter, wenn der aktuelle Zustand verlassen und kein weiterer Zustand zugewiesen wird.
| + | |
− | bool StateManager::Update(float elapsedTime)
| + | |
− | {
| + | |
− | //Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == NULL)
| + | |
− | throw std::exception("Current state not set.");
| + | |
− |
| + | |
− | //aktualisere den Zustand und schaue, ob der Zustand eventuell verlassen werden soll
| + | |
− | bool running = _currentState->OnUpdate(elapsedTime);
| + | |
− |
| + | |
− | //wenn er verlassen werden soll und der Folgezustand gesetzt ist
| + | |
− | if (!running && !_currentState->NextState().length() > 0)
| + | |
− | {
| + | |
− | //Wechsle den Zustand
| + | |
− | SetState(_currentState->NextState());
| + | |
− |
| + | |
− | //Programm läuft weiter
| + | |
− | return true;
| + | |
− | }
| + | |
− |
| + | |
− | //
| + | |
− | return running;
| + | |
− | }
| + | |
− |
| + | |
− | //Zeichnet den aktuellen Zustand.
| + | |
− | void StateManager::Render()
| + | |
− | {
| + | |
− | //Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == NULL)
| + | |
− | throw std::exception("Current state not set.");
| + | |
− |
| + | |
− | //Zeichne den aktuellen Zustand
| + | |
− | _currentState->OnRender();
| + | |
− | }
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>C#</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang=csharp tab=4>public class StateManager
| + | |
− | {
| + | |
− | //Speichert alle Zustände als Assoziatives Array
| + | |
− | private Dictionary<string, State> _statesById;
| + | |
− | //Aktueller Zustand
| + | |
− | private State _currentState;
| + | |
− |
| + | |
− | //erzeugt ein StateManager-Objekt
| + | |
− | public StateManager()
| + | |
− | {
| + | |
− | _statesById = new Dictionary<string, State>();
| + | |
− | }
| + | |
− |
| + | |
− | //Registriert einen Zustand für den Manager an Hand der ID. Diese muss
| + | |
− | //eindeutig und nicht leer sein.
| + | |
− | public void AddState(string id, State state)
| + | |
− | {
| + | |
− | if (string.IsNullOrEmpty(id))
| + | |
− | throw new InvalidOperationException("Id has to be a valid string");
| + | |
− | if (state == null)
| + | |
− | throw new ArgumentNullException("state");
| + | |
− | if (_statesById.ContainsKey(id))
| + | |
− | throw new InvalidOperationException(string.Format("State with ID {0} already exists.", id));
| + | |
− |
| + | |
− | _statesById.Add(id, state);
| + | |
− | }
| + | |
− |
| + | |
− | //Setzt den aktuellen Zustand
| + | |
− | public void SetState(string id)
| + | |
− | {
| + | |
− | State nextState;
| + | |
− | //Wenn der Zustand im Manager registriert ist
| + | |
− | if (_statesById.TryGetValue(id, out nextState))
| + | |
− | {
| + | |
− | //und nicht der aktuelle ist
| + | |
− | if (nextState != _currentState)
| + | |
− | {
| + | |
− | //Rufe OnLeave() vom alten Zustand auf, falls es einen gab
| + | |
− | if (_currentState != null)
| + | |
− | _currentState.OnLeave();
| + | |
− |
| + | |
− | //setze den neuen aktuellen Zustand
| + | |
− | _currentState = nextState;
| + | |
− |
| + | |
− | //Da zu einem neuen Zustand gewechselt worden ist, rufe das Eingangsereignis auf
| + | |
− | _currentState.OnEnter();
| + | |
− | }
| + | |
− | }
| + | |
− | else
| + | |
− | //ansonsten gibt es diesen Zustand nicht!
| + | |
− | throw new InvalidOperationException(string.Format("State with Id {0} does not exist.", id));
| + | |
− | }
| + | |
− |
| + | |
− | //Aktualisert den Spielzustand. der Rückgabewert gibt an, ob das Programm weiterläuft.
| + | |
− | //Es läuft nicht weiter, wenn der aktuelle Zustand verlassen und kein weiterer Zustand zugewiesen wird.
| + | |
− | public bool Update(float elapsedTime)
| + | |
− | {
| + | |
− | //Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == null)
| + | |
− | throw new InvalidOperationException("Current state not set.");
| + | |
− |
| + | |
− | //aktualisere den Zustand und schaue, ob der Zustand eventuell verlassen werden soll
| + | |
− | bool running = _currentState.OnUpdate(elapsedTime);
| + | |
− |
| + | |
− | //wenn er verlassen werden soll und der Folgezustand gesetzt ist
| + | |
− | if (!running && !string.IsNullOrEmpty(_currentState.NextState))
| + | |
− | {
| + | |
− | //Wechsle den Zustand
| + | |
− | SetState(_currentState.NextState);
| + | |
− |
| + | |
− | //Programm läuft weiter
| + | |
− | return true;
| + | |
− | }
| + | |
− |
| + | |
− | //
| + | |
− | return running;
| + | |
− | }
| + | |
− |
| + | |
− | //Zeichnet den aktuellen Zustand.
| + | |
− | public void Render()
| + | |
− | {
| + | |
− | //Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == null)
| + | |
− | throw new InvalidOperationException("Current state not set.");
| + | |
− |
| + | |
− | //Zeichne den aktuellen Zustand
| + | |
− | _currentState.OnRender();
| + | |
− | }
| + | |
− | }
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
− | | + | |
− | {{Spoiler|
| + | |
− | <xh4>Java</xh4>
| + | |
− | |
| + | |
− | <sourcecode lang="java" tab="4">
| + | |
− | import java.util.HashMap;
| + | |
− | | + | |
− | public class StateManager {
| + | |
− | // Speichert alle Zustände als Assoziatives Array
| + | |
− | private HashMap<String, State> _statesById;
| + | |
− | // Aktueller Zustand
| + | |
− | private State _currentState;
| + | |
− |
| + | |
− | // erzeugt ein StateManager-Objekt
| + | |
− | public StateManager() {
| + | |
− | _statesById = new HashMap<String, State>();
| + | |
− | }
| + | |
− |
| + | |
− | // Registriert einen Zustand für den Manager an Hand der ID. Diese muss
| + | |
− | // eindeutig und nicht leer sein.
| + | |
− | public void AddState(String id, State state) {
| + | |
− | if (id == null || id.equals(""))
| + | |
− | throw new IllegalArgumentException("Id has to be a valid string");
| + | |
− | if (state == null)
| + | |
− | throw new NullPointerException("state");
| + | |
− | if (_statesById.containsKey(id))
| + | |
− | throw new IllegalArgumentException("State with ID " + id + " already exists.");
| + | |
− |
| + | |
− | _statesById.put(id, state);
| + | |
− | }
| + | |
− |
| + | |
− | // Setzt den aktuellen Zustand
| + | |
− | public void SetState(String id) {
| + | |
− | State nextState = _statesById.get(id);
| + | |
− | // Wenn der Zustand im Manager registriert ist
| + | |
− | if (nextState != null) {
| + | |
− | // und nicht der aktuelle ist
| + | |
− | if (nextState != _currentState) {
| + | |
− | // Rufe OnLeave() vom alten Zustand auf, falls es einen gab
| + | |
− | if (_currentState != null) {
| + | |
− | _currentState.onLeave();
| + | |
− | }
| + | |
− |
| + | |
− | // setze den neuen aktuellen Zustand
| + | |
− | _currentState = nextState;
| + | |
− |
| + | |
− | // Da zu einem neuen Zustand gewechselt worden ist, rufe das Eingangsereignis auf
| + | |
− | _currentState.onEnter();
| + | |
− | }
| + | |
− | } else {
| + | |
− | // ansonsten gibt es diesen Zustand nicht!
| + | |
− | throw new IllegalArgumentException("State with Id " + id + " does not exist.");
| + | |
− | }
| + | |
− | }
| + | |
− |
| + | |
− | // Aktualisert den Spielzustand. der Rückgabewert gibt an, ob das Programm weiterläuft.
| + | |
− | // Es läuft nicht weiter, wenn der aktuelle Zustand verlassen und kein weiterer Zustand zugewiesen wird.
| + | |
− | public boolean Update(float elapsedTime) {
| + | |
− | // Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == null)
| + | |
− | throw new IllegalArgumentException("Current state not set.");
| + | |
− |
| + | |
− | // aktualisere den Zustand und schaue, ob der Zustand eventuell verlassen werden soll
| + | |
− | boolean running = _currentState.onUpdate(elapsedTime);
| + | |
− |
| + | |
− | // wenn er verlassen werden soll und der Folgezustand gesetzt ist
| + | |
− | String nextState = _currentState.getNextState();
| + | |
− | if (!running && (nextState == null || nextState.equals(""))) {
| + | |
− | // Wechsle den Zustand
| + | |
− | SetState(nextState);
| + | |
− |
| + | |
− | // Programm läuft weiter
| + | |
− | return true;
| + | |
− | }
| + | |
− |
| + | |
− | //
| + | |
− | return running;
| + | |
− | }
| + | |
− |
| + | |
− | // Zeichnet den aktuellen Zustand.
| + | |
− | public void Render() {
| + | |
− | // Es muss ein Zustand gesetzt sein!
| + | |
− | if (_currentState == null)
| + | |
− | throw new IllegalArgumentException("Current state not set.");
| + | |
− |
| + | |
− | // Zeichne den aktuellen Zustand
| + | |
− | _currentState.onRender();
| + | |
− | }
| + | |
− | }
| + | |
− | </sourcecode>
| + | |
− | }}
| + | |
| | | |
| == Vor- und Nachteile == | | == Vor- und Nachteile == |