#include "classicnote.h" #include "classicsprite.h" #include "classicgraphicsmanager.h" // Replace with interface by dependency injection #include "classicflyinganimationscenario.h" #include "classicdyinganimationscenario.h" // ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::shared_ptr& manager) : Note(init.perfect_offset), _evaluator(init.intervals, _perfect_offset), _graphics_manager(manager), _state(State::NONE) { _elements.resize(init.elements.size()); _isHold = init.hold; for (std::size_t i = 0; i < _elements.size(); ++i) { _elements[i].keys = init.elements[i].keys; _elements[i].coordinates = init.elements[i].coordinates; _elements[i].type = init.elements[i].type; // Animations will be injected into note. _elements[i].animations[State::NONE] = nullptr; _elements[i].animations[State::FLYING] = std::make_shared(); _elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING]; _elements[i].animations[State::DYING] = std::make_shared(); _elements[i].animations[State::DEAD] = nullptr; } } bool ClassicNote::isActive() const { return _state == State::ACTIVE; } void ClassicNote::putToGame(const microsec &music_offset) { _state = State::FLYING; for (auto& element : _elements) { element.sprite = _graphics_manager->getSprite(element.type); element.sprite->setCoordinates(element.coordinates, 0., 9.); element.animations[_state]->launch(element.sprite, music_offset, offset()); } } bool ClassicNote::isInGame() const { return _state == State::FLYING || _state == State::ACTIVE || _state == State::DYING; } bool ClassicNote::shouldRemove() const { return _state == State::DEAD; } void ClassicNote::update(const microsec& music_offset) { switch (_state) { default: return; break; case State::FLYING: if (_evaluator.isActive(music_offset)) _state = State::ACTIVE; break; case State::DYING: if (_elements[0].animations[_state]->isDone()) _state = State::DEAD; break; case State::ACTIVE: if (!_evaluator.isActive(music_offset)) { _state = State::DYING; for (auto& element : _elements) element.animations[_state]->launch(element.sprite, music_offset, offset()); } break; } for (auto& element : _elements) if (element.animations[_state]) element.animations[_state]->update(music_offset); } void ClassicNote::input(PlayerInput&& inputdata) { auto grade = ClassicNote::Grade::BAD; bool input_valid = std::any_of(_elements.begin(), _elements.end(), [inputdata=inputdata](auto& element) { if (element.pressed) return false; auto key_iterator = std::find(element.keys.begin(), element.keys.end(), inputdata.event.key.code); bool found_key = key_iterator != element.keys.end(); if (found_key) { element.pressed = true; element.pressed_as = inputdata.event.key.code; } return found_key; }); bool all_pressed = allElementsPressed(); if (all_pressed) grade = _evaluator.calculatePrecision(inputdata.timestamp); if (all_pressed || !input_valid) { _state = State::DYING; for (auto& element : _elements) element.animations[_state]->launch(element.sprite, inputdata.timestamp, offset()); } std::cout << "User input: " << static_cast(grade) << "\n"; } void ClassicNote::draw() const { for (std::size_t i = 0; i < _elements.size(); ++i) { if (i >= 1) _graphics_manager->drawLine(_elements[i-1].sprite->trailCoordinates(), _elements[i].sprite->trailCoordinates()); _graphics_manager->draw(_elements[i].sprite); } } bool ClassicNote::isHold() const { return _isHold; } bool ClassicNote::allElementsPressed() const { return std::all_of(_elements.begin(), _elements.end(), [](const auto& element) { return element.pressed; }); } bool ClassicNote::isPressedAs(sf::Keyboard::Key key) const { return std::any_of(_elements.begin(), _elements.end(), [key=key](const auto& element) { return key == element.pressed_as; }); }