forked from NaiJi/project-kyoku
Implement generic SpriteContainer
This commit is contained in:
parent
106697f6af
commit
cbe0fbb673
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
template<typename Type, class SpriteFactory, class Sprite,
|
||||
typename = std::enable_if_t<std::is_enum<Type>::value>>
|
||||
class SpriteContainer
|
||||
{
|
||||
public:
|
||||
explicit SpriteContainer(std::initializer_list<Type>&& types,
|
||||
std::unique_ptr<SpriteFactory>&& 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<Sprite> getSprite(Type type)
|
||||
{
|
||||
SpritePoll& poll = _sprite_dispatcher.at(type);
|
||||
|
||||
if (poll.empty())
|
||||
reallocatePoll(type);
|
||||
|
||||
std::shared_ptr<Sprite> sprite = poll.top();
|
||||
poll.pop();
|
||||
|
||||
return sprite;
|
||||
}
|
||||
|
||||
inline void resetSprite(const std::shared_ptr<Sprite> &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::shared_ptr<Sprite>>;
|
||||
|
||||
std::map<Type, SpritePoll> _sprite_dispatcher;
|
||||
std::unique_ptr<SpriteFactory> _sprite_factory;
|
||||
|
||||
std::size_t _poll_reserve_size;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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<ClassicTimeline>())
|
||||
_timeline(std::make_unique<ClassicTimeline>()),
|
||||
_graphics_manager(std::make_unique<ClassicGraphicsManager>())
|
||||
{
|
||||
_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
|
||||
|
|
|
@ -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<ClassicTimeline> _timeline;
|
||||
SpriteContainer _sprite_container;
|
||||
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||
};
|
||||
|
||||
#endif // CLASSICGAME_H
|
||||
|
|
|
@ -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<ClassicSpriteFactory>("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());
|
||||
}
|
|
@ -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<Action, ClassicSpriteFactory, ClassicSprite> _sprite_container;
|
||||
};
|
|
@ -2,6 +2,7 @@
|
|||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -20,6 +20,8 @@ public:
|
|||
bool isDead() const;
|
||||
|
||||
private:
|
||||
sf::RectangleShape _prototype;
|
||||
|
||||
sf::RectangleShape _shape;
|
||||
sf::RectangleShape _trail;
|
||||
sf::Text _grade_text;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "classicinputtype.h"
|
||||
#include "classicsprite.h"
|
||||
|
||||
class ClassicSpriteFactory
|
||||
{
|
||||
public:
|
||||
inline ClassicSpriteFactory(const std::string& font_filename)
|
||||
{
|
||||
_font.loadFromFile(font_filename);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<ClassicSprite> 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<ClassicSprite>(sprite, _font);
|
||||
}
|
||||
|
||||
private:
|
||||
sf::Font _font;
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "classictimeline.h"
|
||||
#include "classicnote.h"
|
||||
#include "spritecontainer.h"
|
||||
#include "classicgraphicsmanager.h"
|
||||
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
|
||||
|
@ -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<ClassicGraphicsManager>& 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<ClassicGraphicsManager>& 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);
|
||||
}
|
||||
|
||||
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<ClassicGraphicsManager>& 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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "timeline.h"
|
||||
#include <SFML/Audio/Music.hpp>
|
||||
|
||||
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<ClassicGraphicsManager>& graphics_manager);
|
||||
void initGraphicsForNewNotes(const std::unique_ptr<ClassicGraphicsManager>& graphics_manager, const microsec& music_offset);
|
||||
void discardGraphicsForDeadNotes(const std::unique_ptr<ClassicGraphicsManager>& graphics_manager);
|
||||
|
||||
using Iterator = std::vector<ClassicNote*>::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;
|
||||
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
#include "spritecontainer.h"
|
||||
#include "classicsprite.h"
|
||||
|
||||
#include <SFML/Graphics/RectangleShape.hpp>
|
||||
#include <iostream>
|
||||
|
||||
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<ClassicSprite> 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<ClassicSprite>(sprite, _font);
|
||||
}
|
||||
|
||||
std::shared_ptr<ClassicSprite> SpriteContainer::getSprite(Action action)
|
||||
{
|
||||
SpritePoll& poll = _sprite_dispatcher.at(action);
|
||||
|
||||
if (poll.empty())
|
||||
reallocatePoll(action);
|
||||
|
||||
std::shared_ptr<ClassicSprite> sprite = poll.top();
|
||||
poll.pop();
|
||||
std::cout << "Taking a sprite from poll.\n";
|
||||
|
||||
return sprite;
|
||||
}
|
||||
|
||||
void SpriteContainer::resetSprite(const std::shared_ptr<ClassicSprite> &sprite, Action action)
|
||||
{
|
||||
_sprite_dispatcher[action].push(sprite);
|
||||
std::cout << "Returning a sprite to poll.\n";
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "classicactions.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
|
||||
class ClassicSprite;
|
||||
class ClassicNote;
|
||||
|
||||
/* Move Sprite initialization into factory
|
||||
* and make this class template */
|
||||
|
||||
class SpriteContainer
|
||||
{
|
||||
public:
|
||||
explicit SpriteContainer();
|
||||
|
||||
std::shared_ptr<ClassicSprite> getSprite(Action action);
|
||||
void resetSprite(const std::shared_ptr<ClassicSprite> &sprite, Action action);
|
||||
|
||||
private:
|
||||
void reallocatePoll(Action kind_of_action);
|
||||
std::shared_ptr<ClassicSprite> createSprite(Action kind_of_action) const;
|
||||
|
||||
using SpritePoll = std::stack<std::shared_ptr<ClassicSprite>>;
|
||||
std::map<Action, SpritePoll> _sprite_dispatcher;
|
||||
sf::Font _font;
|
||||
};
|
Loading…
Reference in New Issue