diff --git a/include/spritecontainer.h b/include/spritecontainer.h new file mode 100644 index 0000000..2e2141d --- /dev/null +++ b/include/spritecontainer.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include + +template::value>> +class SpriteContainer +{ +public: + explicit SpriteContainer(std::initializer_list&& types, + std::unique_ptr&& factory, + std::size_t reserve_size = 20) : + _sprite_factory(std::move(factory)), + _poll_reserve_size(reserve_size) + { + for (const Type& type : types) + reallocatePoll(type); + } + + inline std::shared_ptr getSprite(Type type) + { + SpritePoll& poll = _sprite_dispatcher.at(type); + + if (poll.empty()) + reallocatePoll(type); + + std::shared_ptr sprite = poll.top(); + poll.pop(); + + return sprite; + } + + inline void resetSprite(const std::shared_ptr &sprite, Type action) noexcept + { + _sprite_dispatcher[action].push(sprite); + } + + ~SpriteContainer(){} + +private: + inline void reallocatePoll(Type sprite_type) + { + SpritePoll &poll = _sprite_dispatcher[sprite_type]; + for (std::size_t i = 0; i < _poll_reserve_size; ++i) + { + poll.push(_sprite_factory->create(sprite_type)); + } + } + + using SpritePoll = std::stack>; + + std::map _sprite_dispatcher; + std::unique_ptr _sprite_factory; + + std::size_t _poll_reserve_size; +}; diff --git a/src/classicgame/classicactions.h b/src/classicgame/classicactions.h index 9591618..0a4a1dd 100644 --- a/src/classicgame/classicactions.h +++ b/src/classicgame/classicactions.h @@ -11,7 +11,9 @@ enum class Action PRESS_LEFT, RELEASE_LEFT, PRESS_SLIDER_RIGHT, RELEASE_SLIDER_RIGHT, - PRESS_SLIDER_LEFT, RELEASE_SLIDER_LEFT + PRESS_SLIDER_LEFT, RELEASE_SLIDER_LEFT, + + COUNT }; enum class Button diff --git a/src/classicgame/classicgame.cpp b/src/classicgame/classicgame.cpp index e83594b..47fcc78 100644 --- a/src/classicgame/classicgame.cpp +++ b/src/classicgame/classicgame.cpp @@ -1,11 +1,13 @@ #include "classicgame.h" #include "classicinputtype.h" #include "classictimeline.h" +#include "classicgraphicsmanager.h" #include "spritecontainer.h" #include "classicnote.h" ClassicGame::ClassicGame() : - _timeline(std::make_unique()) + _timeline(std::make_unique()), + _graphics_manager(std::make_unique()) { _keys_to_buttons = { @@ -51,7 +53,7 @@ ClassicGame::~ClassicGame() void ClassicGame::run() { - _timeline->fetchVisibleNotes(_sprite_container); + _timeline->fetchVisibleNotes(_graphics_manager); _timeline->run(); } @@ -100,7 +102,7 @@ Action ClassicGame::getActionKeyReleased(Button button) const void ClassicGame::update() { _timeline->update(); - _timeline->fetchVisibleNotes(_sprite_container); + _timeline->fetchVisibleNotes(_graphics_manager); } void ClassicGame::draw(sf::RenderWindow& window) const diff --git a/src/classicgame/classicgame.h b/src/classicgame/classicgame.h index 94237fe..a87311f 100644 --- a/src/classicgame/classicgame.h +++ b/src/classicgame/classicgame.h @@ -8,6 +8,8 @@ #include "spritecontainer.h" class ClassicTimeline; +class ClassicSprite; +class ClassicGraphicsManager; class ClassicGame final : public Game { @@ -30,7 +32,7 @@ private: Action getActionKeyReleased(Button button) const; std::unique_ptr _timeline; - SpriteContainer _sprite_container; + std::unique_ptr _graphics_manager; }; #endif // CLASSICGAME_H diff --git a/src/classicgame/classicgraphicsmanager.cpp b/src/classicgame/classicgraphicsmanager.cpp new file mode 100644 index 0000000..2831b33 --- /dev/null +++ b/src/classicgame/classicgraphicsmanager.cpp @@ -0,0 +1,19 @@ +#include "classicgraphicsmanager.h" +#include "classicnote.h" + +ClassicGraphicsManager::ClassicGraphicsManager() : + _sprite_container({Action::PRESS_UP, Action::PRESS_DOWN, + Action::PRESS_LEFT, Action::PRESS_RIGHT}, + std::make_unique("VeraMono.ttf")) +{} + +void ClassicGraphicsManager::initSprite(ClassicNote* note) +{ + const auto action_type = note->action(); + note->setSprite(_sprite_container.getSprite(action_type)); +} + +void ClassicGraphicsManager::resetSprite(ClassicNote* note) +{ + _sprite_container.resetSprite(note->sprite(), note->action()); +} diff --git a/src/classicgame/classicgraphicsmanager.h b/src/classicgame/classicgraphicsmanager.h new file mode 100644 index 0000000..0861b5a --- /dev/null +++ b/src/classicgame/classicgraphicsmanager.h @@ -0,0 +1,20 @@ +#pragma once + +#include "classicactions.h" +#include "spritecontainer.h" +#include "classicspritefactory.h" + +class ClassicSprite; +class ClassicNote; + +class ClassicGraphicsManager +{ +public: + explicit ClassicGraphicsManager(); + + void initSprite(ClassicNote* note); + void resetSprite(ClassicNote* note); + +private: + SpriteContainer _sprite_container; +}; diff --git a/src/classicgame/classicsprite.cpp b/src/classicgame/classicsprite.cpp index 8ad992d..092368e 100644 --- a/src/classicgame/classicsprite.cpp +++ b/src/classicgame/classicsprite.cpp @@ -2,6 +2,7 @@ #include ClassicSprite::ClassicSprite(const sf::RectangleShape& shape, const sf::Font& font) : + _prototype(shape), _shape(shape), _trail(shape), _font(font) @@ -22,6 +23,9 @@ void ClassicSprite::reset() _trail.setPosition(0, 0); _grade_text.setPosition(0, 0); _grade_text.setFillColor(sf::Color(255, 255, 255, 0)); + + _shape = _prototype; + _trail = _prototype; } void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept @@ -45,6 +49,8 @@ void ClassicSprite::pulse() { _grade_text.setFillColor(sf::Color(255, 255, 255, 255)); _shape.setFillColor(sf::Color(140, 140, 140)); + _trail.setPosition(0, 0); + _trail.setFillColor(sf::Color(0, 0, 0, 0)); } void ClassicSprite::fade() @@ -54,7 +60,7 @@ void ClassicSprite::fade() if (fill_color.a == 0) return; - auto new_alpha = fill_color.a - 55; + auto new_alpha = fill_color.a - 15; fill_color.a = new_alpha < 0 ? 0 : new_alpha; _grade_text.setFillColor(fill_color); @@ -64,7 +70,7 @@ void ClassicSprite::fade() if (fill_color.a == 0) return; - new_alpha = fill_color.a - 55; + new_alpha = fill_color.a - 15; fill_color.a = new_alpha < 0 ? 0 : new_alpha; _shape.setFillColor(fill_color); diff --git a/src/classicgame/classicsprite.h b/src/classicgame/classicsprite.h index 5f7bec1..4c13f7e 100644 --- a/src/classicgame/classicsprite.h +++ b/src/classicgame/classicsprite.h @@ -20,6 +20,8 @@ public: bool isDead() const; private: + sf::RectangleShape _prototype; + sf::RectangleShape _shape; sf::RectangleShape _trail; sf::Text _grade_text; diff --git a/src/classicgame/classicspritefactory.h b/src/classicgame/classicspritefactory.h new file mode 100644 index 0000000..53c4723 --- /dev/null +++ b/src/classicgame/classicspritefactory.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include "classicinputtype.h" +#include "classicsprite.h" + +class ClassicSpriteFactory +{ +public: + inline ClassicSpriteFactory(const std::string& font_filename) + { + _font.loadFromFile(font_filename); + } + + inline std::shared_ptr create(Action action) + { + sf::RectangleShape sprite; + sprite.setSize({20.f, 20.f}); + switch (action) + { + case Action::PRESS_UP: + sprite.setFillColor(sf::Color(255, 0, 0)); + break; + + case Action::PRESS_DOWN: + sprite.setFillColor(sf::Color(0, 255, 0)); + break; + + case Action::PRESS_LEFT: + sprite.setFillColor(sf::Color(0, 0, 255)); + break; + + case Action::PRESS_RIGHT: + sprite.setFillColor(sf::Color(255, 0, 255)); + break; + + default: // yellow + sprite.setFillColor(sf::Color(255, 239, 0)); + } + + return std::make_shared(sprite, _font); + } + +private: + sf::Font _font; +}; + diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp index ec6fe22..3331b1f 100644 --- a/src/classicgame/classictimeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -3,6 +3,7 @@ #include "classictimeline.h" #include "classicnote.h" #include "spritecontainer.h" +#include "classicgraphicsmanager.h" #include @@ -63,7 +64,7 @@ ClassicTimeline::~ClassicTimeline() void ClassicTimeline::clear() { - for (auto note : _timeline) + for (auto& note : _timeline) delete note; _timeline.clear(); @@ -74,23 +75,25 @@ void ClassicTimeline::update() const microsec& offset = currentMusicOffset(); checkCurrentActiveNote(offset); checkForNextActiveNote(offset); + updateVisibleSprites(offset); } -void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) +void ClassicTimeline::checkCurrentActiveNote(const microsec& music_offset) { if (isExpired(_active_note)) return; auto note = *_active_note; - if (!note->isActive(music_offset)) + if (note->state() != ClassicNote::State::FLYING || !note->isActive(music_offset)) { + note->setState(ClassicNote::State::DYING); expire(_active_note); ++_top_note; } } -void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset) +void ClassicTimeline::checkForNextActiveNote(const microsec& music_offset) { if (!isExpired(_active_note)) return; @@ -100,17 +103,29 @@ void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset) _active_note = _top_note; } +void ClassicTimeline::updateVisibleSprites(const microsec& music_offset) +{ + if (nothingToDraw()) + return; + + std::for_each(_first_visible_note, _last_visible_note, + [&music_offset](const auto& note) + { + note->update(music_offset); + }); +} + ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept { return _active_note; } -bool ClassicTimeline::isExpired(const Iterator &iterator) const +bool ClassicTimeline::isExpired(const Iterator& iterator) const { return iterator == _timeline.end(); } -void ClassicTimeline::expire(Iterator &iterator) +void ClassicTimeline::expire(Iterator& iterator) { iterator = _timeline.end(); } @@ -120,19 +135,19 @@ microsec ClassicTimeline::currentMusicOffset() const return _music.getPlayingOffset().asMicroseconds(); } -bool ClassicTimeline::isVisiblyClose(const Iterator &iterator, const microsec &music_offset) const +bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const { return ((*iterator)->offset() - _visibility_offset) <= music_offset; } -void ClassicTimeline::fetchVisibleNotes(SpriteContainer& sprite_container) +void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr& graphics_manager) { const microsec music_offset = currentMusicOffset(); - initGraphicsForNewNotes(sprite_container, music_offset); - discardGraphicsForDeadNotes(sprite_container); + initGraphicsForNewNotes(graphics_manager, music_offset); + discardGraphicsForDeadNotes(graphics_manager); } -void ClassicTimeline::initGraphicsForNewNotes(SpriteContainer& sprite_container, const microsec &music_offset) +void ClassicTimeline::initGraphicsForNewNotes(const std::unique_ptr& graphics_manager, const microsec &music_offset) { Iterator note_iterator = _top_note; while (isVisiblyClose(note_iterator, music_offset)) @@ -142,20 +157,19 @@ void ClassicTimeline::initGraphicsForNewNotes(SpriteContainer& sprite_container, auto note = *note_iterator; - if (note->sprite()) - continue; + if (!note->sprite()) + { + note->saveAppearanceTime(music_offset); + graphics_manager->initSprite(note); + } - note->saveAppearanceTime(music_offset); - - const auto action_type = note->action(); - const auto sprite = sprite_container.getSprite(action_type); - note->setSprite(sprite); + ++note_iterator; } _last_visible_note = note_iterator; } -void ClassicTimeline::discardGraphicsForDeadNotes(SpriteContainer &sprite_container) +void ClassicTimeline::discardGraphicsForDeadNotes(const std::unique_ptr& graphics_manager) { if (nothingToDraw()) return; @@ -167,11 +181,12 @@ void ClassicTimeline::discardGraphicsForDeadNotes(SpriteContainer &sprite_contai 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); + graphics_manager->resetSprite(note); + ++_first_visible_note; } + + ++note_iterator; } } @@ -191,3 +206,4 @@ void ClassicTimeline::drawVisibleNotes(sf::RenderWindow &window) const window.draw(*note); }); } + diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h index 40eb964..b703edc 100644 --- a/src/classicgame/classictimeline.h +++ b/src/classicgame/classictimeline.h @@ -5,8 +5,8 @@ #include "timeline.h" #include +class ClassicGraphicsManager; class ClassicNote; -class SpriteContainer; class ClassicTimeline : public Timeline { @@ -20,9 +20,9 @@ public: virtual microsec currentMusicOffset() const override; virtual void drawVisibleNotes(sf::RenderWindow& window) const override; - void fetchVisibleNotes(SpriteContainer& sprite_container); - void initGraphicsForNewNotes(SpriteContainer& sprite_container, const microsec& music_offset); - void discardGraphicsForDeadNotes(SpriteContainer& sprite_container); + void fetchVisibleNotes(const std::unique_ptr& graphics_manager); + void initGraphicsForNewNotes(const std::unique_ptr& graphics_manager, const microsec& music_offset); + void discardGraphicsForDeadNotes(const std::unique_ptr& graphics_manager); using Iterator = std::vector::const_iterator; @@ -42,8 +42,9 @@ private: sf::Music _music; - void checkCurrentActiveNote(const microsec &music_offset); - void checkForNextActiveNote(const microsec &music_offset); + void updateVisibleSprites(const microsec& music_offset); + void checkCurrentActiveNote(const microsec& music_offset); + void checkForNextActiveNote(const microsec& music_offset); bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; bool nothingToDraw() const noexcept; diff --git a/src/classicgame/spritecontainer.cpp b/src/classicgame/spritecontainer.cpp deleted file mode 100644 index 900caef..0000000 --- a/src/classicgame/spritecontainer.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "spritecontainer.h" -#include "classicsprite.h" - -#include -#include - -static constexpr std::size_t RESERVED_SIZE = 20; - -SpriteContainer::SpriteContainer() -{ - for (auto kind_of_action : {Action::PRESS_UP, Action::PRESS_DOWN, - Action::PRESS_LEFT, Action::PRESS_RIGHT}) - { - reallocatePoll(kind_of_action); - } - - std::cout << "Sprite poll reallocated.\n"; - - _font.loadFromFile("VeraMono.ttf"); -} - -void SpriteContainer::reallocatePoll(Action kind_of_action) -{ - SpritePoll &poll = _sprite_dispatcher[kind_of_action]; - for (std::size_t i = 0; i < RESERVED_SIZE; ++i) - { - poll.push(createSprite(kind_of_action)); - } -} - -std::shared_ptr SpriteContainer::createSprite(Action kind_of_action) const -{ - sf::RectangleShape sprite; - sprite.setSize({20.f, 20.f}); - switch (kind_of_action) - { - case Action::PRESS_UP: - sprite.setFillColor(sf::Color(255, 0, 0)); - break; - - case Action::PRESS_DOWN: - sprite.setFillColor(sf::Color(0, 255, 0)); - break; - - case Action::PRESS_LEFT: - sprite.setFillColor(sf::Color(0, 0, 255)); - break; - - case Action::PRESS_RIGHT: - sprite.setFillColor(sf::Color(255, 0, 255)); - break; - - default: // yellow - sprite.setFillColor(sf::Color(255, 239, 0)); - } - - return std::make_shared(sprite, _font); -} - -std::shared_ptr SpriteContainer::getSprite(Action action) -{ - SpritePoll& poll = _sprite_dispatcher.at(action); - - if (poll.empty()) - reallocatePoll(action); - - std::shared_ptr sprite = poll.top(); - poll.pop(); - std::cout << "Taking a sprite from poll.\n"; - - return sprite; -} - -void SpriteContainer::resetSprite(const std::shared_ptr &sprite, Action action) -{ - _sprite_dispatcher[action].push(sprite); - std::cout << "Returning a sprite to poll.\n"; -} diff --git a/src/classicgame/spritecontainer.h b/src/classicgame/spritecontainer.h deleted file mode 100644 index e491202..0000000 --- a/src/classicgame/spritecontainer.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "classicactions.h" - -#include -#include - -#include - -class ClassicSprite; -class ClassicNote; - -/* Move Sprite initialization into factory - * and make this class template */ - -class SpriteContainer -{ -public: - explicit SpriteContainer(); - - std::shared_ptr getSprite(Action action); - void resetSprite(const std::shared_ptr &sprite, Action action); - -private: - void reallocatePoll(Action kind_of_action); - std::shared_ptr createSprite(Action kind_of_action) const; - - using SpritePoll = std::stack>; - std::map _sprite_dispatcher; - sf::Font _font; -};