From 8b4d3620008a1f91c37432aa265e0e4768839f0a Mon Sep 17 00:00:00 2001 From: NaiJi Date: Thu, 23 Dec 2021 20:33:24 +0300 Subject: [PATCH] Implement complex graphics logic for notes --- core/shared/core/game.h | 1 - core/shared/core/note.h | 2 +- modes/classicmode/editor/mockclassicnote.cpp | 4 +- modes/classicmode/editor/mockclassicnote.h | 2 +- modes/classicmode/game/classicarrownote.cpp | 20 +++-- modes/classicmode/game/classicarrownote.h | 10 ++- modes/classicmode/game/classicgame.cpp | 2 + .../game/classicgraphicsmanager.cpp | 90 +++++++++++++++++-- .../classicmode/game/classicgraphicsmanager.h | 9 +- modes/classicmode/game/classicnote.cpp | 2 +- modes/classicmode/game/classicnote.h | 10 ++- src/application/application.cpp | 4 +- tools/shared/tools/mathutils.h | 14 +++ 13 files changed, 140 insertions(+), 30 deletions(-) diff --git a/core/shared/core/game.h b/core/shared/core/game.h index a8520e7..f43ddd9 100644 --- a/core/shared/core/game.h +++ b/core/shared/core/game.h @@ -12,5 +12,4 @@ public: virtual void input(PlayerInput&& inputdata) = 0; virtual void update(UpdateData&& updatedata) = 0; - virtual void draw() const = 0; }; diff --git a/core/shared/core/note.h b/core/shared/core/note.h index c8582bd..93c984f 100644 --- a/core/shared/core/note.h +++ b/core/shared/core/note.h @@ -12,7 +12,7 @@ public: virtual bool isActive(const microsec& offset) const = 0; virtual void update(const microsec& music_offset) = 0; - virtual void putToGame(const microsec& offset) = 0; + virtual void putToGame() = 0; virtual bool isInGame() const = 0; virtual bool shouldRemove() const = 0; diff --git a/modes/classicmode/editor/mockclassicnote.cpp b/modes/classicmode/editor/mockclassicnote.cpp index 4bab56c..88544ef 100644 --- a/modes/classicmode/editor/mockclassicnote.cpp +++ b/modes/classicmode/editor/mockclassicnote.cpp @@ -41,9 +41,9 @@ bool MockClassicNote::shouldRemove() const || _state == State::NONE; } -void MockClassicNote::putToGame(const microsec &music_offset) +void MockClassicNote::putToGame() { - _state = State::FLYING; (void)music_offset; + _state = State::FLYING; } void MockClassicNote::update(const microsec &music_offset) diff --git a/modes/classicmode/editor/mockclassicnote.h b/modes/classicmode/editor/mockclassicnote.h index 79d6716..d3dc505 100644 --- a/modes/classicmode/editor/mockclassicnote.h +++ b/modes/classicmode/editor/mockclassicnote.h @@ -29,7 +29,7 @@ public: virtual bool isInGame() const override final; virtual bool shouldRemove() const override final; - virtual void putToGame(const microsec &music_offset) override final; + virtual void putToGame() override final; virtual void update(const microsec &music_offset) override final; private: diff --git a/modes/classicmode/game/classicarrownote.cpp b/modes/classicmode/game/classicarrownote.cpp index 71aaad7..2a538e3 100644 --- a/modes/classicmode/game/classicarrownote.cpp +++ b/modes/classicmode/game/classicarrownote.cpp @@ -1,12 +1,8 @@ #include "classicarrownote.h" #include "game/classicgraphicsmanager.h" +#include "graphics/classicanimationscenario.h" #include "holdmanager.h" -// Replace with interface by dependency injection -#include "graphics/classicflyinganimationscenario.h" -#include "graphics/classicdyinganimationscenario.h" -// - ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) : ClassicNote(std::move(init.initializer)), _is_hold(init.hold) @@ -21,9 +17,9 @@ ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) : } } -void ClassicArrowNote::putToGame(const microsec &music_offset) +void ClassicArrowNote::putToGame() { - _state = State::FLYING; (void)music_offset; + _state = State::FLYING; } void ClassicArrowNote::input(PlayerInput&& inputdata) @@ -93,6 +89,16 @@ void ClassicArrowNote::update(const microsec& music_offset) element.animations[_state]->update(music_offset); } +void ClassicArrowNote::draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const +{ + manager->draw(_elements, target, states); +} + +void ClassicArrowNote::setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) +{ + manager->setGraphics(_elements, std::move(range)); +} + bool ClassicArrowNote::allElementsPressed() const { return std::all_of(_elements.begin(), _elements.end(), diff --git a/modes/classicmode/game/classicarrownote.h b/modes/classicmode/game/classicarrownote.h index 991c4c0..c5f7060 100644 --- a/modes/classicmode/game/classicarrownote.h +++ b/modes/classicmode/game/classicarrownote.h @@ -9,16 +9,17 @@ public: explicit ClassicArrowNote(ArrowNoteInitializer&& init); virtual ~ClassicArrowNote() = default; - virtual void putToGame(const microsec& music_offset) override; + virtual void putToGame() override; virtual void update(const microsec &music_offset) override; virtual void input(PlayerInput&& inputdata) override; + virtual void draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const override; + virtual void setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) override; + bool allElementsPressed() const; bool isPressedAs(sf::Keyboard::Key key) const; inline bool isHold() const; -private: - struct ArrowElement { std::shared_ptr sprite; @@ -36,6 +37,9 @@ private: // Note Element represents this idea. }; +private: std::vector _elements; bool _is_hold; }; + +using ArrowElements = std::vector; diff --git a/modes/classicmode/game/classicgame.cpp b/modes/classicmode/game/classicgame.cpp index ece48f6..705d401 100644 --- a/modes/classicmode/game/classicgame.cpp +++ b/modes/classicmode/game/classicgame.cpp @@ -94,8 +94,10 @@ void ClassicGame::input(PlayerInput&& inputdata) void ClassicGame::update(UpdateData&& updatedata) { _timeline.update(updatedata.timestamp); + _graphics_manager->update(updatedata.timestamp); } void ClassicGame::draw() const { + _graphics_manager->draw(); } diff --git a/modes/classicmode/game/classicgraphicsmanager.cpp b/modes/classicmode/game/classicgraphicsmanager.cpp index 5d7f462..9127b26 100644 --- a/modes/classicmode/game/classicgraphicsmanager.cpp +++ b/modes/classicmode/game/classicgraphicsmanager.cpp @@ -1,6 +1,9 @@ #include "classicgraphicsmanager.h" #include "graphics/classicsprite.h" +#include "graphics/classicflyinganimationscenario.h" +#include "graphics/classicdyinganimationscenario.h" + ClassicGraphicsManager::ClassicGraphicsManager(Timeline &timeline, const microsec& visibility_offset) : _sprite_container({Type::UP, Type::DOWN, Type::LEFT, Type::RIGHT}, @@ -17,19 +20,85 @@ void ClassicGraphicsManager::draw(sf::RenderTarget& target, sf::RenderStates sta if (nothingToDraw()) return; - std::for_each(_first, _last, - [&target, &states](const auto& note) - { - target.draw(*note->sprite(), states); - }); + for (auto it = _first; it != _last; ++it) + { + (*it)->draw(this, target, states); + } } -std::shared_ptr ClassicGraphicsManager::getSprite(Type type) +void ClassicGraphicsManager::draw(const std::vector& elements, sf::RenderTarget& target, sf::RenderStates states) const { - return _sprite_container.getSprite(type); + for (std::size_t i = 0; i < elements.size(); ++i) + { + const auto& sprite = elements[i].sprite; + + if (i >= 1) + { + const auto& neighbor_sprite = elements[i - 1].sprite; + + const auto c1 = neighbor_sprite->trailCoordinates(); + const auto c2 = sprite->trailCoordinates(); + + target.draw(makeLine(c1, c2)); + } + + target.draw(*sprite, states); + } +} + +sf::VertexArray ClassicGraphicsManager::makeLine(const Coordinates& c1, const Coordinates& c2) const +{ + sf::VertexArray line(sf::LinesStrip, 2); + line[0].color = sf::Color::Yellow; + line[0].position = {c1.x + 10, c1.y}; + line[1].color = sf::Color::Blue; + line[1].position = {c2.x + 10, c2.y}; + + return line; +} + +void ClassicGraphicsManager::setGraphics(std::vector& elements, TimeRange &&range) +{ + for (auto& element : elements) + { + element.sprite = _sprite_container.getSprite(element.type); + element.sprite->setCoordinates(element.coordinates); + element.sprite->setTrailCoordinates(Coordinates( 0.f, 9.f )); + + element.animations[ClassicArrowNote::State::NONE] = nullptr; + element.animations[ClassicArrowNote::State::FLYING] = std::make_shared(); + element.animations[ClassicArrowNote::State::DYING] = std::make_shared(); + element.animations[ClassicArrowNote::State::DEAD] = nullptr; + + element.animations[ClassicArrowNote::State::FLYING]->launch(element.sprite, range.begin, range.end); + } } void ClassicGraphicsManager::update(const microsec &offset) +{ + fetchLastNote(offset); + fetchFirstNote(offset); +} + +void ClassicGraphicsManager::fetchFirstNote(const microsec& offset) +{ + (void)offset; // ???? + + if (nothingToDraw()) + return; + + Iterator note_iterator = _first; + while (note_iterator != _last) + { + auto note = *note_iterator; + if (note->shouldRemove()) + ++_first; + + ++note_iterator; + } +} + +void ClassicGraphicsManager::fetchLastNote(const microsec& offset) { Iterator note_iterator = _timeline->getTopNote(); while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset)) @@ -40,7 +109,10 @@ void ClassicGraphicsManager::update(const microsec &offset) auto note = *note_iterator; if (!note->isInGame()) - note->putToGame(offset); + { + note->putToGame(); + note->setGraphics(this, TimeRange{offset, note->offset()}); + } ++note_iterator; } @@ -56,5 +128,5 @@ bool ClassicGraphicsManager::nothingToDraw() const noexcept bool ClassicGraphicsManager::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept { - return ((iterator)->offset() - _visibility_offset) <= music_offset; + return ((*iterator)->offset() - _visibility_offset) <= music_offset; } diff --git a/modes/classicmode/game/classicgraphicsmanager.h b/modes/classicmode/game/classicgraphicsmanager.h index 1ae96d6..d439f01 100644 --- a/modes/classicmode/game/classicgraphicsmanager.h +++ b/modes/classicmode/game/classicgraphicsmanager.h @@ -3,7 +3,7 @@ #include "spritecontainer.h" #include "classicmode/classicactions.h" #include "graphics/classicspritefactory.h" -#include "classicnote.h" +#include "classicarrownote.h" #include "core/timeline.h" #include @@ -16,8 +16,12 @@ public: explicit ClassicGraphicsManager(Timeline& timeline, const microsec& visibility_offset); virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; - std::shared_ptr getSprite(Type type); + void draw(const std::vector& elements, sf::RenderTarget& target, sf::RenderStates states) const; + void setGraphics(std::vector &elements, TimeRange&& range); + void update(const microsec& offset); + void fetchFirstNote(const microsec& offset); + void fetchLastNote(const microsec& offset); private: using Iterator = Timeline::Iterator; @@ -32,4 +36,5 @@ private: 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; }; diff --git a/modes/classicmode/game/classicnote.cpp b/modes/classicmode/game/classicnote.cpp index 78cffd6..b35071a 100644 --- a/modes/classicmode/game/classicnote.cpp +++ b/modes/classicmode/game/classicnote.cpp @@ -1,6 +1,6 @@ #include "classicnote.h" #include "graphics/classicsprite.h" -#include "graphics/classicgraphicsmanager.h" +#include "game/classicgraphicsmanager.h" // Replace with interface by dependency injection #include "graphics/classicflyinganimationscenario.h" diff --git a/modes/classicmode/game/classicnote.h b/modes/classicmode/game/classicnote.h index 07e6f1d..7c665db 100644 --- a/modes/classicmode/game/classicnote.h +++ b/modes/classicmode/game/classicnote.h @@ -7,6 +7,9 @@ class ClassicSprite; class ClassicAnimationScenario; +class ClassicGraphicsManager; + +namespace sf { class RenderTarget; class RenderStates; } class ClassicNote : public Note { @@ -35,11 +38,16 @@ public: virtual bool isInGame() const override final; virtual bool shouldRemove() const override final; - virtual void putToGame(const microsec &music_offset) override = 0; + virtual void putToGame() override = 0; virtual void update(const microsec &music_offset) override = 0; virtual void input(PlayerInput&& inputdata) = 0; + // encapsulate + virtual void draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const = 0; + virtual void setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) = 0; + // + protected: const PrecisionEvaluator _evaluator; diff --git a/src/application/application.cpp b/src/application/application.cpp index 993e842..720a4f7 100644 --- a/src/application/application.cpp +++ b/src/application/application.cpp @@ -32,8 +32,8 @@ Application::Application() : EditorState::Callbacks editor_callbacks = {[&](){ popState(); }}; const auto main_menu = std::make_shared(_game_window, std::move(callbacks), _font_holder); - const auto game_state = std::make_shared(_game_window, classic::initGame(_game_window), GameState::Callbacks()); - const auto editor = std::make_shared(_game_window, classic::initEditor(_game_window), std::move(editor_callbacks), _font_holder); + const auto game_state = std::make_shared(_game_window, classic::initGame(), GameState::Callbacks()); + const auto editor = std::make_shared(_game_window, classic::initEditor(), std::move(editor_callbacks), _font_holder); _states[GUIState::Tag::MAIN_MENU] = main_menu; _states[GUIState::Tag::GAME] = game_state; diff --git a/tools/shared/tools/mathutils.h b/tools/shared/tools/mathutils.h index b0476f8..19ff5a4 100644 --- a/tools/shared/tools/mathutils.h +++ b/tools/shared/tools/mathutils.h @@ -2,6 +2,20 @@ using microsec = long long; +struct TimeRange +{ + const microsec begin = 0; + const microsec end = 0; + + constexpr inline explicit TimeRange() noexcept : + begin(0), end(0) + {} + + constexpr inline explicit TimeRange(microsec x, microsec y) noexcept : + begin(x), end(y) + {} +}; + struct Coordinates { float x;