Implement complex graphics logic for notes
This commit is contained in:
parent
ff07b628ac
commit
8b4d362000
|
@ -12,5 +12,4 @@ public:
|
||||||
|
|
||||||
virtual void input(PlayerInput&& inputdata) = 0;
|
virtual void input(PlayerInput&& inputdata) = 0;
|
||||||
virtual void update(UpdateData&& updatedata) = 0;
|
virtual void update(UpdateData&& updatedata) = 0;
|
||||||
virtual void draw() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
virtual bool isActive(const microsec& offset) const = 0;
|
virtual bool isActive(const microsec& offset) const = 0;
|
||||||
virtual void update(const microsec& music_offset) = 0;
|
virtual void update(const microsec& music_offset) = 0;
|
||||||
|
|
||||||
virtual void putToGame(const microsec& offset) = 0;
|
virtual void putToGame() = 0;
|
||||||
virtual bool isInGame() const = 0;
|
virtual bool isInGame() const = 0;
|
||||||
virtual bool shouldRemove() const = 0;
|
virtual bool shouldRemove() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ bool MockClassicNote::shouldRemove() const
|
||||||
|| _state == State::NONE;
|
|| _state == State::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MockClassicNote::putToGame(const microsec &music_offset)
|
void MockClassicNote::putToGame()
|
||||||
{
|
{
|
||||||
_state = State::FLYING; (void)music_offset;
|
_state = State::FLYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MockClassicNote::update(const microsec &music_offset)
|
void MockClassicNote::update(const microsec &music_offset)
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
virtual bool isInGame() const override final;
|
virtual bool isInGame() const override final;
|
||||||
virtual bool shouldRemove() const override final;
|
virtual bool shouldRemove() const override final;
|
||||||
|
|
||||||
virtual void putToGame(const microsec &music_offset) override final;
|
virtual void putToGame() override final;
|
||||||
virtual void update(const microsec &music_offset) override final;
|
virtual void update(const microsec &music_offset) override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
#include "classicarrownote.h"
|
#include "classicarrownote.h"
|
||||||
#include "game/classicgraphicsmanager.h"
|
#include "game/classicgraphicsmanager.h"
|
||||||
|
#include "graphics/classicanimationscenario.h"
|
||||||
#include "holdmanager.h"
|
#include "holdmanager.h"
|
||||||
|
|
||||||
// Replace with interface by dependency injection
|
|
||||||
#include "graphics/classicflyinganimationscenario.h"
|
|
||||||
#include "graphics/classicdyinganimationscenario.h"
|
|
||||||
//
|
|
||||||
|
|
||||||
ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) :
|
ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) :
|
||||||
ClassicNote(std::move(init.initializer)),
|
ClassicNote(std::move(init.initializer)),
|
||||||
_is_hold(init.hold)
|
_is_hold(init.hold)
|
||||||
|
@ -21,9 +17,9 @@ ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicArrowNote::putToGame(const microsec &music_offset)
|
void ClassicArrowNote::putToGame()
|
||||||
{
|
{
|
||||||
_state = State::FLYING; (void)music_offset;
|
_state = State::FLYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicArrowNote::input(PlayerInput&& inputdata)
|
void ClassicArrowNote::input(PlayerInput&& inputdata)
|
||||||
|
@ -93,6 +89,16 @@ void ClassicArrowNote::update(const microsec& music_offset)
|
||||||
element.animations[_state]->update(music_offset);
|
element.animations[_state]->update(music_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassicArrowNote::draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const
|
||||||
|
{
|
||||||
|
manager->draw(_elements, target, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicArrowNote::setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range)
|
||||||
|
{
|
||||||
|
manager->setGraphics(_elements, std::move(range));
|
||||||
|
}
|
||||||
|
|
||||||
bool ClassicArrowNote::allElementsPressed() const
|
bool ClassicArrowNote::allElementsPressed() const
|
||||||
{
|
{
|
||||||
return std::all_of(_elements.begin(), _elements.end(),
|
return std::all_of(_elements.begin(), _elements.end(),
|
||||||
|
|
|
@ -9,16 +9,17 @@ public:
|
||||||
explicit ClassicArrowNote(ArrowNoteInitializer&& init);
|
explicit ClassicArrowNote(ArrowNoteInitializer&& init);
|
||||||
virtual ~ClassicArrowNote() = default;
|
virtual ~ClassicArrowNote() = default;
|
||||||
|
|
||||||
virtual void putToGame(const microsec& music_offset) override;
|
virtual void putToGame() override;
|
||||||
virtual void update(const microsec &music_offset) override;
|
virtual void update(const microsec &music_offset) override;
|
||||||
virtual void input(PlayerInput&& inputdata) override;
|
virtual void input(PlayerInput&& inputdata) override;
|
||||||
|
|
||||||
|
virtual void draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||||
|
virtual void setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) override;
|
||||||
|
|
||||||
bool allElementsPressed() const;
|
bool allElementsPressed() const;
|
||||||
bool isPressedAs(sf::Keyboard::Key key) const;
|
bool isPressedAs(sf::Keyboard::Key key) const;
|
||||||
inline bool isHold() const;
|
inline bool isHold() const;
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct ArrowElement
|
struct ArrowElement
|
||||||
{
|
{
|
||||||
std::shared_ptr<ClassicSprite> sprite;
|
std::shared_ptr<ClassicSprite> sprite;
|
||||||
|
@ -36,6 +37,9 @@ private:
|
||||||
// Note Element represents this idea.
|
// Note Element represents this idea.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
std::vector<ArrowElement> _elements;
|
std::vector<ArrowElement> _elements;
|
||||||
bool _is_hold;
|
bool _is_hold;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ArrowElements = std::vector<ClassicArrowNote::ArrowElement>;
|
||||||
|
|
|
@ -94,8 +94,10 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
void ClassicGame::update(UpdateData&& updatedata)
|
void ClassicGame::update(UpdateData&& updatedata)
|
||||||
{
|
{
|
||||||
_timeline.update(updatedata.timestamp);
|
_timeline.update(updatedata.timestamp);
|
||||||
|
_graphics_manager->update(updatedata.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGame::draw() const
|
void ClassicGame::draw() const
|
||||||
{
|
{
|
||||||
|
_graphics_manager->draw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "classicgraphicsmanager.h"
|
#include "classicgraphicsmanager.h"
|
||||||
#include "graphics/classicsprite.h"
|
#include "graphics/classicsprite.h"
|
||||||
|
|
||||||
|
#include "graphics/classicflyinganimationscenario.h"
|
||||||
|
#include "graphics/classicdyinganimationscenario.h"
|
||||||
|
|
||||||
ClassicGraphicsManager::ClassicGraphicsManager(Timeline<ClassicNote> &timeline, const microsec& visibility_offset) :
|
ClassicGraphicsManager::ClassicGraphicsManager(Timeline<ClassicNote> &timeline, const microsec& visibility_offset) :
|
||||||
_sprite_container({Type::UP, Type::DOWN,
|
_sprite_container({Type::UP, Type::DOWN,
|
||||||
Type::LEFT, Type::RIGHT},
|
Type::LEFT, Type::RIGHT},
|
||||||
|
@ -17,19 +20,85 @@ void ClassicGraphicsManager::draw(sf::RenderTarget& target, sf::RenderStates sta
|
||||||
if (nothingToDraw())
|
if (nothingToDraw())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::for_each(_first, _last,
|
for (auto it = _first; it != _last; ++it)
|
||||||
[&target, &states](const auto& note)
|
{
|
||||||
{
|
(*it)->draw(this, target, states);
|
||||||
target.draw(*note->sprite(), states);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClassicSprite> ClassicGraphicsManager::getSprite(Type type)
|
void ClassicGraphicsManager::draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const
|
||||||
{
|
{
|
||||||
return _sprite_container.getSprite(type);
|
for (std::size_t i = 0; i < elements.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& sprite = elements[i].sprite;
|
||||||
|
|
||||||
|
if (i >= 1)
|
||||||
|
{
|
||||||
|
const auto& neighbor_sprite = elements[i - 1].sprite;
|
||||||
|
|
||||||
|
const auto c1 = neighbor_sprite->trailCoordinates();
|
||||||
|
const auto c2 = sprite->trailCoordinates();
|
||||||
|
|
||||||
|
target.draw(makeLine(c1, c2));
|
||||||
|
}
|
||||||
|
|
||||||
|
target.draw(*sprite, states);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::VertexArray ClassicGraphicsManager::makeLine(const Coordinates& c1, const Coordinates& c2) const
|
||||||
|
{
|
||||||
|
sf::VertexArray line(sf::LinesStrip, 2);
|
||||||
|
line[0].color = sf::Color::Yellow;
|
||||||
|
line[0].position = {c1.x + 10, c1.y};
|
||||||
|
line[1].color = sf::Color::Blue;
|
||||||
|
line[1].position = {c2.x + 10, c2.y};
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicGraphicsManager::setGraphics(std::vector<ClassicArrowNote::ArrowElement>& elements, TimeRange &&range)
|
||||||
|
{
|
||||||
|
for (auto& element : elements)
|
||||||
|
{
|
||||||
|
element.sprite = _sprite_container.getSprite(element.type);
|
||||||
|
element.sprite->setCoordinates(element.coordinates);
|
||||||
|
element.sprite->setTrailCoordinates(Coordinates( 0.f, 9.f ));
|
||||||
|
|
||||||
|
element.animations[ClassicArrowNote::State::NONE] = nullptr;
|
||||||
|
element.animations[ClassicArrowNote::State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
|
||||||
|
element.animations[ClassicArrowNote::State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
|
||||||
|
element.animations[ClassicArrowNote::State::DEAD] = nullptr;
|
||||||
|
|
||||||
|
element.animations[ClassicArrowNote::State::FLYING]->launch(element.sprite, range.begin, range.end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGraphicsManager::update(const microsec &offset)
|
void ClassicGraphicsManager::update(const microsec &offset)
|
||||||
|
{
|
||||||
|
fetchLastNote(offset);
|
||||||
|
fetchFirstNote(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicGraphicsManager::fetchFirstNote(const microsec& offset)
|
||||||
|
{
|
||||||
|
(void)offset; // ????
|
||||||
|
|
||||||
|
if (nothingToDraw())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Iterator note_iterator = _first;
|
||||||
|
while (note_iterator != _last)
|
||||||
|
{
|
||||||
|
auto note = *note_iterator;
|
||||||
|
if (note->shouldRemove())
|
||||||
|
++_first;
|
||||||
|
|
||||||
|
++note_iterator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicGraphicsManager::fetchLastNote(const microsec& offset)
|
||||||
{
|
{
|
||||||
Iterator note_iterator = _timeline->getTopNote();
|
Iterator note_iterator = _timeline->getTopNote();
|
||||||
while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset))
|
while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset))
|
||||||
|
@ -40,7 +109,10 @@ void ClassicGraphicsManager::update(const microsec &offset)
|
||||||
auto note = *note_iterator;
|
auto note = *note_iterator;
|
||||||
|
|
||||||
if (!note->isInGame())
|
if (!note->isInGame())
|
||||||
note->putToGame(offset);
|
{
|
||||||
|
note->putToGame();
|
||||||
|
note->setGraphics(this, TimeRange{offset, note->offset()});
|
||||||
|
}
|
||||||
|
|
||||||
++note_iterator;
|
++note_iterator;
|
||||||
}
|
}
|
||||||
|
@ -56,5 +128,5 @@ bool ClassicGraphicsManager::nothingToDraw() const noexcept
|
||||||
|
|
||||||
bool ClassicGraphicsManager::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept
|
bool ClassicGraphicsManager::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept
|
||||||
{
|
{
|
||||||
return ((iterator)->offset() - _visibility_offset) <= music_offset;
|
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "spritecontainer.h"
|
#include "spritecontainer.h"
|
||||||
#include "classicmode/classicactions.h"
|
#include "classicmode/classicactions.h"
|
||||||
#include "graphics/classicspritefactory.h"
|
#include "graphics/classicspritefactory.h"
|
||||||
#include "classicnote.h"
|
#include "classicarrownote.h"
|
||||||
#include "core/timeline.h"
|
#include "core/timeline.h"
|
||||||
|
|
||||||
#include <SFML/Graphics/RenderTarget.hpp>
|
#include <SFML/Graphics/RenderTarget.hpp>
|
||||||
|
@ -16,8 +16,12 @@ public:
|
||||||
explicit ClassicGraphicsManager(Timeline<ClassicNote>& timeline, const microsec& visibility_offset);
|
explicit ClassicGraphicsManager(Timeline<ClassicNote>& timeline, const microsec& visibility_offset);
|
||||||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||||
|
|
||||||
std::shared_ptr<ClassicSprite> getSprite(Type type);
|
void draw(const std::vector<ClassicArrowNote::ArrowElement>& elements, sf::RenderTarget& target, sf::RenderStates states) const;
|
||||||
|
void setGraphics(std::vector<ClassicArrowNote::ArrowElement> &elements, TimeRange&& range);
|
||||||
|
|
||||||
void update(const microsec& offset);
|
void update(const microsec& offset);
|
||||||
|
void fetchFirstNote(const microsec& offset);
|
||||||
|
void fetchLastNote(const microsec& offset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Iterator = Timeline<ClassicNote>::Iterator;
|
using Iterator = Timeline<ClassicNote>::Iterator;
|
||||||
|
@ -32,4 +36,5 @@ private:
|
||||||
|
|
||||||
inline bool nothingToDraw() const noexcept;
|
inline bool nothingToDraw() const noexcept;
|
||||||
inline bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept;
|
inline bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept;
|
||||||
|
inline sf::VertexArray makeLine(const Coordinates& c1, const Coordinates& c2) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "classicnote.h"
|
#include "classicnote.h"
|
||||||
#include "graphics/classicsprite.h"
|
#include "graphics/classicsprite.h"
|
||||||
#include "graphics/classicgraphicsmanager.h"
|
#include "game/classicgraphicsmanager.h"
|
||||||
|
|
||||||
// Replace with interface by dependency injection
|
// Replace with interface by dependency injection
|
||||||
#include "graphics/classicflyinganimationscenario.h"
|
#include "graphics/classicflyinganimationscenario.h"
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
class ClassicSprite;
|
class ClassicSprite;
|
||||||
class ClassicAnimationScenario;
|
class ClassicAnimationScenario;
|
||||||
|
class ClassicGraphicsManager;
|
||||||
|
|
||||||
|
namespace sf { class RenderTarget; class RenderStates; }
|
||||||
|
|
||||||
class ClassicNote : public Note
|
class ClassicNote : public Note
|
||||||
{
|
{
|
||||||
|
@ -35,11 +38,16 @@ public:
|
||||||
virtual bool isInGame() const override final;
|
virtual bool isInGame() const override final;
|
||||||
virtual bool shouldRemove() const override final;
|
virtual bool shouldRemove() const override final;
|
||||||
|
|
||||||
virtual void putToGame(const microsec &music_offset) override = 0;
|
virtual void putToGame() override = 0;
|
||||||
virtual void update(const microsec &music_offset) override = 0;
|
virtual void update(const microsec &music_offset) override = 0;
|
||||||
|
|
||||||
virtual void input(PlayerInput&& inputdata) = 0;
|
virtual void input(PlayerInput&& inputdata) = 0;
|
||||||
|
|
||||||
|
// encapsulate
|
||||||
|
virtual void draw(const ClassicGraphicsManager * const manager, sf::RenderTarget& target, sf::RenderStates states) const = 0;
|
||||||
|
virtual void setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) = 0;
|
||||||
|
//
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const PrecisionEvaluator<Grade> _evaluator;
|
const PrecisionEvaluator<Grade> _evaluator;
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ Application::Application() :
|
||||||
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
|
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
|
||||||
|
|
||||||
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks), _font_holder);
|
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks), _font_holder);
|
||||||
const auto game_state = std::make_shared<GameState>(_game_window, classic::initGame(_game_window), GameState::Callbacks());
|
const auto game_state = std::make_shared<GameState>(_game_window, classic::initGame(), GameState::Callbacks());
|
||||||
const auto editor = std::make_shared<EditorState>(_game_window, classic::initEditor(_game_window), std::move(editor_callbacks), _font_holder);
|
const auto editor = std::make_shared<EditorState>(_game_window, classic::initEditor(), std::move(editor_callbacks), _font_holder);
|
||||||
|
|
||||||
_states[GUIState::Tag::MAIN_MENU] = main_menu;
|
_states[GUIState::Tag::MAIN_MENU] = main_menu;
|
||||||
_states[GUIState::Tag::GAME] = game_state;
|
_states[GUIState::Tag::GAME] = game_state;
|
||||||
|
|
|
@ -2,6 +2,20 @@
|
||||||
|
|
||||||
using microsec = long long;
|
using microsec = long long;
|
||||||
|
|
||||||
|
struct TimeRange
|
||||||
|
{
|
||||||
|
const microsec begin = 0;
|
||||||
|
const microsec end = 0;
|
||||||
|
|
||||||
|
constexpr inline explicit TimeRange() noexcept :
|
||||||
|
begin(0), end(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr inline explicit TimeRange(microsec x, microsec y) noexcept :
|
||||||
|
begin(x), end(y)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
struct Coordinates
|
struct Coordinates
|
||||||
{
|
{
|
||||||
float x;
|
float x;
|
||||||
|
|
Loading…
Reference in New Issue