#pragma once #include "core/precisionevaluator.h" #include "classicmode/classicnote.h" #include "graphics/animations/classicanimationscenario.h" #include template class ClassicArrowNote : public ClassicNote { public: struct Init { const kku::microsec perfect_offset = 0; const std::vector& intervals = {}; const std::vector& elements = {}; }; enum class Grade { PERFECT, GOOD, BAD }; 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; 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 = 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; }); } private: const kku::PrecisionEvaluator _evaluator; std::vector _elements; };