diff --git a/src/modes/classicmode/game/classicarrownote.cpp b/src/modes/classicmode/game/classicarrownote.cpp new file mode 100644 index 0000000..7af5c2e --- /dev/null +++ b/src/modes/classicmode/game/classicarrownote.cpp @@ -0,0 +1,43 @@ +#include "game/classicarrownote.h" +#include "classicmode/context.h" + +ClassicArrowNote::ClassicArrowNote(Init&& init) : + ClassicNote(init.perfect_offset), + _evaluator(init.intervals, init.perfect_offset), + _context(init.context) +{ + _elements.resize(init.elements.size()); + + for (std::size_t i = 0; i < _elements.size(); ++i) + { + _elements[i].keys = init.elements[i].keys; + _elements[i].position = init.elements[i].position; + _elements[i].type = init.elements[i].type; + } +} + +bool ClassicArrowNote::isActive(const kku::microsec& offset) const +{ + return _evaluator.isActive(offset) + && _state != State::DYING; +} + +void ClassicArrowNote::update(const kku::microsec &music_offset) +{ + _context->update(this, music_offset); +} + +void ClassicArrowNote::input(kku::GameEvent&& input) +{ + _context->input(this, std::move(input)); +} + +std::vector& ClassicArrowNote::getElements() +{ + return _elements; +} + +auto ClassicArrowNote::calculatePrecision(const kku::microsec& offset) const -> Grade +{ + return _evaluator.calculatePrecision(offset); +} diff --git a/src/modes/classicmode/game/classicarrownote.h b/src/modes/classicmode/game/classicarrownote.h index 40ac86b..6f9dc00 100644 --- a/src/modes/classicmode/game/classicarrownote.h +++ b/src/modes/classicmode/game/classicarrownote.h @@ -2,138 +2,44 @@ #include "core/precisionevaluator.h" #include "classicmode/classicnote.h" -#include "graphics/animations/classicanimationscenario.h" +#include "game/arrowelement.h" #include -template +class Context; + class ClassicArrowNote : public ClassicNote { public: struct Init { + const Context * const context; const kku::microsec perfect_offset = 0; const std::vector& intervals = {}; - const std::vector& elements = {}; + const std::vector& elements = {}; }; enum class Grade { - PERFECT, - GOOD, - BAD + PERFECT = 0, + GOOD = 1, + BAD = 2 }; - explicit ClassicArrowNote(Init&& init) : - ClassicNote(init.perfect_offset), - _evaluator(init.intervals, init.perfect_offset) - { - _elements.resize(init.elements.size()); - - for (std::size_t i = 0; i < _elements.size(); ++i) - { - _elements[i].keys = init.elements[i].keys; - _elements[i].position = init.elements[i].element.position; - _elements[i].type = init.elements[i].element.type; - } - } - - virtual bool isActive(const kku::microsec& offset) const override - { - return _evaluator.isActive(offset) - && _state != State::DYING; - } - - virtual void update(const kku::microsec &music_offset) override - { - switch (_state) - { - default: return; - break; - - case State::FLYING: - if (!_evaluator.isActive(music_offset) && music_offset > getPerfectOffset()) - { - _state = State::DYING; - for (auto& element : _elements) - element.animations[_state]->launch(element.sprite, music_offset, getPerfectOffset()); - } - break; - - case State::DYING: - if (_elements[0].animations[_state]->isDone()) - _state = State::DEAD; - break; - } - - for (auto& element : _elements) - if (element.animations[_state]) - element.animations[_state]->update(music_offset); - } - - virtual void input(kku::GameEvent&& input) override - { - auto grade = Grade::BAD; + explicit ClassicArrowNote(Init&& init); - bool input_valid = std::any_of(_elements.begin(), _elements.end(), - [input=input](auto& element) - { - if (element.pressed) - return false; + virtual bool isActive(const kku::microsec& offset) const override; + virtual void update(const kku::microsec &music_offset) override; + virtual void input(kku::GameEvent&& input) override; - const auto code = std::get(input.event.data).view; - auto key_iterator = std::find(element.keys.begin(), element.keys.end(), code); - - bool found_key = key_iterator != element.keys.end(); - if (found_key) - { - element.pressed = true; - element.pressed_as = code; - } - - return found_key; - }); - - bool all_pressed = allElementsPressed(); - - if (all_pressed) - { - grade = _evaluator.calculatePrecision(input.timestamp); - //if (isHold()) - //_hold_manager->emplace(this); - } - - if (all_pressed || !input_valid) - { - _state = State::DYING; - for (auto& element : _elements) - element.animations[_state]->launch(element.sprite, input.timestamp, getPerfectOffset()); - } - - std::cout << "User input: " << static_cast(grade) << "\n"; - } - - bool allElementsPressed() const - { - return std::all_of(_elements.begin(), _elements.end(), - [](const auto& element) - { - return element.pressed; - }); - } - - bool isPressedAs(kku::SystemEvent::Key::Code key) const - { - return std::any_of(_elements.begin(), _elements.end(), - [key](const auto& element) - { - return key == element.pressed_as; - }); - } + bool isHold() const; + std::vector& getElements(); + Grade calculatePrecision(const kku::microsec& offset) const; private: const kku::PrecisionEvaluator _evaluator; - std::vector _elements; + std::vector _elements; + const Context * const _context; }; diff --git a/src/modes/classicmode/game/gamecontext.cpp b/src/modes/classicmode/game/gamecontext.cpp new file mode 100644 index 0000000..5fd4d87 --- /dev/null +++ b/src/modes/classicmode/game/gamecontext.cpp @@ -0,0 +1,85 @@ +#include "gamecontext.h" +#include "game/classicarrownote.h" +#include "game/holdmanager.h" +#include "graphics/animations/classicanimationscenario.h" + +GameContext::GameContext(HoldManager *hold_manager, ClassicGraphicsManager *graphics_manager) : + _hold_manager(hold_manager), + _graphics_manager(graphics_manager) +{} + +void GameContext::input(ClassicArrowNote *note, kku::GameEvent&& input) const +{ + auto grade = ClassicArrowNote::Grade::BAD; + auto& elements = note->getElements(); + + bool input_valid = std::any_of(elements.begin(), elements.end(), + [input=input](auto& element) + { + if (element.pressed) + return false; + + const auto code = std::get(input.event.data).view; + auto key_iterator = std::find(element.keys.begin(), element.keys.end(), code); + + bool found_key = key_iterator != element.keys.end(); + if (found_key) + { + element.pressed = true; + element.pressed_as = code; + } + + return found_key; + }); + + bool all_pressed = std::all_of(elements.begin(), elements.end(), + [](const auto& element) + { + return element.pressed; + }); + + if (all_pressed) + { + grade = note->calculatePrecision(input.timestamp); + if (note->isHold()) + _hold_manager->emplace(note); + } + + if (all_pressed || !input_valid) + { + note->setState(ClassicArrowNote::State::DYING); + for (auto& element : elements) + element.animations[note->getState()]->launch(element.sprite, input.timestamp, note->getPerfectOffset()); + } + + std::cout << "User input: " << static_cast(grade) << "\n"; +} + +void GameContext::update(ClassicArrowNote *note, const kku::microsec& music_offset) const +{ + auto& elements = note->getElements(); + + switch (note->getState()) + { + default: return; + break; + + case ClassicArrowNote::State::FLYING: + if (!note->isActive(music_offset) && music_offset > note->getPerfectOffset()) + { + note->setState(ClassicArrowNote::State::DYING); + for (auto& element : elements) + element.animations[note->getState()]->launch(element.sprite, music_offset, note->getPerfectOffset()); + } + break; + + case ClassicArrowNote::State::DYING: + if (elements[0].animations[note->getState()]->isDone()) + note->setState(ClassicArrowNote::State::DEAD); + break; + } + + for (auto& element : elements) + if (element.animations[note->getState()]) + element.animations[note->getState()]->update(music_offset); +} diff --git a/src/modes/classicmode/game/gamecontext.h b/src/modes/classicmode/game/gamecontext.h new file mode 100644 index 0000000..1848af0 --- /dev/null +++ b/src/modes/classicmode/game/gamecontext.h @@ -0,0 +1,19 @@ +#pragma once + +#include "classicmode/context.h" + +class HoldManager; +class ClassicGraphicsManager; + +class GameContext : public Context +{ +public: + explicit GameContext(HoldManager *hold_manager, ClassicGraphicsManager *graphics_manager); + + virtual void input(ClassicArrowNote *note, kku::GameEvent&& input) const override; + virtual void update(ClassicArrowNote *note, const kku::microsec &music_offset) const override; + +private: + HoldManager * const _hold_manager; + ClassicGraphicsManager * const _graphics_manager; +}; diff --git a/src/modes/classicmode/game/holdmanager.h b/src/modes/classicmode/game/holdmanager.h index fb04acd..37bd9d2 100644 --- a/src/modes/classicmode/game/holdmanager.h +++ b/src/modes/classicmode/game/holdmanager.h @@ -12,12 +12,12 @@ class ClassicGraphicsManager; class HoldManager { public: - void emplace(ClassicArrowNote* note); + void emplace(ClassicArrowNote* note); void checkRelease(kku::SystemEvent::Key::Code released_key); void drawHoldBar(); private: - std::vector*> _notes_on_hold; + std::vector _notes_on_hold; std::shared_ptr _graphics_manager; }; diff --git a/src/modes/classicmode/include/classicmode/classicnote.h b/src/modes/classicmode/include/classicmode/classicnote.h index 073c3ec..1fa460f 100644 --- a/src/modes/classicmode/include/classicmode/classicnote.h +++ b/src/modes/classicmode/include/classicmode/classicnote.h @@ -8,11 +8,11 @@ public: enum State { - NONE, + NONE = 0, - FLYING, - DYING, - DEAD + FLYING = 1, + DYING = 2, + DEAD = 3 }; explicit ClassicNote(const kku::microsec& perfect_offset); diff --git a/src/modes/classicmode/include/classicmode/context.h b/src/modes/classicmode/include/classicmode/context.h new file mode 100644 index 0000000..333fda4 --- /dev/null +++ b/src/modes/classicmode/include/classicmode/context.h @@ -0,0 +1,15 @@ +#pragma once + +#include "core/time.h" +#include "core/gameevent.h" + +class ClassicArrowNote; + +class Context +{ +public: + virtual ~Context() = default; + + virtual void input(ClassicArrowNote *note, kku::GameEvent&& input) const = 0; + virtual void update(ClassicArrowNote *note, const kku::microsec &music_offset) const = 0; +};