From a0ad8e7ed6ddea7b9794a93cb68fe4fbafaefdad Mon Sep 17 00:00:00 2001 From: NaiJi Date: Tue, 3 Aug 2021 21:42:58 +0300 Subject: [PATCH] Implement state machine infrastructure --- include/application.h | 20 +++++--------------- include/gui/state.h | 21 ++++++++++++++++++--- src/application.cpp | 35 ++++++++++++++++++++++------------- src/gui/gamestate.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/gui/gamestate.h | 37 +++++++++++++++++++++++++++++++++++++ src/gui/mainmenu.cpp | 22 +++++++++++++++------- src/gui/mainmenu.h | 13 +++++++++++-- src/gui/widgets/widget.cpp | 8 ++++++++ src/gui/widgets/widget.h | 2 ++ 9 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 src/gui/gamestate.cpp create mode 100644 src/gui/gamestate.h diff --git a/include/application.h b/include/application.h index 8ab52f5..fe72d4c 100644 --- a/include/application.h +++ b/include/application.h @@ -2,6 +2,7 @@ #define APPLICATION_H #include +#include #include #include #include @@ -12,18 +13,6 @@ class Application { public: - - enum State - { - SPLASH_SCREEN, - MAIN_MENU, - GAME_PICKER, - GAME, - EDITOR_PICKER, - EDITOR, - SETTINGS - }; - Application(); void run(); void input(); @@ -31,13 +20,14 @@ public: void draw(); private: - std::stack> _states; + std::array, GUIState::Tag::AMOUNT> _states; + std::vector> _state_stack; + sf::RenderWindow _game_window; std::shared_ptr _game; - State _state; - void exec(); + void emplaceState(GUIState::Tag new_state); }; #endif // APPLICATION_H diff --git a/include/gui/state.h b/include/gui/state.h index 398be7e..ddf9ac6 100644 --- a/include/gui/state.h +++ b/include/gui/state.h @@ -3,14 +3,29 @@ #include #include #include -#include -class GUIState : public sf::Drawable +class GUIState { public: + + enum Tag { + SPLASH_SCREEN, + MAIN_MENU, + GAME_PICKER, + GAME, + EDITOR_PICKER, + EDITOR, + SETTINGS, + + AMOUNT + }; + virtual ~GUIState() = default; virtual void input(const sf::Event& event) = 0; virtual void update() = 0; - virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const = 0; + virtual void draw() const = 0; + + virtual void enter() = 0; + virtual void leave() = 0; }; diff --git a/src/application.cpp b/src/application.cpp index c5f59a9..7efc616 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -5,6 +5,7 @@ #include "classicgame/classicgraphicsmanager.h" #include "gui/mainmenu.h" +#include "gui/gamestate.h" #include @@ -19,13 +20,19 @@ Application::Application() : _game_window.setMouseCursorGrabbed(false); _game_window.setVerticalSyncEnabled(true); - _states.push(std::make_shared(_game_window)); + MainMenu::Callbacks callbacks = {[&](){ emplaceState(GUIState::Tag::GAME); }}; + + const auto main_menu = std::make_shared(_game_window, std::move(callbacks)); + const auto game_state = std::make_shared(_game_window, _game, GameState::Callbacks()); + _states[GUIState::Tag::MAIN_MENU] = main_menu; + _states[GUIState::Tag::GAME] = game_state; + + _state_stack.emplace_back(_states.at(GUIState::Tag::MAIN_MENU)); } void Application::run() { _game_window.display(); - exec(); } @@ -61,16 +68,8 @@ void Application::input() _game_window.close(); break; - case sf::Event::KeyPressed: - case sf::Event::KeyReleased: - case sf::Event::MouseButtonReleased: - case sf::Event::MouseButtonPressed: - if (event.key.code == sf::Keyboard::Escape) - _game_window.close(); - _states.top()->input(event); - break; - default: + _state_stack.back()->input(event); break; } } @@ -78,12 +77,22 @@ void Application::input() void Application::update() { - _states.top()->update(); + _state_stack.back()->update(); } void Application::draw() { _game_window.clear(); - _game_window.draw(*_states.top()); + + for (const auto& state : _state_stack) + state->draw(); + _game_window.display(); } + +void Application::emplaceState(GUIState::Tag new_state) +{ + _state_stack.back()->leave(); + _state_stack.emplace_back(_states.at(new_state)); + _state_stack.back()->enter(); +} diff --git a/src/gui/gamestate.cpp b/src/gui/gamestate.cpp new file mode 100644 index 0000000..a5af5b2 --- /dev/null +++ b/src/gui/gamestate.cpp @@ -0,0 +1,37 @@ +#include "gamestate.h" +#include "widgets/button.h" +#include "widgets/group.h" + +#include "game/game.h" + +GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr& game, + Callbacks&& callbacks) : + _game(game), + _game_window(game_window), + _onLeaveGameCallback(callbacks.onLeaveGame) +{} + +void GameState::input(const sf::Event& event) +{ + _game->input({0, event}); +} + +void GameState::update() +{ + _game->update(); +} + +void GameState::draw() const +{ + _game->draw(); +} + +void GameState::enter() +{ + _game->run(); +} + +void GameState::leave() +{ + _onLeaveGameCallback(); +} diff --git a/src/gui/gamestate.h b/src/gui/gamestate.h new file mode 100644 index 0000000..68be7d0 --- /dev/null +++ b/src/gui/gamestate.h @@ -0,0 +1,37 @@ +#pragma once + +#include "gui/state.h" +#include + +class Group; +class Game; + +class GameState : public GUIState +{ +public: + + struct Callbacks + { + std::function onLeaveGame; + }; + + + explicit GameState(sf::RenderWindow& game_window, + const std::shared_ptr& game, + Callbacks&& callbacks); + + virtual void input(const sf::Event& event) override; + virtual void update() override; + virtual void draw() const override; + + virtual void enter() override; + virtual void leave() override; + +private: + std::shared_ptr _game; + sf::RenderWindow& _game_window; + + std::function _onEnterGameCallback; + std::function _onLeaveGameCallback; +}; + diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index 818b217..bf9b202 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -2,16 +2,13 @@ #include "widgets/button.h" #include "widgets/group.h" -MainMenu::MainMenu(sf::RenderWindow& game_window) : +MainMenu::MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks) : _buttons(std::make_shared()), _game_window(game_window) { std::shared_ptr