Implement new Graphics Manager

This commit is contained in:
NaiJi ✨ 2021-12-27 21:41:25 +03:00
parent 8b4d362000
commit bf35501c21
19 changed files with 151 additions and 114 deletions

View File

@ -2,14 +2,17 @@
#include "core/inputtype.h"
#include "core/updatedata.h"
#include <SFML/Graphics/Drawable.hpp>
class Game
class Game : public sf::Drawable
{
public:
virtual ~Game() = default;
virtual void run() = 0;
virtual void input(PlayerInput&& inputdata) = 0;
virtual void update(UpdateData&& updatedata) = 0;
// Separate CORE from SFML in the future
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const = 0;
};

View File

@ -3,9 +3,12 @@
#include <stack>
#include <memory>
#include <functional>
#include <SFML/Window/Event.hpp>
class GUIState
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Rect.hpp>
class GUIState : public sf::Drawable
{
public:
@ -25,8 +28,8 @@ public:
virtual void input(const sf::Event& event) = 0;
virtual void update(const sf::Time& dt) = 0;
virtual void draw() const = 0;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override = 0;
virtual void enter() = 0;
virtual void enter(sf::Vector2u&& render_size) = 0;
virtual void leave() = 0;
};

View File

@ -1,6 +1,6 @@
#include "shared/classicmode/classicfactory.h"
#include "game/classicgame.h"
#include "game/classicgraphicsmanager.h"
#include "graphics/classicgraphicsmanager.h"
#include "tools/music.h"
#include "editor/classiceditor.h"

View File

@ -1,5 +1,5 @@
#include "mockclassicnote.h"
#include "game/classicgraphicsmanager.h"
#include "graphics/classicgraphicsmanager.h"
// Replace with interface by dependency injection
#include "graphics/classicflyinganimationscenario.h"

View File

@ -1,5 +1,5 @@
#include "classicarrownote.h"
#include "game/classicgraphicsmanager.h"
#include "graphics/classicgraphicsmanager.h"
#include "graphics/classicanimationscenario.h"
#include "holdmanager.h"

View File

@ -1,10 +1,11 @@
#include "classicgame.h"
#include "classicnote.h"
#include "classicmapcreator.h"
#include "game/classicgraphicsmanager.h"
#include "game/classicgamegraphicsmanager.h"
#include "holdmanager.h"
ClassicGame::ClassicGame() :
_graphics_manager(new ClassicGameGraphicsManager(_timeline, 1648648)),
_hold_manager(std::make_unique<HoldManager>())
{
_slap_buffer.loadFromFile("Tick.ogg");
@ -93,11 +94,21 @@ void ClassicGame::input(PlayerInput&& inputdata)
void ClassicGame::update(UpdateData&& updatedata)
{
// UNCOMMENT TO TEST AUTOPLAY
/*auto note_it = _timeline.getActiveNote(updatedata.timestamp);
if (!_timeline.isExpired(note_it) && updatedata.timestamp >= (*note_it)->offset())
{
auto note = (*note_it);
note->input(PlayerInput{updatedata.timestamp, sf::Event{}});
_slap.play();
}*/
_timeline.update(updatedata.timestamp);
_graphics_manager->update(updatedata.timestamp);
}
void ClassicGame::draw() const
void ClassicGame::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
_graphics_manager->draw();
_graphics_manager->draw(target, states);
}

View File

@ -27,14 +27,14 @@ public:
virtual void input(PlayerInput&& inputdata) override;
virtual void update(UpdateData&& updatedata) override;
virtual void draw() const override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
private:
std::map<sf::Keyboard::Key, Type> _keys_to_buttons;
std::map<Type, Action> _buttons_to_pressed_actions;
std::map<Type, Action> _buttons_to_released_actions;
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
ClassicGraphicsManager * const _graphics_manager;
std::shared_ptr<HoldManager> _hold_manager;
Timeline<ClassicNote> _timeline;

View File

@ -1,21 +1,18 @@
#include "classicgraphicsmanager.h"
#include "classicgamegraphicsmanager.h"
#include "graphics/classicsprite.h"
#include "graphics/classicflyinganimationscenario.h"
#include "graphics/classicdyinganimationscenario.h"
ClassicGraphicsManager::ClassicGraphicsManager(Timeline<ClassicNote> &timeline, const microsec& visibility_offset) :
_sprite_container({Type::UP, Type::DOWN,
Type::LEFT, Type::RIGHT},
std::make_unique<ClassicSpriteFactory>()),
_timeline(&timeline),
_visibility_offset(visibility_offset)
ClassicGameGraphicsManager::ClassicGameGraphicsManager(Timeline<ClassicNote> &timeline, const microsec& visibility_offset) :
ClassicGraphicsManager(visibility_offset),
_timeline(&timeline)
{
_timeline->expire(_first);
_timeline->expire(_last);
}
void ClassicGraphicsManager::draw(sf::RenderTarget& target, sf::RenderStates states) const
void ClassicGameGraphicsManager::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (nothingToDraw())
return;
@ -26,7 +23,7 @@ void ClassicGraphicsManager::draw(sf::RenderTarget& target, sf::RenderStates sta
}
}
void ClassicGraphicsManager::draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const
void ClassicGameGraphicsManager::draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const
{
for (std::size_t i = 0; i < elements.size(); ++i)
{
@ -46,7 +43,7 @@ void ClassicGraphicsManager::draw(const std::vector<ClassicArrowNote::ArrowEleme
}
}
sf::VertexArray ClassicGraphicsManager::makeLine(const Coordinates& c1, const Coordinates& c2) const
sf::VertexArray ClassicGameGraphicsManager::makeLine(const Coordinates& c1, const Coordinates& c2) const
{
sf::VertexArray line(sf::LinesStrip, 2);
line[0].color = sf::Color::Yellow;
@ -57,7 +54,7 @@ sf::VertexArray ClassicGraphicsManager::makeLine(const Coordinates& c1, const Co
return line;
}
void ClassicGraphicsManager::setGraphics(std::vector<ClassicArrowNote::ArrowElement>& elements, TimeRange &&range)
void ClassicGameGraphicsManager::setGraphics(std::vector<ClassicArrowNote::ArrowElement>& elements, TimeRange &&range)
{
for (auto& element : elements)
{
@ -74,13 +71,21 @@ void ClassicGraphicsManager::setGraphics(std::vector<ClassicArrowNote::ArrowElem
}
}
void ClassicGraphicsManager::update(const microsec &offset)
void ClassicGameGraphicsManager::update(const microsec &offset)
{
fetchLastNote(offset);
fetchFirstNote(offset);
updateVisibleNotes(offset);
}
void ClassicGraphicsManager::fetchFirstNote(const microsec& offset)
void ClassicGameGraphicsManager::updateVisibleNotes(const microsec &offset)
{
for (auto it = _first; it != _last; ++it)
(*it)->update(offset);
}
void ClassicGameGraphicsManager::fetchFirstNote(const microsec& offset)
{
(void)offset; // ????
@ -98,7 +103,7 @@ void ClassicGraphicsManager::fetchFirstNote(const microsec& offset)
}
}
void ClassicGraphicsManager::fetchLastNote(const microsec& offset)
void ClassicGameGraphicsManager::fetchLastNote(const microsec& offset)
{
Iterator note_iterator = _timeline->getTopNote();
while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset))
@ -120,13 +125,13 @@ void ClassicGraphicsManager::fetchLastNote(const microsec& offset)
_last = note_iterator;
}
bool ClassicGraphicsManager::nothingToDraw() const noexcept
bool ClassicGameGraphicsManager::nothingToDraw() const noexcept
{
return _timeline->isExpired(_first)
|| _timeline->isExpired(_last);
}
bool ClassicGraphicsManager::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept
bool ClassicGameGraphicsManager::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept
{
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
}

View File

@ -1,27 +1,22 @@
#pragma once
#include "spritecontainer.h"
#include "classicmode/classicactions.h"
#include "graphics/classicspritefactory.h"
#include "classicarrownote.h"
#include "graphics/classicgraphicsmanager.h"
#include "core/timeline.h"
#include <SFML/Graphics/RenderTarget.hpp>
class ClassicSprite;
class ClassicGraphicsManager : public sf::Drawable
class ClassicGameGraphicsManager : public ClassicGraphicsManager
{
public:
explicit ClassicGraphicsManager(Timeline<ClassicNote>& timeline, const microsec& visibility_offset);
explicit ClassicGameGraphicsManager(Timeline<ClassicNote>& timeline, const microsec& visibility_offset);
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
void draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const;
void setGraphics(std::vector<ClassicArrowNote::ArrowElement> &elements, TimeRange&& range);
virtual void draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void setGraphics(std::vector<ClassicArrowNote::ArrowElement> &elements, TimeRange&& range) override;
void update(const microsec& offset);
void fetchFirstNote(const microsec& offset);
void fetchLastNote(const microsec& offset);
virtual void update(const microsec& offset) override;
private:
using Iterator = Timeline<ClassicNote>::Iterator;
@ -29,12 +24,13 @@ private:
Iterator _first;
Iterator _last;
SpriteContainer<Type, ClassicSpriteFactory, ClassicSprite> _sprite_container;
Timeline<ClassicNote> * const _timeline;
microsec _visibility_offset;
inline bool nothingToDraw() const noexcept;
inline bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept;
inline sf::VertexArray makeLine(const Coordinates& c1, const Coordinates& c2) const;
void fetchFirstNote(const microsec& offset);
void fetchLastNote(const microsec& offset);
void updateVisibleNotes(const microsec& offset);
};

View File

@ -10,7 +10,7 @@ auto classic::createBeatmap(const std::string& filepath, const Context &context)
{
(void) filepath;
microsec starting_beat_offset = 362162;
microsec starting_beat_offset = 402162;
int amount_of_beats = 209;
microsec interval = 1412162;
microsec tempo_interval = interval / 4;

View File

@ -1,11 +1,4 @@
#include "classicnote.h"
#include "graphics/classicsprite.h"
#include "game/classicgraphicsmanager.h"
// Replace with interface by dependency injection
#include "graphics/classicflyinganimationscenario.h"
#include "graphics/classicdyinganimationscenario.h"
//
ClassicNote::ClassicNote(NoteInitializer &&init) :
Note(init.perfect_offset),

View File

@ -0,0 +1,32 @@
#pragma once
#include "game/classicarrownote.h"
#include "spritecontainer.h"
#include "classicmode/classicactions.h"
#include "graphics/classicspritefactory.h"
#include <SFML/Graphics/RenderTarget.hpp>
class ClassicSprite;
class ClassicGraphicsManager : public sf::Drawable
{
public:
virtual ~ClassicGraphicsManager() = default;
explicit ClassicGraphicsManager(const microsec& visibility_offset) :
_sprite_container({Type::UP, Type::DOWN,
Type::LEFT, Type::RIGHT},
std::make_unique<ClassicSpriteFactory>()),
_visibility_offset(visibility_offset)
{}
virtual void draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const = 0;
virtual void setGraphics(std::vector<ClassicArrowNote::ArrowElement> &elements, TimeRange&& range) = 0;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override = 0;
virtual void update(const microsec& offset) = 0;
protected:
SpriteContainer<Type, ClassicSpriteFactory, ClassicSprite> _sprite_container;
microsec _visibility_offset;
};

View File

@ -31,15 +31,15 @@ Application::Application() :
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks), _font_holder);
const auto game_state = std::make_shared<GameState>(_game_window, classic::initGame(), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(_game_window, classic::initEditor(), std::move(editor_callbacks), _font_holder);
const auto main_menu = std::make_shared<MainMenu>(std::move(callbacks), _font_holder);
const auto game_state = std::make_shared<GameState>(classic::initGame(), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(classic::initEditor(), std::move(editor_callbacks), _font_holder);
_states[GUIState::Tag::MAIN_MENU] = main_menu;
_states[GUIState::Tag::GAME] = game_state;
_states[GUIState::Tag::EDITOR] = editor;
_state_stack.emplace_back(_states.at(GUIState::Tag::MAIN_MENU));
pushState(GUIState::Tag::MAIN_MENU);
}
void Application::run()
@ -97,21 +97,23 @@ void Application::draw()
_game_window.clear();
for (const auto& state : _state_stack)
state->draw();
_game_window.draw(*state);
_game_window.display();
}
void Application::pushState(GUIState::Tag new_state)
{
_state_stack.back()->leave();
if (!_state_stack.empty())
_state_stack.back()->leave();
_state_stack.emplace_back(_states.at(new_state));
_state_stack.back()->enter();
_state_stack.back()->enter(_game_window.getSize());
}
void Application::popState()
{
_state_stack.back()->leave();
_state_stack.pop_back();
_state_stack.back()->enter();
_state_stack.back()->enter(_game_window.getSize());
}

View File

@ -11,9 +11,8 @@
#include <iostream>
EditorState::EditorState(sf::RenderWindow& game_window, std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder) :
EditorState::EditorState(std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder) :
_font(font_holder.get(Fonts::Id::GUI)),
_game_window(game_window),
_callbacks(std::move(callbacks)),
_editor(std::move(editor))
{}
@ -31,12 +30,12 @@ void EditorState::update(const sf::Time& dt)
_group->update(dt);
}
void EditorState::draw() const
void EditorState::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
_game_window.draw(*_group);
target.draw(*_group, states);
}
void EditorState::enter()
void EditorState::enter(sf::Vector2u &&render_size)
{
_music.openFromFile("METEOR.flac");
_music.setVolume(5);
@ -95,7 +94,7 @@ void EditorState::enter()
group->unblock();
};
const float window_width = _game_window.getSize().x;
const float window_width = render_size.x;
auto menu_bar = std::make_shared<MenuBar>(_font);
@ -107,7 +106,9 @@ void EditorState::enter()
bpm_widget->setVisibility(true);
});
bpm_widget->setRect(sf::FloatRect(_game_window.getSize().x / 3, _game_window.getSize().y / 3, _game_window.getSize().x / 3, _game_window.getSize().y / 3));
bpm_widget->setRect(sf::FloatRect(render_size.x / 3, render_size.y / 3,
render_size.x / 3, render_size.y / 3));
bpm_widget->addBarButton("X", bpm_widget_callback);
bpm_widget->setVisibility(false);

View File

@ -18,18 +18,17 @@ public:
std::function<void(void)> onLeaveEditorState;
};
explicit EditorState(sf::RenderWindow& game_window, std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder);
explicit EditorState(std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder);
virtual ~EditorState() override;
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw() const override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter() override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
const std::shared_ptr<sf::Font> _font;
sf::RenderWindow& _game_window;
Callbacks _callbacks;

View File

@ -4,10 +4,8 @@
#include "core/game.h"
GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr<Game>& game,
Callbacks&& callbacks) :
GameState::GameState(const std::shared_ptr<Game>& game, Callbacks&& callbacks) :
_game(game),
_game_window(game_window),
_onLeaveGameCallback(callbacks.onLeaveGame)
{}
@ -24,13 +22,14 @@ void GameState::update(const sf::Time& dt)
_game->update(UpdateData{_music.fetchOffset(), dt});
}
void GameState::draw() const
void GameState::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
_game->draw();
_game->draw(target, states);
}
void GameState::enter()
void GameState::enter(sf::Vector2u&& render_size)
{
(void)render_size; // We will need this later when I add UI to game state
_game->run();
_music.openFromFile("METEOR.flac");

View File

@ -17,21 +17,18 @@ public:
};
explicit GameState(sf::RenderWindow& game_window,
const std::shared_ptr<Game>& game,
Callbacks&& callbacks);
explicit GameState(const std::shared_ptr<Game>& game, Callbacks&& callbacks);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw() const override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter() override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
Music _music;
std::shared_ptr<Game> _game;
sf::RenderWindow& _game_window;
std::function<void(void)> _onEnterGameCallback;
std::function<void(void)> _onLeaveGameCallback;

View File

@ -2,31 +2,11 @@
#include "widgets/pushbutton.h"
#include "widgets/group.h"
MainMenu::MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks, const FontHolder& font_holder) :
_buttons(std::make_shared<Group>()),
_game_window(game_window)
MainMenu::MainMenu(Callbacks&& callbacks, const FontHolder& font_holder) :
_font(font_holder.get(Fonts::Id::GUI)),
_callbacks(std::move(callbacks)),
_buttons(std::make_shared<Group>())
{
const float window_width = game_window.getSize().x;
const float window_height = game_window.getSize().y;
auto button_start = std::make_shared<PushButton>("Start", font_holder.get(Fonts::Id::GUI), 48);
button_start->setRect(sf::FloatRect(window_width / 3., window_height / 7., window_width / 3., window_height / 7.));
button_start->setCallback(callbacks.onAppendGameState);
auto button_editor = std::make_shared<PushButton>("Editor", font_holder.get(Fonts::Id::GUI), 48);
button_editor->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 3, window_width / 3., window_height / 7.));
button_editor->setCallback(callbacks.onAppendEditorState);
auto button_exit = std::make_shared<PushButton>("Exit", font_holder.get(Fonts::Id::GUI), 48);
button_exit->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 5, window_width / 3., window_height / 7.));
button_exit->setCallback([&]()
{
_game_window.close();
});
_buttons->addChild(button_start);
_buttons->addChild(button_editor);
_buttons->addChild(button_exit);
}
void MainMenu::input(const sf::Event& event)
@ -39,13 +19,27 @@ void MainMenu::update(const sf::Time& dt)
_buttons->update(dt);
}
void MainMenu::draw() const
void MainMenu::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
_game_window.draw(*_buttons);
target.draw(*_buttons, states);
}
void MainMenu::enter()
void MainMenu::enter(sf::Vector2u&& render_size)
{
const float window_width = render_size.x;
const float window_height = render_size.y;
auto button_start = std::make_shared<PushButton>("Start", _font, 48);
button_start->setRect(sf::FloatRect(window_width / 3., window_height / 7., window_width / 3., window_height / 7.));
button_start->setCallback(_callbacks.onAppendGameState);
auto button_editor = std::make_shared<PushButton>("Editor", _font, 48);
button_editor->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 3, window_width / 3., window_height / 7.));
button_editor->setCallback(_callbacks.onAppendEditorState);
_buttons->addChild(button_start);
_buttons->addChild(button_editor);
_buttons->setVisibility();
}

View File

@ -16,16 +16,18 @@ public:
std::function<void(void)> onAppendEditorState;
};
explicit MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks, const FontHolder &font_holder);
explicit MainMenu(Callbacks&& callbacks, const FontHolder &font_holder);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw() const override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter() override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
const std::shared_ptr<sf::Font> _font;
const Callbacks _callbacks;
std::shared_ptr<Group> _buttons;
sf::RenderWindow& _game_window;
};