diff --git a/include/sprite.h b/include/sprite.h index e88f238..d749dd0 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -4,4 +4,5 @@ class Sprite { public: virtual ~Sprite() = default; + virtual void reset() = 0; }; diff --git a/include/timelineviewmanager.h b/include/timelineviewmanager.h deleted file mode 100644 index 33d7b25..0000000 --- a/include/timelineviewmanager.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TIMELINEVIEWMANAGER_H -#define TIMELINEVIEWMANAGER_H - -class Note; - -class TimelineViewManager -{ -public: - virtual ~TimelineViewManager() = default; -}; - -#endif // TIMELINEVIEWMANAGER_H diff --git a/src/application.cpp b/src/application.cpp index 0a6a774..8b28b7e 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -44,10 +44,16 @@ void Application::input() sf::Event event; while (_game_window.pollEvent(event)) { - if (event.type == sf::Event::Closed) + switch(event.type) + { + case sf::Event::Closed: _game_window.close(); + break; - _game->input(event); + default: + _game->input(event); + break; + } } } diff --git a/src/classicgame/classicgame.cpp b/src/classicgame/classicgame.cpp index bcb77b9..e83594b 100644 --- a/src/classicgame/classicgame.cpp +++ b/src/classicgame/classicgame.cpp @@ -1,12 +1,11 @@ #include "classicgame.h" #include "classicinputtype.h" #include "classictimeline.h" -#include "classicviewmanager.h" +#include "spritecontainer.h" #include "classicnote.h" ClassicGame::ClassicGame() : - _timeline(std::make_unique()), - _view_manager(std::make_unique()) + _timeline(std::make_unique()) { _keys_to_buttons = { @@ -52,7 +51,7 @@ ClassicGame::~ClassicGame() void ClassicGame::run() { - _timeline->fetchVisibleNotes(_view_manager); + _timeline->fetchVisibleNotes(_sprite_container); _timeline->run(); } @@ -82,7 +81,7 @@ void ClassicGame::input(const sf::Event& event) auto note = _timeline->getActiveNote(); - if (!_timeline->isExpired(note) && (*note)->state() == ClassicNote::State::FLYING) + if (!_timeline->isExpired(note)) { (*note)->input(ClassicInputType(timestamp, new_action)); } @@ -101,7 +100,7 @@ Action ClassicGame::getActionKeyReleased(Button button) const void ClassicGame::update() { _timeline->update(); - _timeline->fetchVisibleNotes(_view_manager); + _timeline->fetchVisibleNotes(_sprite_container); } void ClassicGame::draw(sf::RenderWindow& window) const diff --git a/src/classicgame/classicgame.h b/src/classicgame/classicgame.h index 95fb8e9..94237fe 100644 --- a/src/classicgame/classicgame.h +++ b/src/classicgame/classicgame.h @@ -5,9 +5,9 @@ #include #include "game.h" #include "classicactions.h" +#include "spritecontainer.h" class ClassicTimeline; -class ClassicViewManager; class ClassicGame final : public Game { @@ -30,7 +30,7 @@ private: Action getActionKeyReleased(Button button) const; std::unique_ptr _timeline; - std::unique_ptr _view_manager; + SpriteContainer _sprite_container; }; #endif // CLASSICGAME_H diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp index 2c67292..00741e5 100644 --- a/src/classicgame/classicnote.cpp +++ b/src/classicgame/classicnote.cpp @@ -9,6 +9,7 @@ ClassicNote::ClassicNote(const std::vector& intervals, microsec perfec _coordinates(coord), _evaluator(intervals, _perfect_offset), _action(action), + _state(State::NONE), _appearance_time(0) {} @@ -26,19 +27,31 @@ static int getPt( int n1 , int n2 , float perc ) void ClassicNote::update(const microsec& music_offset) { - auto update_time = music_offset - _appearance_time; - auto i = update_time / _trail_path_percent / 100; + switch (_state) // States will be objects + { + case State::DYING: + _sprite->update(); + if (_sprite->isDead()) + setState(State::DEAD); + break; - int xa = getPt( 720./2. , 1280./2. , i ); - int ya = getPt( 0 , 720./2. , i ); - int xb = getPt( 1280./2. , _coordinates.x , i ); - int yb = getPt( 720./2. , _coordinates.y , i ); + case State::FLYING: + { + auto update_time = music_offset - _appearance_time; // This all will be inside ::update + auto i = update_time / _trail_path_percent / 100; // of an animation object - _sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i )); + int xa = getPt( 720./2. , 1280./2. , i ); + int ya = getPt( 0 , 720./2. , i ); + int xb = getPt( 1280./2. , _coordinates.x , i ); + int yb = getPt( 720./2. , _coordinates.y , i ); - if (_state == State::DYING) - if (_sprite->isDead()) - _state = State::DEAD; + _sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i )); + break; + } + + default: + break; + } } void ClassicNote::draw(sf::RenderTarget& target, sf::RenderStates states) const @@ -51,13 +64,12 @@ auto ClassicNote::input(ClassicInputType&& input_data) -> Grade auto grade = ClassicNote::Grade::BAD; if (input_data == _action) - { grade = _evaluator.calculatePrecision(input_data.timestamp()); - } + + setState(State::DYING); std::cout << "User input: " << static_cast(grade) << "\n"; - _state = State::DYING; - _sprite->showGrade(); + return grade; } @@ -73,6 +85,24 @@ auto ClassicNote::state() const -> State void ClassicNote::setState(State next_state) { + switch (next_state) // States will be objects + { + case State::DYING: + _sprite->pulse(); + break; + + case State::FLYING: + _sprite->setCoordinates(_coordinates.x, _coordinates.y, 720/2, 50); + break; + + case State::NONE: + _sprite->reset(); + break; + + default: + break; + } + _state = next_state; } @@ -91,7 +121,7 @@ void ClassicNote::setSprite(const std::shared_ptr& sprite) noexce { _sprite = sprite; if (_sprite) - _sprite->setCoordinates(_coordinates.x, _coordinates.y, 720/2, 50); + setState(State::FLYING); } const Coordinates& ClassicNote::getCoordinates() const noexcept diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h index d6caae3..1ff2e16 100644 --- a/src/classicgame/classicnote.h +++ b/src/classicgame/classicnote.h @@ -32,6 +32,8 @@ public: enum class State { + NONE, + FLYING, DYING, DEAD @@ -60,7 +62,7 @@ private: const Coordinates _coordinates; const PrecisionEvaluator _evaluator; const Action _action; - State _state = State::FLYING; + State _state; std::shared_ptr _sprite; microsec _appearance_time; diff --git a/src/classicgame/classicsprite.cpp b/src/classicgame/classicsprite.cpp index 97d09e1..8ad992d 100644 --- a/src/classicgame/classicsprite.cpp +++ b/src/classicgame/classicsprite.cpp @@ -16,6 +16,14 @@ void ClassicSprite::draw(sf::RenderTarget& target, sf::RenderStates states) cons target.draw(_grade_text, states); } +void ClassicSprite::reset() +{ + _shape.setPosition(0, 0); + _trail.setPosition(0, 0); + _grade_text.setPosition(0, 0); + _grade_text.setFillColor(sf::Color(255, 255, 255, 0)); +} + void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept { _shape.setPosition(x, y); @@ -26,12 +34,17 @@ void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_ void ClassicSprite::update(float trail_x, float trail_y) noexcept { _trail.setPosition(trail_x, trail_y); +} + +void ClassicSprite::update() noexcept +{ fade(); } -void ClassicSprite::showGrade() +void ClassicSprite::pulse() { _grade_text.setFillColor(sf::Color(255, 255, 255, 255)); + _shape.setFillColor(sf::Color(140, 140, 140)); } void ClassicSprite::fade() @@ -41,13 +54,24 @@ void ClassicSprite::fade() if (fill_color.a == 0) return; - const auto new_alpha = fill_color.a - 55; + auto new_alpha = fill_color.a - 55; fill_color.a = new_alpha < 0 ? 0 : new_alpha; _grade_text.setFillColor(fill_color); + + fill_color = _shape.getFillColor(); + + if (fill_color.a == 0) + return; + + new_alpha = fill_color.a - 55; + fill_color.a = new_alpha < 0 ? 0 : new_alpha; + + _shape.setFillColor(fill_color); } bool ClassicSprite::isDead() const { - return _grade_text.getFillColor().a == 0; + return _grade_text.getFillColor().a == 0 + || _shape.getFillColor().a == 0; } diff --git a/src/classicgame/classicsprite.h b/src/classicgame/classicsprite.h index 165e0b3..5f7bec1 100644 --- a/src/classicgame/classicsprite.h +++ b/src/classicgame/classicsprite.h @@ -9,10 +9,13 @@ class ClassicSprite : public Sprite, public sf::Drawable public: ClassicSprite(const sf::RectangleShape& shape, const sf::Font &font); virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; + virtual void reset() override; void setCoordinates(float x, float y, float trail_x, float trail_y) noexcept; void update(float trail_x, float trail_y) noexcept; - void showGrade(); + void update() noexcept; + + void pulse(); void fade(); bool isDead() const; diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp index ce1812e..ec6fe22 100644 --- a/src/classicgame/classictimeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -2,7 +2,8 @@ #include "classicactions.h" #include "classictimeline.h" #include "classicnote.h" -#include "classicviewmanager.h" +#include "spritecontainer.h" + #include ClassicTimeline::ClassicTimeline() @@ -44,6 +45,7 @@ ClassicTimeline::ClassicTimeline() x += 70; } + expire(_first_visible_note); expire(_last_visible_note); expire(_active_note); _top_note = _timeline.begin(); @@ -65,9 +67,6 @@ void ClassicTimeline::clear() delete note; _timeline.clear(); - expire(_top_note); - expire(_last_visible_note); - expire(_active_note); } void ClassicTimeline::update() @@ -79,8 +78,12 @@ void ClassicTimeline::update() void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) { - if (!isExpired(_active_note) - && ((!(*_active_note)->isActive(music_offset)) || (*_active_note)->state() == ClassicNote::State::DEAD)) + if (isExpired(_active_note)) + return; + + auto note = *_active_note; + + if (!note->isActive(music_offset)) { expire(_active_note); ++_top_note; @@ -89,16 +92,16 @@ void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset) { - if (isExpired(_active_note) && (*_top_note)->isActive(music_offset)) - { - std::cout << "New active note: " << music_offset << '\n'; + if (!isExpired(_active_note)) + return; + + auto top_note = *_top_note; + if (top_note->isActive(music_offset)) _active_note = _top_note; - } } ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept { - update(); return _active_note; } @@ -117,68 +120,74 @@ microsec ClassicTimeline::currentMusicOffset() const return _music.getPlayingOffset().asMicroseconds(); } -void ClassicTimeline::discardExpiredNotes(const std::unique_ptr &view_manager) -{ - if (_top_note == _timeline.begin()) - return; - - Iterator past_note = _top_note - 1; - std::shared_ptr sprite = (*past_note)->sprite(); - while (sprite) - { - auto state = (*past_note)->state(); - if (state == ClassicNote::State::DEAD || state == ClassicNote::State::FLYING) - view_manager->resetNoteSprite(*past_note); - if (past_note == _timeline.begin()) - return; - --past_note; - sprite = (*past_note)->sprite(); - } -} - bool ClassicTimeline::isVisiblyClose(const Iterator &iterator, const microsec &music_offset) const { return ((*iterator)->offset() - _visibility_offset) <= music_offset; } -void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr& view_manager) +void ClassicTimeline::fetchVisibleNotes(SpriteContainer& sprite_container) { const microsec music_offset = currentMusicOffset(); - discardExpiredNotes(view_manager); + initGraphicsForNewNotes(sprite_container, music_offset); + discardGraphicsForDeadNotes(sprite_container); +} +void ClassicTimeline::initGraphicsForNewNotes(SpriteContainer& sprite_container, const microsec &music_offset) +{ Iterator note_iterator = _top_note; while (isVisiblyClose(note_iterator, music_offset)) { - ClassicNote* note = *note_iterator; - if (!note->sprite()) - { - note->saveAppearanceTime(music_offset); - view_manager->initNoteSprite(note); - } + if (nothingToDraw()) + _first_visible_note = note_iterator; - if (note->state() == ClassicNote::State::DEAD) - view_manager->resetNoteSprite(note); + auto note = *note_iterator; + + if (note->sprite()) + continue; + + note->saveAppearanceTime(music_offset); - note->update(music_offset); - ++note_iterator; + const auto action_type = note->action(); + const auto sprite = sprite_container.getSprite(action_type); + note->setSprite(sprite); } _last_visible_note = note_iterator; } -void ClassicTimeline::drawVisibleNotes(sf::RenderWindow &window) const +void ClassicTimeline::discardGraphicsForDeadNotes(SpriteContainer &sprite_container) { - bool no_visible_notes = isExpired(_last_visible_note) - || _top_note > _last_visible_note; - - if (no_visible_notes) + if (nothingToDraw()) return; - Iterator note_to_draw = _top_note; - while (note_to_draw != (_last_visible_note)) + auto note_iterator = _first_visible_note; + while (note_iterator != _last_visible_note) { - if ((*note_to_draw)->sprite()) - window.draw(*(*note_to_draw)); - ++note_to_draw; + auto note = *note_iterator; + if (note->state() == ClassicNote::State::DEAD) + { + note->setState(ClassicNote::State::NONE); + const auto action_type = note->action(); + sprite_container.resetSprite(note->sprite(), action_type); + note->setSprite(nullptr); + ++_first_visible_note; + } } } + +bool ClassicTimeline::nothingToDraw() const noexcept +{ + return isExpired(_first_visible_note); +} + +void ClassicTimeline::drawVisibleNotes(sf::RenderWindow &window) const +{ + if (nothingToDraw()) + return; + + std::for_each(_first_visible_note, _last_visible_note, + [&window](const auto& note) + { + window.draw(*note); + }); +} diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h index 68cd7b0..40eb964 100644 --- a/src/classicgame/classictimeline.h +++ b/src/classicgame/classictimeline.h @@ -6,7 +6,7 @@ #include class ClassicNote; -class ClassicViewManager; +class SpriteContainer; class ClassicTimeline : public Timeline { @@ -20,7 +20,9 @@ public: virtual microsec currentMusicOffset() const override; virtual void drawVisibleNotes(sf::RenderWindow& window) const override; - void fetchVisibleNotes(const std::unique_ptr& view_manager); + void fetchVisibleNotes(SpriteContainer& sprite_container); + void initGraphicsForNewNotes(SpriteContainer& sprite_container, const microsec& music_offset); + void discardGraphicsForDeadNotes(SpriteContainer& sprite_container); using Iterator = std::vector::const_iterator; @@ -34,6 +36,7 @@ private: Iterator _top_note; Iterator _active_note; Iterator _last_visible_note; + Iterator _first_visible_note; microsec _visibility_offset; @@ -41,8 +44,8 @@ private: void checkCurrentActiveNote(const microsec &music_offset); void checkForNextActiveNote(const microsec &music_offset); - void discardExpiredNotes(const std::unique_ptr& view_manager); bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; + bool nothingToDraw() const noexcept; /* Difference between top and active note is that * top note is the note handling input right now diff --git a/src/classicgame/classicviewmanager.cpp b/src/classicgame/spritecontainer.cpp similarity index 67% rename from src/classicgame/classicviewmanager.cpp rename to src/classicgame/spritecontainer.cpp index d6cb552..900caef 100644 --- a/src/classicgame/classicviewmanager.cpp +++ b/src/classicgame/spritecontainer.cpp @@ -1,12 +1,12 @@ -#include "classicviewmanager.h" +#include "spritecontainer.h" #include "classicsprite.h" -#include "classicnote.h" + #include #include static constexpr std::size_t RESERVED_SIZE = 20; -ClassicViewManager::ClassicViewManager() +SpriteContainer::SpriteContainer() { for (auto kind_of_action : {Action::PRESS_UP, Action::PRESS_DOWN, Action::PRESS_LEFT, Action::PRESS_RIGHT}) @@ -14,10 +14,12 @@ ClassicViewManager::ClassicViewManager() reallocatePoll(kind_of_action); } + std::cout << "Sprite poll reallocated.\n"; + _font.loadFromFile("VeraMono.ttf"); } -void ClassicViewManager::reallocatePoll(Action kind_of_action) +void SpriteContainer::reallocatePoll(Action kind_of_action) { SpritePoll &poll = _sprite_dispatcher[kind_of_action]; for (std::size_t i = 0; i < RESERVED_SIZE; ++i) @@ -26,7 +28,7 @@ void ClassicViewManager::reallocatePoll(Action kind_of_action) } } -std::shared_ptr ClassicViewManager::createSprite(Action kind_of_action) const +std::shared_ptr SpriteContainer::createSprite(Action kind_of_action) const { sf::RectangleShape sprite; sprite.setSize({20.f, 20.f}); @@ -55,22 +57,22 @@ std::shared_ptr ClassicViewManager::createSprite(Action kind_of_a return std::make_shared(sprite, _font); } -void ClassicViewManager::initNoteSprite(ClassicNote* note) +std::shared_ptr SpriteContainer::getSprite(Action action) { - const auto action_type = note->action(); - SpritePoll& poll = _sprite_dispatcher.at(action_type); + SpritePoll& poll = _sprite_dispatcher.at(action); if (poll.empty()) - reallocatePoll(action_type); + reallocatePoll(action); - note->setSprite(poll.top()); + std::shared_ptr sprite = poll.top(); poll.pop(); std::cout << "Taking a sprite from poll.\n"; + + return sprite; } -void ClassicViewManager::resetNoteSprite(ClassicNote* note) +void SpriteContainer::resetSprite(const std::shared_ptr &sprite, Action action) { - _sprite_dispatcher[note->action()].push(note->sprite()); - note->setSprite(nullptr); + _sprite_dispatcher[action].push(sprite); std::cout << "Returning a sprite to poll.\n"; } diff --git a/src/classicgame/classicviewmanager.h b/src/classicgame/spritecontainer.h similarity index 56% rename from src/classicgame/classicviewmanager.h rename to src/classicgame/spritecontainer.h index b6e3c00..e491202 100644 --- a/src/classicgame/classicviewmanager.h +++ b/src/classicgame/spritecontainer.h @@ -1,24 +1,25 @@ -#ifndef CLASSICDIVAVIEWMANAGER_H -#define CLASSICDIVAVIEWMANAGER_H +#pragma once -#include "timelineviewmanager.h" #include "classicactions.h" #include #include -#include + #include class ClassicSprite; class ClassicNote; -class ClassicViewManager : public TimelineViewManager +/* Move Sprite initialization into factory + * and make this class template */ + +class SpriteContainer { public: - explicit ClassicViewManager(); + explicit SpriteContainer(); - void initNoteSprite(ClassicNote *note); - void resetNoteSprite(ClassicNote *note); + std::shared_ptr getSprite(Action action); + void resetSprite(const std::shared_ptr &sprite, Action action); private: void reallocatePoll(Action kind_of_action); @@ -28,5 +29,3 @@ private: std::map _sprite_dispatcher; sf::Font _font; }; - -#endif // CLASSICDIVAVIEWMANAGER_H