From bf409c0a610503d6e66427c2bd08a201a2e04eac Mon Sep 17 00:00:00 2001 From: NaiJi Date: Thu, 15 Jul 2021 06:45:52 +0400 Subject: [PATCH] Implement multinotes --- src/classicgame/classicgraphicsmanager.cpp | 21 +-- src/classicgame/classicgraphicsmanager.h | 6 +- src/classicgame/classicmapcreator.cpp | 29 ++++- src/classicgame/classicnote.cpp | 145 ++++++++++++--------- src/classicgame/classicnote.h | 36 +++-- src/classicgame/classicsprite.cpp | 5 + src/classicgame/classicsprite.h | 1 + 7 files changed, 155 insertions(+), 88 deletions(-) diff --git a/src/classicgame/classicgraphicsmanager.cpp b/src/classicgame/classicgraphicsmanager.cpp index 8859b16..fe5e883 100644 --- a/src/classicgame/classicgraphicsmanager.cpp +++ b/src/classicgame/classicgraphicsmanager.cpp @@ -1,5 +1,5 @@ #include "classicgraphicsmanager.h" -#include "classicnote.h" +#include "classicsprite.h" ClassicGraphicsManager::ClassicGraphicsManager(sf::RenderTarget& target) : _sprite_container({Type::UP, Type::DOWN, @@ -8,19 +8,22 @@ ClassicGraphicsManager::ClassicGraphicsManager(sf::RenderTarget& target) : _render_target(target) {} -void ClassicGraphicsManager::initGraphics(ClassicNote* note) +std::shared_ptr ClassicGraphicsManager::getSprite(Type type) { - note->setSprite(_sprite_container.getSprite(note->type())); - note->sprite()->setCoordinates(note->getCoordinates(), 0, 0); + return _sprite_container.getSprite(type); } -void ClassicGraphicsManager::resetGraphics(ClassicNote* note) +void ClassicGraphicsManager::draw(const std::shared_ptr& sprite) { - _sprite_container.resetSprite(note->sprite(), note->type()); - note->setSprite(nullptr); + _render_target.draw(*sprite); } -void ClassicGraphicsManager::draw(const ClassicNote *note) +void ClassicGraphicsManager::drawLine(const Coordinates &p1, const Coordinates &p2) { - _render_target.draw(*note->sprite()); + sf::VertexArray line(sf::LinesStrip, 2); + line[0].color = sf::Color::Yellow; + line[0].position = {p1.x + 10, p1.y}; + line[1].color = sf::Color::Blue; + line[1].position = {p2.x + 10, p2.y}; + _render_target.draw(line); } diff --git a/src/classicgame/classicgraphicsmanager.h b/src/classicgame/classicgraphicsmanager.h index f21f885..a2ffdca 100644 --- a/src/classicgame/classicgraphicsmanager.h +++ b/src/classicgame/classicgraphicsmanager.h @@ -14,9 +14,9 @@ class ClassicGraphicsManager public: explicit ClassicGraphicsManager(sf::RenderTarget& target); - void initGraphics(ClassicNote* note); - void resetGraphics(ClassicNote* note); - void draw(const ClassicNote *note); + std::shared_ptr getSprite(Type type); + void draw(const std::shared_ptr &sprite); + void drawLine(const Coordinates &p1, const Coordinates &p2); private: SpriteContainer _sprite_container; diff --git a/src/classicgame/classicmapcreator.cpp b/src/classicgame/classicmapcreator.cpp index 44dd962..7eaac04 100644 --- a/src/classicgame/classicmapcreator.cpp +++ b/src/classicgame/classicmapcreator.cpp @@ -25,9 +25,36 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const float x = 90.; + int counter = 3; + while (bpm_iterator < bpm_end) { - notes.emplace_back(new ClassicNote(input_intervals, bpm_iterator, Type::UP, {x, 390.}, _graphics_manager)); + ClassicNote::ClassicNoteInitializer init; + ClassicNote::ClassicNoteInitializer::Element element, element2; + init.intervals = input_intervals; + init.perfect_offset = bpm_iterator; + + element.coordinates = {x, 390.}; + element.falling_curve_interpolation = {}; + element.keys = {sf::Keyboard::W, sf::Keyboard::Up}; + element.type = Type::UP; + + if (counter == 0) + { + counter = 3; + element2.coordinates = {x, 300.}; + element2.falling_curve_interpolation = {}; + element2.keys = {sf::Keyboard::A, sf::Keyboard::Left}; + element2.type = Type::LEFT; + + init.elements = {element, element2}; + } + else + init.elements = {element}; + + --counter; + + notes.emplace_back(new ClassicNote(std::move(init), _graphics_manager)); bpm_iterator += tempo_interval; x += 70; diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp index 6305bb5..459b85e 100644 --- a/src/classicgame/classicnote.cpp +++ b/src/classicgame/classicnote.cpp @@ -4,21 +4,25 @@ #include "classicflyinganimationscenario.h" #include "classicdyinganimationscenario.h" -ClassicNote::ClassicNote(const std::vector& intervals, microsec perfect_offset, - Type type, const Coordinates& coord, const std::unique_ptr &manager) : - Note(perfect_offset), - _coordinates(coord), - _evaluator(intervals, _perfect_offset), - _keys({sf::Keyboard::W, sf::Keyboard::Up}), +ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::unique_ptr &manager) : + Note(init.perfect_offset), + _evaluator(init.intervals, _perfect_offset), _graphics_manager(manager), - _type(type), _state(State::NONE) { - _animations[State::NONE] = nullptr; - _animations[State::FLYING] = std::make_shared(); - _animations[State::ACTIVE] = _animations[State::FLYING]; - _animations[State::DYING] = std::make_shared(); - _animations[State::DEAD] = nullptr; + _elements.resize(init.elements.size()); + 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; + + _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 @@ -28,9 +32,14 @@ bool ClassicNote::isActive() const void ClassicNote::putToGame(const microsec &music_offset) { - _graphics_manager->initGraphics(this); _state = State::FLYING; - _animations[_state]->launch(_sprite, music_offset, offset()); + + 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 @@ -47,68 +56,82 @@ bool ClassicNote::isExpired() const 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 (_animations[_state]->isDone()) - _state = State::DEAD; - break; - - case State::ACTIVE: - if (!_evaluator.isActive(music_offset)) + switch (_state) { - _state = State::DYING; - _animations[_state]->launch(_sprite, music_offset, offset()); + 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; } - break; - } - if (_animations[_state]) - _animations[_state]->update(music_offset); + for (auto& element : _elements) + if (element.animations[_state]) + element.animations[_state]->update(music_offset); } void ClassicNote::input(PlayerInput&& inputdata) { auto grade = ClassicNote::Grade::BAD; - if (std::find(_keys.begin(), _keys.end(), inputdata.event.key.code) != _keys.end()) + 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 = std::all_of(_elements.begin(), _elements.end(), + [](const auto& element) + { + return element.pressed; + }); + + if (all_pressed) grade = _evaluator.calculatePrecision(inputdata.timestamp); - _state = State::DYING; - _animations[_state]->launch(_sprite, inputdata.timestamp, offset()); + 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"; } -std::shared_ptr ClassicNote::sprite() const noexcept -{ - return _sprite; -} - -void ClassicNote::setSprite(const std::shared_ptr& sprite) noexcept -{ - _sprite = sprite; -} - -const Coordinates& ClassicNote::getCoordinates() const noexcept -{ - return _coordinates; -} - -Type ClassicNote::type() const noexcept -{ - return _type; -} - void ClassicNote::draw() const { - _graphics_manager->draw(this); + 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); + } } diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h index f1992e6..55332b2 100644 --- a/src/classicgame/classicnote.h +++ b/src/classicgame/classicnote.h @@ -32,9 +32,23 @@ public: DEAD }; - explicit ClassicNote(const std::vector& intervals, microsec perfect_offset, - Type type, const Coordinates& coord, - const std::unique_ptr& manager); + struct ClassicNoteInitializer + { + std::vector intervals; + microsec perfect_offset; + + struct Element + { + Type type; + Coordinates coordinates; + std::vector falling_curve_interpolation; + std::array keys; + }; + + std::vector elements; + }; + + explicit ClassicNote(ClassicNoteInitializer&& init, const std::unique_ptr& manager); virtual ~ClassicNote() = default; virtual bool isActive() const override; @@ -45,22 +59,16 @@ public: virtual bool isExpired() const override; virtual void draw() const override; - Type type() const noexcept; - - std::shared_ptr sprite() const noexcept; - void setSprite(const std::shared_ptr& sprite) noexcept; - const Coordinates& getCoordinates() const noexcept; - private: struct NoteElement { - std::shared_ptr _sprite; - std::array, 5> _animations; + std::shared_ptr sprite; + std::array, 5> animations; - const std::array _keys; - const Coordinates _coordinates; - const Type _type; + std::array keys; + Coordinates coordinates; + Type type; bool pressed = false; sf::Keyboard::Key pressed_as; diff --git a/src/classicgame/classicsprite.cpp b/src/classicgame/classicsprite.cpp index 4ae3386..8a010da 100644 --- a/src/classicgame/classicsprite.cpp +++ b/src/classicgame/classicsprite.cpp @@ -41,6 +41,11 @@ Coordinates ClassicSprite::coordinates() const return {_shape.getPosition().x, _shape.getPosition().y}; } +Coordinates ClassicSprite::trailCoordinates() const +{ + return {_trail.getPosition().x, _trail.getPosition().y}; +} + void ClassicSprite::update(float trail_x, float trail_y) noexcept { _trail.setPosition(trail_x, trail_y); diff --git a/src/classicgame/classicsprite.h b/src/classicgame/classicsprite.h index bc816da..919e6c2 100644 --- a/src/classicgame/classicsprite.h +++ b/src/classicgame/classicsprite.h @@ -14,6 +14,7 @@ public: void setCoordinates(const Coordinates &coordinates, float trail_x, float trail_y) noexcept; Coordinates coordinates() const; + Coordinates trailCoordinates() const; void update(float trail_x, float trail_y) noexcept; void update() noexcept;