From 2a0eca649009f78028db286a67a532429cab5b88 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 7 Aug 2012 15:14:30 +0200 Subject: [PATCH] reworked Application's state stack --- src/app/Application.cpp | 65 +++++++++++++++++++------- src/app/Application.h | 12 ++++- src/app/State.h | 9 +++- src/battle/BattleState.cpp | 23 +++++---- src/battle/BattleState.h | 10 +++- src/battle/states/SelectAttackType.cpp | 24 ++++++++-- src/battle/states/SelectAttackType.h | 4 +- src/battle/states/SelectMoveAction.cpp | 13 +++++- src/battle/states/SelectMoveAction.h | 4 +- 9 files changed, 124 insertions(+), 40 deletions(-) diff --git a/src/app/Application.cpp b/src/app/Application.cpp index 19aa06a..80ebb5d 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -16,8 +16,7 @@ namespace app { Application::Application(sdl::InitScreen *screen, State *initialState) : screen(screen) , states() -, last(SDL_GetTicks()) -, toPop(0) { +, last(SDL_GetTicks()) { assert(screen && "cannot create application without screen"); assert(initialState && "cannot create application without initial state"); RealPushState(initialState); @@ -33,40 +32,72 @@ State *Application::CurrentState() { } void Application::UpdateState() { - while (toPop > 0) { - RealPopState(); - --toPop; - } - while (!toPush.empty()) { - State *s(toPush.front()); - toPush.pop(); - RealPushState(s); + while (!stateChanges.empty()) { + switch (stateChanges.front().type) { + case StateCommand::PUSH: + RealPushState(stateChanges.front().state); + break; + case StateCommand::POP: + RealPopState(); + break; + case StateCommand::CHANGE: + RealChangeState(stateChanges.front().state); + break; + } + stateChanges.pop(); } } void Application::ChangeState(State *s) { - PopState(); - PushState(s); + StateCommand cmd; + cmd.type = StateCommand::CHANGE; + cmd.state = s; + stateChanges.push(cmd); } void Application::PushState(State *s) { - toPush.push(s); + StateCommand cmd; + cmd.type = StateCommand::PUSH; + cmd.state = s; + stateChanges.push(cmd); } -void Application::RealPushState(State *s) { +void Application::PopState() { + StateCommand cmd; + cmd.type = StateCommand::POP; + cmd.state = 0; + stateChanges.push(cmd); +} + +void Application::RealChangeState(State *s) { + if (!states.empty()) { + states.top()->PauseState(*this, screen->Screen()); + states.top()->ExitState(*this, screen->Screen()); + states.pop(); + } states.push(s); s->EnterState(*this, screen->Screen()); + s->ResumeState(*this, screen->Screen()); } -void Application::PopState() { - ++toPop; +void Application::RealPushState(State *s) { + if (!states.empty()) { + states.top()->PauseState(*this, screen->Screen()); + } + states.push(s); + s->EnterState(*this, screen->Screen()); + s->ResumeState(*this, screen->Screen()); } void Application::RealPopState() { if (states.empty()) return; - states.top()->ExitState(); + states.top()->PauseState(*this, screen->Screen()); + states.top()->ExitState(*this, screen->Screen()); delete states.top(); states.pop(); + if (!states.empty()) { + states.top()->ResumeState(*this, screen->Screen()); + } } void Application::Quit() { diff --git a/src/app/Application.h b/src/app/Application.h index dcc5e00..853d0cb 100644 --- a/src/app/Application.h +++ b/src/app/Application.h @@ -41,9 +41,18 @@ public: Input &Buttons() { return input; } const Input &Buttons() const { return input; } +private: + struct StateCommand { + enum Type { + PUSH, POP, CHANGE + } type; + State *state; + }; + private: State *CurrentState(); void UpdateState(); + void RealChangeState(State *); void RealPushState(State *); void RealPopState(); void PopAllStates(); @@ -56,10 +65,9 @@ private: private: sdl::InitScreen *screen; std::stack states; - std::queue toPush; + std::queue stateChanges; Input input; Uint32 last; - int toPop; }; diff --git a/src/app/State.h b/src/app/State.h index 7f46c57..678f2b9 100644 --- a/src/app/State.h +++ b/src/app/State.h @@ -22,9 +22,16 @@ public: public: /// do some setup + /// called when the state first enters the stack /// @param ctrl the Application running the state virtual void EnterState(Application &ctrl, SDL_Surface *screen) = 0; - virtual void ExitState() = 0; + /// do some cleanup + /// called when the state is popped from the stack + virtual void ExitState(Application &ctrl, SDL_Surface *screen) = 0; + /// called when the state becomes the active one + virtual void ResumeState(Application &ctrl, SDL_Surface *screen) = 0; + /// called when the state becomes inactive + virtual void PauseState(Application &ctrl, SDL_Surface *screen) = 0; /// adapt the state's graphics to given dimensions virtual void Resize(int width, int height) = 0; diff --git a/src/battle/BattleState.cpp b/src/battle/BattleState.cpp index 4e12f79..2c5fe81 100644 --- a/src/battle/BattleState.cpp +++ b/src/battle/BattleState.cpp @@ -51,10 +51,21 @@ void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) { for (vector::size_type i(0), end(heroes.size()); i < end; ++i) { heroTags.push_back(HeroTag(&heroes[i], HeroTag::Alignment((i + 1) % 2))); } +} + +void BattleState::ExitState(Application &ctrl, SDL_Surface *screen) { + +} + +void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) { + // reset attack choices + activeHero = -1; + attackChoices.clear(); + attackChoices.resize(heroes.size()); ctrl.PushState(new SelectMoveAction(this)); } -void BattleState::ExitState() { +void BattleState::PauseState(Application &ctrl, SDL_Surface *screen) { } @@ -74,7 +85,6 @@ void BattleState::Render(SDL_Surface *screen) { RenderMonsters(screen, offset); // RenderHeroes(screen, offset); RenderHeroTags(screen, offset); - RenderAttackTypeMenu(screen, offset); } void BattleState::RenderBackground(SDL_Surface *screen, const Vector &offset) { @@ -112,15 +122,8 @@ void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector &offset) tagPosition[3] = Point(tagWidth + attackTypeMenu.IconWidth(), uiOffset + tagHeight + attackTypeMenu.IconHeight()); for (vector::size_type i(0), end(heroTags.size()); i < end; ++i) { - heroTags[i].Render(screen, tagWidth, tagHeight, tagPosition[i] + offset, i == activeHero); + heroTags[i].Render(screen, tagWidth, tagHeight, tagPosition[i] + offset, (int)i == activeHero); } } -void BattleState::RenderAttackTypeMenu(SDL_Surface *screen, const Vector &offset) { - Point position( - (BackgroundWidth() - attackTypeMenu.Width()) / 2, - (BackgroundHeight() * 3 / 4) - (attackTypeMenu.Height() / 2)); - attackTypeMenu.Render(screen, position + offset); -} - } diff --git a/src/battle/BattleState.h b/src/battle/BattleState.h index 73f3fbc..12c55f7 100644 --- a/src/battle/BattleState.h +++ b/src/battle/BattleState.h @@ -8,6 +8,7 @@ #ifndef BATTLE_BATTLESTATE_H_ #define BATTLE_BATTLESTATE_H_ +#include "AttackChoice.h" #include "AttackTypeMenu.h" #include "Hero.h" #include "HeroTag.h" @@ -46,7 +47,9 @@ public: public: virtual void EnterState(app::Application &ctrl, SDL_Surface *screen); - virtual void ExitState(); + virtual void ExitState(app::Application &ctrl, SDL_Surface *screen); + virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen); + virtual void PauseState(app::Application &ctrl, SDL_Surface *screen); virtual void Resize(int width, int height); @@ -60,6 +63,9 @@ public: bool HasMoreHeroes() const { return activeHero < (int) heroes.size(); } void NextHero() { ++activeHero; } + bool HasChosenAttackType() const { return attackChoices[activeHero].GetType() != AttackChoice::UNDECIDED; } + void SetAttackType(AttackChoice::Type t) { attackChoices[activeHero].SetType(t); } + bool AttackSelectionDone() const { return activeHero >= (int) heroes.size(); } public: geometry::Vector CalculateScreenOffset(SDL_Surface *screen) const { @@ -74,7 +80,6 @@ public: void RenderMonsters(SDL_Surface *screen, const geometry::Vector &offset); void RenderHeroes(SDL_Surface *screen, const geometry::Vector &offset); void RenderHeroTags(SDL_Surface *screen, const geometry::Vector &offset); - void RenderAttackTypeMenu(SDL_Surface *screen, const geometry::Vector &offset); private: SDL_Surface *background; @@ -87,6 +92,7 @@ private: std::vector monsters; std::vector heroes; std::vector heroTags; + std::vector attackChoices; int activeHero; }; diff --git a/src/battle/states/SelectAttackType.cpp b/src/battle/states/SelectAttackType.cpp index c054813..c7a65be 100644 --- a/src/battle/states/SelectAttackType.cpp +++ b/src/battle/states/SelectAttackType.cpp @@ -9,25 +9,35 @@ #include "../AttackChoice.h" #include "../BattleState.h" +#include "../../app/Application.h" #include "../../app/Input.h" #include "../../geometry/operators.h" #include +using app::Application; using app::Input; using geometry::Point; using geometry::Vector; namespace battle { -void SelectAttackType::EnterState(app::Application &c, SDL_Surface *screen) { +void SelectAttackType::EnterState(Application &c, SDL_Surface *screen) { ctrl = &c; } -void SelectAttackType::ExitState() { +void SelectAttackType::ExitState(Application &c, SDL_Surface *screen) { ctrl = 0; } +void SelectAttackType::ResumeState(Application &ctrl, SDL_Surface *screen) { + +} + +void SelectAttackType::PauseState(Application &ctrl, SDL_Surface *screen) { + +} + void SelectAttackType::Resize(int width, int height) { @@ -48,15 +58,16 @@ void SelectAttackType::HandleInput(const Input &input) { } if (input.JustPressed(Input::ACTION_A)) { + battle->SetAttackType(battle->GetAttackTypeMenu().Selected()); switch (battle->GetAttackTypeMenu().Selected()) { case AttackChoice::SWORD: - // TODO: switch to next character + battle->NextHero(); break; case AttackChoice::MAGIC: // TODO: switch to spell select break; case AttackChoice::DEFEND: - // TODO: switch to next character + battle->NextHero(); break; case AttackChoice::IKARI: // TODO: switch to ikari attack select @@ -68,6 +79,11 @@ void SelectAttackType::HandleInput(const Input &input) { throw std::logic_error("selected invalid attack type"); } } + + if (battle->AttackSelectionDone()) { + // TODO: switch to battle animation instead + ctrl->PopState(); + } } void SelectAttackType::UpdateWorld(float deltaT) { diff --git a/src/battle/states/SelectAttackType.h b/src/battle/states/SelectAttackType.h index 3b10188..b2974bb 100644 --- a/src/battle/states/SelectAttackType.h +++ b/src/battle/states/SelectAttackType.h @@ -26,7 +26,9 @@ public: public: virtual void EnterState(app::Application &ctrl, SDL_Surface *screen); - virtual void ExitState(); + virtual void ExitState(app::Application &ctrl, SDL_Surface *screen); + virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen); + virtual void PauseState(app::Application &ctrl, SDL_Surface *screen); virtual void Resize(int width, int height); diff --git a/src/battle/states/SelectMoveAction.cpp b/src/battle/states/SelectMoveAction.cpp index 54f0f29..bee880b 100644 --- a/src/battle/states/SelectMoveAction.cpp +++ b/src/battle/states/SelectMoveAction.cpp @@ -14,20 +14,29 @@ #include "../../app/Input.h" #include "../../geometry/operators.h" +using app::Application; using app::Input; using geometry::Point; using geometry::Vector; namespace battle { -void SelectMoveAction::EnterState(app::Application &c, SDL_Surface *screen) { +void SelectMoveAction::EnterState(Application &c, SDL_Surface *screen) { ctrl = &c; } -void SelectMoveAction::ExitState() { +void SelectMoveAction::ExitState(Application &c, SDL_Surface *screen) { ctrl = 0; } +void SelectMoveAction::ResumeState(Application &ctrl, SDL_Surface *screen) { + +} + +void SelectMoveAction::PauseState(Application &ctrl, SDL_Surface *screen) { + +} + void SelectMoveAction::Resize(int width, int height) { diff --git a/src/battle/states/SelectMoveAction.h b/src/battle/states/SelectMoveAction.h index c135663..bce6bfe 100644 --- a/src/battle/states/SelectMoveAction.h +++ b/src/battle/states/SelectMoveAction.h @@ -26,7 +26,9 @@ public: public: virtual void EnterState(app::Application &ctrl, SDL_Surface *screen); - virtual void ExitState(); + virtual void ExitState(app::Application &ctrl, SDL_Surface *screen); + virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen); + virtual void PauseState(app::Application &ctrl, SDL_Surface *screen); virtual void Resize(int width, int height); -- 2.39.2