Implement state machine infrastructure

selection
NaiJi ✨ 3 years ago
parent 325d49270d
commit a0ad8e7ed6

@ -2,6 +2,7 @@
#define APPLICATION_H
#include <memory>
#include <array>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <SFML/Window/Event.hpp>
@ -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<std::shared_ptr<GUIState>> _states;
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
std::vector<std::shared_ptr<GUIState>> _state_stack;
sf::RenderWindow _game_window;
std::shared_ptr<Game> _game;
State _state;
void exec();
void emplaceState(GUIState::Tag new_state);
};
#endif // APPLICATION_H

@ -3,14 +3,29 @@
#include <stack>
#include <memory>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Drawable.hpp>
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;
};

@ -5,6 +5,7 @@
#include "classicgame/classicgraphicsmanager.h"
#include "gui/mainmenu.h"
#include "gui/gamestate.h"
#include <iostream>
@ -19,13 +20,19 @@ Application::Application() :
_game_window.setMouseCursorGrabbed(false);
_game_window.setVerticalSyncEnabled(true);
_states.push(std::make_shared<MainMenu>(_game_window));
MainMenu::Callbacks callbacks = {[&](){ emplaceState(GUIState::Tag::GAME); }};
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks));
const auto game_state = std::make_shared<GameState>(_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();
}

@ -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>& 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();
}

@ -0,0 +1,37 @@
#pragma once
#include "gui/state.h"
#include <SFML/Graphics/RenderWindow.hpp>
class Group;
class Game;
class GameState : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onLeaveGame;
};
explicit GameState(sf::RenderWindow& game_window,
const std::shared_ptr<Game>& 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> _game;
sf::RenderWindow& _game_window;
std::function<void(void)> _onEnterGameCallback;
std::function<void(void)> _onLeaveGameCallback;
};

@ -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<Group>()),
_game_window(game_window)
{
std::shared_ptr<Button> button_start = std::make_shared<Button>("Start");
button_start->setRect(sf::FloatRect(140, 140, 500, 100));
button_start->setCallback([&]()
{
_game_window.close();
});
button_start->setCallback(callbacks.onAppendGameState);
std::shared_ptr<Button> button_exit = std::make_shared<Button>("Exit");
button_exit->setRect(sf::FloatRect(140, 140, 400, 100));
@ -35,7 +32,18 @@ void MainMenu::update()
_buttons->update();
}
void MainMenu::draw(sf::RenderTarget& target, sf::RenderStates states) const
void MainMenu::draw() const
{
_game_window.draw(*_buttons);
}
void MainMenu::enter()
{
target.draw(*_buttons, states);
_buttons->setVisibility();
}
void MainMenu::leave()
{
_buttons->setVisibility(false);
}

@ -8,10 +8,19 @@ class Group;
class MainMenu : public GUIState
{
public:
MainMenu(sf::RenderWindow& game_window);
struct Callbacks
{
std::function<void(void)> onAppendGameState;
};
MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks);
virtual void input(const sf::Event& event) override;
virtual void update() override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void draw() const override;
virtual void enter() override;
virtual void leave() override;
private:
std::shared_ptr<Group> _buttons;

@ -14,10 +14,18 @@ void Widget::update()
void Widget::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (!_is_visible)
return;
for (auto& child : _children)
child->draw(target, states);
}
void Widget::setVisibility(bool is_visible)
{
_is_visible = is_visible;
}
void Widget::addChild(const std::shared_ptr<Widget> &child)
{
child->_parent = shared_from_this();

@ -18,10 +18,12 @@ public:
virtual void setPosition(const sf::Vector2f& position) = 0;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const = 0;
void setVisibility(bool is_visible = true);
void addChild(const std::shared_ptr<Widget>& child);
protected:
std::vector<std::shared_ptr<Widget>> _children;
std::shared_ptr<Widget> _parent;
bool _is_visible = true;
};

Loading…
Cancel
Save