Implement selection for editor notes

This commit is contained in:
NaiJi ✨ 2022-02-06 04:33:09 +03:00
parent c576686752
commit 4ec11560f1
39 changed files with 588 additions and 429 deletions

View File

@ -16,10 +16,6 @@ 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() = 0;
virtual bool isInGame() const = 0;
virtual bool shouldRemove() const = 0;
virtual void input(kku::GameEvent&& input) = 0; virtual void input(kku::GameEvent&& input) = 0;
inline const microsec& getPerfectOffset() const noexcept inline const microsec& getPerfectOffset() const noexcept

View File

@ -18,6 +18,7 @@ public:
virtual void move(const kku::Vector2<float>& delta) = 0; virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void setColor(const Color& color) = 0; virtual void setColor(const Color& color) = 0;
virtual kku::Color getColor() const = 0;
virtual bool contains(const kku::Point& position) const = 0; virtual bool contains(const kku::Point& position) const = 0;
virtual void display() = 0; virtual void display() = 0;

View File

@ -1,9 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <stack> #include <stack>
#include <map> #include <map>
namespace kku namespace kku
{ {
@ -48,7 +46,7 @@ private:
SpritePoll &poll = _sprite_dispatcher[sprite_type]; SpritePoll &poll = _sprite_dispatcher[sprite_type];
for (std::size_t i = 0; i < _poll_reserve_size; ++i) for (std::size_t i = 0; i < _poll_reserve_size; ++i)
{ {
poll.push(_sprite_factory->create(sprite_type)); poll.push(_sprite_factory->createSprite(sprite_type));
} }
} }

View File

@ -7,8 +7,6 @@
#include "../../include/application/state.h" // HOW? WHY DOESN'T "application/state.h" LINK ON BY ITSELF #include "../../include/application/state.h" // HOW? WHY DOESN'T "application/state.h" LINK ON BY ITSELF
#include "core/corefactory.h" #include "core/corefactory.h"
class ClassicFactory;
class Application class Application
{ {
public: public:
@ -22,7 +20,6 @@ public:
protected: protected:
std::shared_ptr<kku::CoreFactory> _core_factory; std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<ClassicFactory> _game_factory;
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states; std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
std::vector<std::shared_ptr<GUIState>> _state_stack; std::vector<std::shared_ptr<GUIState>> _state_stack;

View File

@ -10,7 +10,7 @@
bool Application::init() bool Application::init()
{ {
if (!_game_factory || !_core_factory) if (!_core_factory)
return false; return false;
MainMenu::Callbacks callbacks = MainMenu::Callbacks callbacks =
@ -22,8 +22,8 @@ bool Application::init()
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }}; EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(_core_factory, std::move(callbacks)); const auto main_menu = std::make_shared<MainMenu>(_core_factory, std::move(callbacks));
const auto game_state = std::make_shared<GameState>(_core_factory, _game_factory->getGame(), GameState::Callbacks()); const auto game_state = std::make_shared<GameState>(_core_factory, classic::getGame(_core_factory), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(_core_factory, _game_factory->getEditor(), std::move(editor_callbacks)); const auto editor = std::make_shared<EditorState>(_core_factory, classic::getEditor(_core_factory), std::move(editor_callbacks));
_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;

View File

@ -1,6 +1,5 @@
#include "applicationsfml.h" #include "applicationsfml.h"
#include "sfml/corefactorysfml.h" #include "sfml/corefactorysfml.h"
#include "sfml/classicmode/classicfactorysfml.h"
#include "sfml/application/inputconvertersfml.h" #include "sfml/application/inputconvertersfml.h"
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
@ -16,7 +15,6 @@ ApplicationSFML::ApplicationSFML(sf::RenderWindow * const render_window) :
_render_window->setVerticalSyncEnabled(true); _render_window->setVerticalSyncEnabled(true);
_core_factory = std::make_shared<CoreFactorySFML>(_render_window); _core_factory = std::make_shared<CoreFactorySFML>(_render_window);
_game_factory = std::make_shared<ClassicFactorySFML>(_render_window);
} }
void ApplicationSFML::display() void ApplicationSFML::display()

View File

@ -1,17 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderWindow.hpp>
#include <memory>
#include "shared/classicmode/classicfactory.h"
class ClassicFactorySFML : public ClassicFactory
{
public:
explicit ClassicFactorySFML(sf::RenderTarget * const render_target);
virtual std::unique_ptr<kku::Game> getGame() const override;
virtual std::unique_ptr<kku::Editor> getEditor() const override;
private:
sf::RenderTarget * const _render_target;
};

View File

@ -1,66 +0,0 @@
#include "classicspritesfml.h"
ClassicSpriteSFML::ClassicSpriteSFML(sf::RenderTarget * const render_target,
const sf::RectangleShape& shape) :
_prototype(shape),
_shape(shape),
_trail(shape),
_render_target(render_target)
{}
void ClassicSpriteSFML::reset()
{
_shape.setPosition(0, 0);
_trail.setPosition(0, 0);
_shape = _prototype;
_trail = _prototype;
}
void ClassicSpriteSFML::setPosition(const kku::Point& position)
{
_shape.setPosition(position.x, position.y);
}
void ClassicSpriteSFML::setTrailPosition(const kku::Point &position)
{
_trail.setPosition(position.x, position.y);
}
kku::Point ClassicSpriteSFML::getPosition() const
{
return kku::Point{ _shape.getPosition().x, _shape.getPosition().y };
}
kku::Point ClassicSpriteSFML::getTrailPosition() const
{
return kku::Point{ _trail.getPosition().x, _trail.getPosition().y };
}
void ClassicSpriteSFML::setColor(const kku::Color& color)
{
_shape.setFillColor(sf::Color{ color.red, color.green, color.blue, color.alpha });
}
void ClassicSpriteSFML::setTrailColor(const kku::Color& color)
{
_trail.setFillColor(sf::Color{ color.red, color.green, color.blue, color.alpha });
}
kku::Color ClassicSpriteSFML::getColor() const
{
const auto color = _shape.getFillColor();
return kku::Color{ color.r, color.g, color.b, color.a };
}
kku::Color ClassicSpriteSFML::getTrailColor() const
{
const auto color = _trail.getFillColor();
return kku::Color{ color.r, color.g, color.b, color.a };
}
void ClassicSpriteSFML::display() const
{
_render_target->draw(_shape);
_render_target->draw(_trail);
}

View File

@ -1,34 +0,0 @@
#pragma once
#include "graphics/classicsprite.h"
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
class ClassicSpriteSFML : public ClassicSprite
{
public:
explicit ClassicSpriteSFML(sf::RenderTarget * const render_target,
const sf::RectangleShape& shape);
virtual void reset() override;
virtual void display() const override;
virtual void setPosition(const kku::Point &position) override;
virtual void setTrailPosition(const kku::Point &position) override;
virtual kku::Point getPosition() const override;
virtual kku::Point getTrailPosition() const override;
virtual void setColor(const kku::Color& color) override;
virtual void setTrailColor(const kku::Color& color) override;
virtual kku::Color getColor() const override;
virtual kku::Color getTrailColor() const override;
private:
sf::RectangleShape _prototype;
sf::RectangleShape _shape;
sf::RectangleShape _trail;
sf::RenderTarget * const _render_target;
};

View File

@ -1,35 +0,0 @@
#include "spritefactorysfml.h"
#include "classicspritesfml.h"
ClassicSpriteFactorySFML::ClassicSpriteFactorySFML(sf::RenderTarget * const render_target) :
_render_target(render_target)
{}
std::shared_ptr<ClassicSprite> ClassicSpriteFactorySFML::create(Type type) const
{
sf::RectangleShape sprite;
sprite.setSize({20.f, 20.f});
switch (type)
{
case Type::UP:
sprite.setFillColor(sf::Color(255, 0, 0));
break;
case Type::DOWN:
sprite.setFillColor(sf::Color(0, 255, 0));
break;
case Type::LEFT:
sprite.setFillColor(sf::Color(0, 0, 255));
break;
case Type::RIGHT:
sprite.setFillColor(sf::Color(255, 0, 255));
break;
default: // yellow
sprite.setFillColor(sf::Color(255, 239, 0));
}
return std::make_shared<ClassicSpriteSFML>(_render_target, sprite);
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "graphics/classicspritefactory.h"
#include <SFML/Graphics/RenderTarget.hpp>
class ClassicSpriteFactorySFML : public ClassicSpriteFactory
{
public:
explicit ClassicSpriteFactorySFML(sf::RenderTarget * const render_target);
virtual std::shared_ptr<ClassicSprite> create(Type type) const override;
private:
sf::RenderTarget * const _render_target;
};

View File

@ -40,6 +40,12 @@ void RectangleSFML::setColor(const kku::Color& color)
color.blue, color.alpha}); color.blue, color.alpha});
} }
kku::Color RectangleSFML::getColor() const
{
const auto color = _rectangle.getFillColor();
return kku::Color{color.r, color.g, color.b, color.a};
}
bool RectangleSFML::contains(const kku::Point& position) const bool RectangleSFML::contains(const kku::Point& position) const
{ {
return _rectangle.getGlobalBounds().contains(position.x, position.y); return _rectangle.getGlobalBounds().contains(position.x, position.y);

View File

@ -18,6 +18,7 @@ public:
virtual void move(const kku::Vector2<float>& delta) override; virtual void move(const kku::Vector2<float>& delta) override;
virtual void setColor(const kku::Color& color) override; virtual void setColor(const kku::Color& color) override;
virtual kku::Color getColor() const override;
virtual bool contains(const kku::Point& position) const override; virtual bool contains(const kku::Point& position) const override;
virtual void display() override; virtual void display() override;

View File

@ -2,7 +2,7 @@
int main() int main()
{ {
sf::RenderWindow window(sf::VideoMode{1280, 720}, "Test", sf::Style::Fullscreen); sf::RenderWindow window(sf::VideoMode{1280, 720}, "Test", sf::Style::Default);
ApplicationSFML app(&window); ApplicationSFML app(&window);
if (app.init()) if (app.init())
app.run(); app.run();

View File

@ -9,7 +9,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
file(GLOB_RECURSE SOURCES "editor/*.h" "editor/*.cpp" file(GLOB_RECURSE SOURCES "editor/*.h" "editor/*.cpp"
"graphics/*.h" "graphics/*.cpp" "graphics/*.h" "graphics/*.cpp"
"game/*.h" "game/*.cpp" "game/*.h" "game/*.cpp"
"shared/*.h" "shared/*.h" "*.cpp"
"include/*.h") "include/*.h")
add_library(classicmode STATIC ${SOURCES} ${HEADERS}) add_library(classicmode STATIC ${SOURCES} ${HEADERS})

View File

@ -1,34 +1,31 @@
#include "classicfactorysfml.h" #include "classicmode/classicfactory.h"
#include "spritefactorysfml.h"
#include "graphics/classicscenegraphicsmanager.h" #include "graphics/classicscenegraphicsmanager.h"
#include "core/timeline.h" #include "graphics/classicgraphicsfactory.h"
#include "core/timeline.h"
#include "game/classicgame.h" #include "game/classicgame.h"
#include "editor/classiceditor.h" #include "editor/classiceditor.h"
ClassicFactorySFML::ClassicFactorySFML(sf::RenderTarget * const render_target) :
_render_target(render_target)
{}
std::unique_ptr<kku::Game> ClassicFactorySFML::getGame() const std::unique_ptr<kku::Game> classic::getGame(const std::shared_ptr<kku::CoreFactory>& core_factory)
{ {
// read offset from beatmap metadata // read offset from beatmap metadata
const kku::microsec visibility_offset = 1648648; const kku::microsec visibility_offset = 1648648;
const auto factory = std::make_shared<ClassicSpriteFactorySFML>(_render_target); const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory);
const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>(); const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>();
const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager>(timeline, factory, visibility_offset); const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager>(timeline, factory, visibility_offset);
return std::make_unique<ClassicGame>(timeline, graphics_manager); return std::make_unique<ClassicGame>(timeline, graphics_manager);
} }
std::unique_ptr<kku::Editor> ClassicFactorySFML::getEditor() const std::unique_ptr<kku::Editor> classic::getEditor(const std::shared_ptr<kku::CoreFactory>& core_factory)
{ {
// read offset from beatmap metadata // read offset from beatmap metadata
const kku::microsec visibility_offset = 1648648; const kku::microsec visibility_offset = 1648648;
const auto factory = std::make_shared<ClassicSpriteFactorySFML>(_render_target); const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory);
const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>(); const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>();
const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager>(timeline, factory, visibility_offset); const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager>(timeline, factory, visibility_offset);

View File

@ -1,6 +1,8 @@
#include "classiceditor.h" #include "classiceditor.h"
#include "game/classicarrownote.h" #include "game/classicmocknote.h"
#include "graphics/classicgraphicsmanager.h"
#include "game/classicmapcreator.h"
// Replace with interface by dependency injection // Replace with interface by dependency injection
#include "graphics/animations/classicflyinganimationscenario.h" #include "graphics/animations/classicflyinganimationscenario.h"
@ -15,7 +17,65 @@ ClassicEditor::ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicNote>>&
_current_time(0), _current_time(0),
_scroll_step(500000) _scroll_step(500000)
{ {
_timeline->setNotes({}); kku::microsec starting_beat_offset = 402162;
int amount_of_beats = 209;
kku::microsec interval = 1412162;
kku::microsec tempo_interval = interval / 4;
kku::microsec note_input_offset = 412162 / 2;
//microsec note_input_offset_fast = 412162 / 6;
kku::microsec bpm_iterator = starting_beat_offset;
kku::microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
std::vector<kku::microsec> input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset};
std::set<ClassicNote*, kku::NotePtrComparator> notes;
input_intervals.shrink_to_fit();
bpm_iterator += tempo_interval;
float x = 90.;
int counter = 3;
while (bpm_iterator < bpm_end)
{
ArrowNoteInitializer init;
ArrowElementInitializer element;
init.initializer.intervals = input_intervals;
init.initializer.perfect_offset = bpm_iterator;
init.hold = false;
element.element.position = kku::Point(x, 390.f);
element.element.falling_curve_interpolation = {};
element.keys = {kku::SystemEvent::Key::Code::W,
kku::SystemEvent::Key::Code::Up};
element.element.type = Type::UP;
if (counter == 0)
{
init.hold = true;
element.keys = {kku::SystemEvent::Key::Code::D,
kku::SystemEvent::Key::Code::Right};
element.element.type = Type::RIGHT;
}
--counter;
init.elements = {element};
notes.insert(new ClassicMockNote(std::move(init)));
bpm_iterator += tempo_interval;
x += 70;
if (x >= 1200)
x = 90.;
}
_timeline->setNotes(notes);
} }
kku::microsec ClassicEditor::adjustOffset(kku::microsec offset) const noexcept kku::microsec ClassicEditor::adjustOffset(kku::microsec offset) const noexcept
@ -59,8 +119,10 @@ void ClassicEditor::input(kku::GameEvent&& input)
init.elements = { element }; init.elements = { element };
_timeline->insertNote(new ClassicArrowNote(std::move(init))); _timeline->insertNote(new ClassicMockNote(std::move(init)));
} }
else
_graphics_manager->input(std::move(input));
break; break;
} }
@ -70,10 +132,12 @@ void ClassicEditor::input(kku::GameEvent&& input)
void ClassicEditor::update(kku::UpdateData&& updatedata) void ClassicEditor::update(kku::UpdateData&& updatedata)
{ {
_timeline->update(updatedata.timestamp); _timeline->update(updatedata.timestamp);
_graphics_manager->update(updatedata.timestamp);
} }
void ClassicEditor::display() const void ClassicEditor::display() const
{ {
_graphics_manager->display();
} }
void ClassicEditor::recalculate(const kku::microsec& timestamp) void ClassicEditor::recalculate(const kku::microsec& timestamp)

View File

@ -5,6 +5,7 @@
ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) : ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) :
ClassicNote(std::move(init.initializer)), ClassicNote(std::move(init.initializer)),
_evaluator(init.initializer.intervals, _perfect_offset),
_is_hold(init.hold) _is_hold(init.hold)
{ {
_elements.resize(init.elements.size()); _elements.resize(init.elements.size());
@ -17,14 +18,15 @@ ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init) :
} }
} }
void ClassicArrowNote::putToGame() bool ClassicArrowNote::isActive(const kku::microsec& offset) const
{ {
_state = State::FLYING; return _evaluator.isActive(offset)
&& _state != State::DYING;
} }
void ClassicArrowNote::input(kku::GameEvent&& input) void ClassicArrowNote::input(kku::GameEvent&& input)
{ {
auto grade = ClassicNote::Grade::BAD; auto grade = Grade::BAD;
bool input_valid = std::any_of(_elements.begin(), _elements.end(), bool input_valid = std::any_of(_elements.begin(), _elements.end(),
[input=input](auto& element) [input=input](auto& element)

View File

@ -8,10 +8,17 @@
class ClassicArrowNote : public ClassicNote class ClassicArrowNote : public ClassicNote
{ {
public: public:
enum class Grade
{
PERFECT,
GOOD,
BAD
};
explicit ClassicArrowNote(ArrowNoteInitializer&& init); explicit ClassicArrowNote(ArrowNoteInitializer&& init);
virtual ~ClassicArrowNote() = default; virtual ~ClassicArrowNote() = default;
virtual void putToGame() override; virtual bool isActive(const kku::microsec& offset) const override;
virtual void update(const kku::microsec &music_offset) override; virtual void update(const kku::microsec &music_offset) override;
virtual void input(kku::GameEvent&& input) override; virtual void input(kku::GameEvent&& input) override;
@ -23,6 +30,8 @@ public:
inline bool isHold() const; inline bool isHold() const;
private: private:
const kku::PrecisionEvaluator<Grade> _evaluator;
std::vector<ArrowElement> _elements; std::vector<ArrowElement> _elements;
bool _is_hold; bool _is_hold;
}; };

View File

@ -0,0 +1,85 @@
#include "classicmocknote.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "graphics/animations/classicanimationscenario.h"
#include "holdmanager.h"
ClassicMockNote::ClassicMockNote(ArrowNoteInitializer&& init) :
ClassicNote(std::move(init.initializer))
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
bool ClassicMockNote::isActive(const kku::microsec &offset) const
{
(void)offset;
return _state != State::DEAD
&& _state != State::NONE;
}
void ClassicMockNote::input(kku::GameEvent&& input)
{
switch (input.event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
const auto position = std::get<kku::SystemEvent::Mouse>(input.event.data).position;
for (auto& element : _elements)
{
if (element.sprite->getRectangle()->contains(position))
{
element.selected = !element.selected;
element.selection->toggle(element.selected);
}
}
break;
}
}
}
void ClassicMockNote::update(const kku::microsec& music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (music_offset >= getPerfectOffset())
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, music_offset, getPerfectOffset());
}
break;
case State::DYING:
if (_elements[0].animations[_state]->isDone())
_state = State::DEAD;
break;
}
for (auto& element : _elements)
if (element.animations[_state])
element.animations[_state]->update(music_offset);
}
void ClassicMockNote::display(const ClassicGraphicsManager * const manager) const
{
manager->display(_elements);
}
void ClassicMockNote::setGraphics(ClassicGraphicsManager * const manager, kku::TimeRange&& range)
{
manager->setGraphics(_elements, std::move(range));
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "arrowelement.h"
#include "classicnote.h"
#include "mockelement.h"
#include "initializers/arrownoteinitializer.h"
class ClassicMockNote : public ClassicNote
{
public:
explicit ClassicMockNote(ArrowNoteInitializer&& init);
virtual ~ClassicMockNote() = default;
virtual bool isActive(const kku::microsec& offset) const override;
virtual void update(const kku::microsec &music_offset) override;
virtual void input(kku::GameEvent&& input) override;
virtual void display(const ClassicGraphicsManager * const manager) const override;
virtual void setGraphics(ClassicGraphicsManager * const manager, kku::TimeRange&& range) override;
private:
std::vector<MockElement> _elements;
bool _is_selected;
};
using MockElements = std::vector<MockElement>;

View File

@ -2,24 +2,16 @@
ClassicNote::ClassicNote(NoteInitializer &&init) : ClassicNote::ClassicNote(NoteInitializer &&init) :
Note(init.perfect_offset), Note(init.perfect_offset),
_evaluator(init.intervals, _perfect_offset),
_state(State::NONE), _state(State::NONE),
_context(init.context) _context(init.context)
{} {}
bool ClassicNote::isActive(const kku::microsec& offset) const void ClassicNote::setState(ClassicNote::State state) noexcept
{ {
return _evaluator.isActive(offset) _state = state;
&& _state != State::DYING;
} }
bool ClassicNote::isInGame() const auto ClassicNote::getState() const noexcept -> State
{ {
return _state == State::FLYING return _state;
|| _state == State::DYING;
}
bool ClassicNote::shouldRemove() const
{
return _state == State::DEAD;
} }

View File

@ -5,21 +5,12 @@
#include "classicmode/noteinitializer.h" #include "classicmode/noteinitializer.h"
#include "classicmode/context.h" #include "classicmode/context.h"
class ClassicSprite;
class ClassicAnimationScenario;
class ClassicGraphicsManager; class ClassicGraphicsManager;
class ClassicNote : public kku::Note class ClassicNote : public kku::Note
{ {
public: public:
enum class Grade
{
PERFECT,
GOOD,
BAD
};
enum State enum State
{ {
NONE, NONE,
@ -32,11 +23,7 @@ public:
explicit ClassicNote(NoteInitializer&& init); explicit ClassicNote(NoteInitializer&& init);
virtual ~ClassicNote() override = default; virtual ~ClassicNote() override = default;
virtual bool isActive(const kku::microsec& offset) const override final; virtual bool isActive(const kku::microsec& offset) const override = 0;
virtual bool isInGame() const override final;
virtual bool shouldRemove() const override final;
virtual void putToGame() override = 0;
virtual void update(const kku::microsec &music_offset) override = 0; virtual void update(const kku::microsec &music_offset) override = 0;
virtual void input(kku::GameEvent&& input) override = 0; virtual void input(kku::GameEvent&& input) override = 0;
@ -44,9 +31,10 @@ public:
virtual void display(const ClassicGraphicsManager * const manager) const = 0; virtual void display(const ClassicGraphicsManager * const manager) const = 0;
virtual void setGraphics(ClassicGraphicsManager * const manager, kku::TimeRange&& range) = 0; virtual void setGraphics(ClassicGraphicsManager * const manager, kku::TimeRange&& range) = 0;
protected: void setState(State state) noexcept;
const kku::PrecisionEvaluator<Grade> _evaluator; State getState() const noexcept;
protected:
State _state; State _state;
const Context *_context; const Context *_context;
}; };

View File

@ -0,0 +1,32 @@
#pragma once
#include "classicmode/classicactions.h"
#include "core/gameevent.h"
#include "core/point.h"
#include <memory>
#include <vector>
#include <array>
class ClassicAnimationScenario;
class ClassicSprite;
class ClassicSelection;
struct MockElement
{
std::shared_ptr<ClassicSprite> sprite;
std::shared_ptr<ClassicSelection> selection;
bool selected;
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
kku::Point position;
std::vector<kku::Point> falling_curve_interpolation;
Type type = Type::NONE;
// Each note may consist of several buttons.
// For example, ↑ → or ↓ → ←
// Note Element represents this idea.
};

View File

@ -0,0 +1,56 @@
#include "classicgraphicsfactory.h"
ClassicGraphicsFactory::ClassicGraphicsFactory(const std::shared_ptr<kku::CoreFactory>& core_factory) :
_core_factory(core_factory)
{}
auto ClassicGraphicsFactory::generate(Type type) const -> SpriteData
{
auto shape = _core_factory->getRectangle();
auto trail = _core_factory->getRectangle();
shape->setRect(kku::Area<float>{0.f, 0.f, 20.f, 20.f});
trail->setRect(kku::Area<float>{0.f, 0.f, 20.f, 20.f});
kku::Color color;
switch (type)
{
case Type::UP:
color = kku::Color{255, 0, 0, 255};
break;
case Type::DOWN:
color = kku::Color{0, 255, 0, 255};
break;
case Type::LEFT:
color = kku::Color{0, 0, 255, 255};
break;
case Type::RIGHT:
color = kku::Color{255, 0, 255, 255};
break;
default: // yellow
color = kku::Color{255, 239, 0, 255};
}
shape->setColor(color);
trail->setColor(color);
return SpriteData{shape, trail, color};
}
std::shared_ptr<ClassicSprite> ClassicGraphicsFactory::createSprite(Type type) const
{
const auto data = generate(type);
return std::make_shared<ClassicSprite>(ClassicSprite::Init{data.shape, data.trail, data.color});
}
std::shared_ptr<ClassicSelection> ClassicGraphicsFactory::createSelection() const
{
const auto shape = _core_factory->getRectangle();
return std::make_shared<ClassicSelection>(ClassicSelection::Init{shape, kku::Color{51, 153, 255, 0}});
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <memory>
#include "classicmode/classicactions.h"
#include "graphics/classicsprite.h"
#include "graphics/classicselection.h"
#include "core/rectangle.h"
#include "core/corefactory.h"
class ClassicGraphicsFactory
{
public:
explicit ClassicGraphicsFactory(const std::shared_ptr<kku::CoreFactory>& core_factory);
std::shared_ptr<ClassicSprite> createSprite(Type type) const;
std::shared_ptr<ClassicSelection> createSelection() const;
private:
const std::shared_ptr<kku::CoreFactory> _core_factory;
struct SpriteData
{
std::shared_ptr<kku::Rectangle> shape;
std::shared_ptr<kku::Rectangle> trail;
kku::Color color;
};
SpriteData generate(Type type) const;
};

View File

@ -7,6 +7,7 @@
#include <vector> #include <vector>
struct ArrowElement; struct ArrowElement;
struct MockElement;
class ClassicGraphicsManager : public std::enable_shared_from_this<ClassicGraphicsManager> class ClassicGraphicsManager : public std::enable_shared_from_this<ClassicGraphicsManager>
{ {
@ -16,9 +17,14 @@ public:
_visibility_offset(visibility_offset) _visibility_offset(visibility_offset)
{} {}
virtual void input(kku::GameEvent&& input) = 0;
virtual void display(const std::vector<ArrowElement>& elements) const = 0; virtual void display(const std::vector<ArrowElement>& elements) const = 0;
virtual void setGraphics(std::vector<ArrowElement>& elements, kku::TimeRange&& range) = 0; virtual void setGraphics(std::vector<ArrowElement>& elements, kku::TimeRange&& range) = 0;
virtual void display(const std::vector<MockElement>& elements) const = 0;
virtual void setGraphics(std::vector<MockElement>& elements, kku::TimeRange&& range) = 0;
virtual void display() const = 0; virtual void display() const = 0;
virtual void update(const kku::microsec& offset) = 0; virtual void update(const kku::microsec& offset) = 0;

View File

@ -1,24 +1,36 @@
#include "classicscenegraphicsmanager.h" #include "classicscenegraphicsmanager.h"
#include "graphics/classicsprite.h"
#include "game/mockelement.h"
#include "game/arrowelement.h" #include "game/arrowelement.h"
#include "graphics/animations/classicflyinganimationscenario.h" #include "graphics/animations/classicflyinganimationscenario.h"
#include "graphics/animations/classicdyinganimationscenario.h" #include "graphics/animations/classicdyinganimationscenario.h"
ClassicSceneGraphicsManager::ClassicSceneGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline, ClassicSceneGraphicsManager::ClassicSceneGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicSpriteFactory>& factory, const std::shared_ptr<ClassicGraphicsFactory>& factory,
const kku::microsec& visibility_offset) : const kku::microsec& visibility_offset) :
ClassicGraphicsManager(visibility_offset), ClassicGraphicsManager(visibility_offset),
_sprite_container({Type::UP, Type::DOWN, _sprite_container({Type::UP, Type::DOWN,
Type::LEFT, Type::RIGHT}, Type::LEFT, Type::RIGHT},
factory), factory),
_factory(factory),
_timeline(timeline) _timeline(timeline)
{ {
_timeline->expire(_first); _timeline->expire(_first);
_timeline->expire(_last); _timeline->expire(_last);
} }
void ClassicSceneGraphicsManager::input(kku::GameEvent&& input)
{
if (nothingToDraw())
return;
for (auto it = _first; it != _last; ++it)
{
(*it)->input(std::move(input));
}
}
void ClassicSceneGraphicsManager::display() const void ClassicSceneGraphicsManager::display() const
{ {
if (nothingToDraw()) if (nothingToDraw())
@ -75,6 +87,47 @@ void ClassicSceneGraphicsManager::setGraphics(std::vector<ArrowElement>& element
} }
} }
void ClassicSceneGraphicsManager::display(const std::vector<MockElement>& elements) const
{
for (std::size_t i = 0; i < elements.size(); ++i)
{
const auto& sprite = elements[i].sprite;
const auto& selection = elements[i].selection;
if (i >= 1)
{
//const auto& neighbor_sprite = elements[i - 1].sprite;
//const auto c1 = neighbor_sprite->trailPosition();
//const auto c2 = sprite->trailPosition();
//_render_target->draw(makeLine(c1, c2));
}
sprite->display();
selection->display();
}
}
void ClassicSceneGraphicsManager::setGraphics(std::vector<MockElement>& elements, kku::TimeRange &&range)
{
for (auto& element : elements)
{
element.sprite = _sprite_container.getSprite(element.type);
element.sprite->setPosition(element.position);
element.sprite->setTrailPosition(kku::Point( 0.f, 9.f ));
element.selection = _factory->createSelection();
element.selection->adjustTo(element.sprite);
element.animations[ClassicNote::State::NONE] = nullptr;
element.animations[ClassicNote::State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
element.animations[ClassicNote::State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
element.animations[ClassicNote::State::DEAD] = nullptr;
element.animations[ClassicNote::State::FLYING]->launch(element.sprite, range.begin, range.end);
}
}
/*sf::VertexArray ClassicSceneGraphicsSFML::makeLine(const kku::Point& c1, const kku::Point& c2) const /*sf::VertexArray ClassicSceneGraphicsSFML::makeLine(const kku::Point& c1, const kku::Point& c2) const
{ {
sf::VertexArray line(sf::LinesStrip, 2); sf::VertexArray line(sf::LinesStrip, 2);
@ -103,7 +156,7 @@ void ClassicSceneGraphicsManager::fetchFirstNote(const kku::microsec& offset)
while (note_iterator != _last) while (note_iterator != _last)
{ {
auto note = *note_iterator; auto note = *note_iterator;
if (note->shouldRemove()) if (note->getState() == ClassicNote::State::DEAD)
++_first; ++_first;
++note_iterator; ++note_iterator;
@ -120,9 +173,10 @@ void ClassicSceneGraphicsManager::fetchLastNote(const kku::microsec& offset)
auto note = *note_iterator; auto note = *note_iterator;
if (!note->isInGame()) if (note->getState() != ClassicNote::State::FLYING
&& note->getState() != ClassicNote::State::DYING)
{ {
note->putToGame(); note->setState(ClassicNote::State::FLYING);
note->setGraphics(this, kku::TimeRange{offset, note->getPerfectOffset()}); note->setGraphics(this, kku::TimeRange{offset, note->getPerfectOffset()});
} }

View File

@ -2,7 +2,7 @@
#include "game/classicnote.h" #include "game/classicnote.h"
#include "graphics/classicgraphicsmanager.h" #include "graphics/classicgraphicsmanager.h"
#include "graphics/classicspritefactory.h" #include "graphics/classicgraphicsfactory.h"
#include "core/timeline.h" #include "core/timeline.h"
#include "core/spritecontainer.h" #include "core/spritecontainer.h"
@ -12,17 +12,23 @@ class ClassicSceneGraphicsManager : public ClassicGraphicsManager
{ {
public: public:
explicit ClassicSceneGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline, explicit ClassicSceneGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicSpriteFactory>& factory, const std::shared_ptr<ClassicGraphicsFactory>& factory,
const kku::microsec& visibility_offset); const kku::microsec& visibility_offset);
virtual void input(kku::GameEvent&& input) override;
virtual void display() const override; virtual void display() const override;
virtual void update(const kku::microsec& offset) override; virtual void update(const kku::microsec& offset) override;
virtual void display(const std::vector<ArrowElement>& elements) const override; virtual void display(const std::vector<ArrowElement>& elements) const override;
virtual void setGraphics(std::vector<ArrowElement>& elements, kku::TimeRange&& range) override; virtual void setGraphics(std::vector<ArrowElement>& elements, kku::TimeRange&& range) override;
virtual void display(const std::vector<MockElement>& elements) const override;
virtual void setGraphics(std::vector<MockElement>& elements, kku::TimeRange&& range) override;
protected: protected:
kku::SpriteContainer<Type, ClassicSpriteFactory, ClassicSprite> _sprite_container; kku::SpriteContainer<Type, ClassicGraphicsFactory, ClassicSprite> _sprite_container;
const std::shared_ptr<const ClassicGraphicsFactory> _factory;
using Iterator = kku::Timeline<ClassicNote>::Iterator; using Iterator = kku::Timeline<ClassicNote>::Iterator;
Iterator _first; Iterator _first;

View File

@ -0,0 +1,34 @@
#include "classicselection.h"
#include "classicsprite.h"
ClassicSelection::ClassicSelection(ClassicSelection::Init&& init) :
_fill_color(init.color),
_shape(init.shape)
{
_shape->setColor(init.color);
}
void ClassicSelection::reset()
{
_shape->setPosition(kku::Point{0, 0});
_shape->setColor(kku::Color{0, 0, 0, 0});
}
void ClassicSelection::display() const
{
_shape->display();
}
void ClassicSelection::adjustTo(const std::shared_ptr<ClassicSprite>& sprite)
{
_shape->setRect(sprite->getRectangle()->getRect());
}
void ClassicSelection::toggle(bool selected)
{
_fill_color.alpha = selected
? 120
: 0;
_shape->setColor(_fill_color);
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "core/sprite.h"
#include "core/color.h"
#include "core/rectangle.h"
#include <memory>
class ClassicSprite;
class ClassicSelection : public kku::Sprite
{
public:
struct Init
{
std::shared_ptr<kku::Rectangle> shape;
kku::Color color;
};
explicit ClassicSelection(ClassicSelection::Init&& init);
virtual void reset() override;
virtual void display() const override;
void adjustTo(const std::shared_ptr<ClassicSprite>& sprite);
void toggle(bool selected);
protected:
kku::Color _fill_color;
std::shared_ptr<kku::Rectangle> _shape;
};

View File

@ -0,0 +1,70 @@
#include "classicsprite.h"
ClassicSprite::ClassicSprite(ClassicSprite::Init&& init) :
_reset_color(init.color),
_shape(init.shape),
_trail(init.trail)
{
_shape->setColor(init.color);
_trail->setColor(init.color);
}
void ClassicSprite::reset()
{
_shape->setPosition(kku::Point{0, 0});
_trail->setPosition(kku::Point{0, 0});
_shape->setColor(_reset_color);
_trail->setColor(_reset_color);
}
void ClassicSprite::setPosition(const kku::Point& position)
{
_shape->setPosition(position);
}
void ClassicSprite::setTrailPosition(const kku::Point &position)
{
_trail->setPosition(position);
}
kku::Point ClassicSprite::getPosition() const
{
return _shape->getPosition();
}
kku::Point ClassicSprite::getTrailPosition() const
{
return _trail->getPosition();
}
void ClassicSprite::setColor(const kku::Color& color)
{
_shape->setColor(color);
}
void ClassicSprite::setTrailColor(const kku::Color& color)
{
_trail->setColor(color);
}
kku::Color ClassicSprite::getColor() const
{
return _shape->getColor();
}
kku::Color ClassicSprite::getTrailColor() const
{
return _trail->getColor();
}
void ClassicSprite::display() const
{
_shape->display();
_trail->display();
}
std::shared_ptr<const kku::Rectangle> ClassicSprite::getRectangle() const
{
return _shape;
}

View File

@ -3,22 +3,39 @@
#include "core/sprite.h" #include "core/sprite.h"
#include "core/point.h" #include "core/point.h"
#include "core/color.h" #include "core/color.h"
#include "core/rectangle.h"
#include <memory> #include <memory>
class ClassicSprite : public kku::Sprite class ClassicSprite : public kku::Sprite
{ {
public: public:
virtual void reset() override = 0;
virtual void display() const override = 0;
virtual void setPosition(const kku::Point &position) = 0; struct Init
virtual void setTrailPosition(const kku::Point &position) = 0; {
virtual kku::Point getPosition() const = 0; std::shared_ptr<kku::Rectangle> shape;
virtual kku::Point getTrailPosition() const = 0; std::shared_ptr<kku::Rectangle> trail;
kku::Color color;
};
virtual void setColor(const kku::Color& color) = 0; explicit ClassicSprite(ClassicSprite::Init&& init);
virtual void setTrailColor(const kku::Color& color) = 0; virtual void reset() override;
virtual kku::Color getColor() const = 0; virtual void display() const override;
virtual kku::Color getTrailColor() const = 0;
virtual void setPosition(const kku::Point &position);
virtual void setTrailPosition(const kku::Point &position);
virtual kku::Point getPosition() const;
virtual kku::Point getTrailPosition() const;
virtual void setColor(const kku::Color& color);
virtual void setTrailColor(const kku::Color& color);
virtual kku::Color getColor() const;
virtual kku::Color getTrailColor() const;
std::shared_ptr<const kku::Rectangle> getRectangle() const;
protected:
kku::Color _reset_color;
std::shared_ptr<kku::Rectangle> _shape;
std::shared_ptr<kku::Rectangle> _trail;
}; };

View File

@ -1,13 +0,0 @@
#pragma once
#include <memory>
#include "classicmode/classicactions.h"
#include "graphics/classicsprite.h"
class ClassicSpriteFactory
{
public:
virtual ~ClassicSpriteFactory() = default;
virtual std::shared_ptr<ClassicSprite> create(Type type) const = 0;
};

View File

@ -1,112 +0,0 @@
#include "classictimelinegraphicsmanager.h"
#include "graphics/classicsprite.h"
#include "game/arrowelement.h"
#include "graphics/animations/classicflyinganimationscenario.h"
#include "graphics/animations/classicdyinganimationscenario.h"
ClassicTimelineGraphicsManager::ClassicTimelineGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicSpriteFactory>& factory,
const kku::microsec& visibility_offset) :
ClassicGraphicsManager(factory, visibility_offset),
_timeline(timeline),
_display_offset(0)
{
_timeline->expire(_first);
_timeline->expire(_last);
_sprites[Type::NONE] = nullptr;
_sprites[Type::UP] = factory->getSprite(Type::UP);
_sprites[Type::RIGHT] = factory->getSprite(Type::RIGHT);
_sprites[Type::DOWN] = factory->getSprite(Type::DOWN);
_sprites[Type::LEFT] = factory->getSprite(Type::LEFT);
//_sprites[Type::SLIDER_RIGHT] = factory->getSprite(Type::SLIDER_RIGHT);
//_sprites[Type::SLIDER_LEFT] = factory->getSprite(Type::SLIDER_LEFT);
}
void ClassicTimelineGraphicsManager::display() const
{
if (nothingToDraw())
return;
for (auto it = _first; it != _last; ++it)
{
const auto& note = (*it);
note->display(this);
}
}
void ClassicTimelineGraphicsManager::update(const kku::microsec &offset)
{
_timeline->expire(_first);
_timeline->expire(_last);
fetchLastNote(offset);
fetchFirstNote(offset);
_display_offset = offset;
}
void ClassicTimelineGraphicsManager::display(const std::vector<ArrowElement>& elements) const
{
for (std::size_t i = 0; i < elements.size(); ++i)
{
auto sprite = *_sprites.at(elements.at(i).type)
if (i >= 1)
{
//const auto& neighbor_sprite = elements[i - 1].sprite;
//const auto c1 = neighbor_sprite->trailPosition();
//const auto c2 = sprite->trailPosition();
//_render_target->draw(makeLine(c1, c2));
}
sprite->setPosition(kku::Position{});
sprite->display();
}
}
void ClassicTimelineGraphicsManager::fetchFirstNote(const kku::microsec& offset)
{
if (nothingToDraw())
return;
Iterator note_iterator = _first;
while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset))
{
--note_iterator;
}
_first = note_iterator;
}
void ClassicTimelineGraphicsManager::fetchLastNote(const kku::microsec& offset)
{
Iterator note_iterator = _timeline->getTopNote();
while (!_timeline->isExpired(note_iterator) && isVisiblyClose(note_iterator, offset))
{
if (nothingToDraw())
_first = note_iterator;
++note_iterator;
}
_last = note_iterator;
}
bool ClassicTimelineGraphicsManager::nothingToDraw() const noexcept
{
return _timeline->isExpired(_first)
|| _timeline->isExpired(_last);
}
bool ClassicTimelineGraphicsManager::isVisiblyClose(const Iterator& iterator, const kku::microsec& music_offset) const noexcept
{
const auto& perfect_offset = (*iterator)->getPerfectOffset();
return ((perfect_offset - _visibility_offset) <= music_offset)
|| ((perfect_offset + (_visibility_offset / 4.)) >= music_offset);
}

View File

@ -1,37 +0,0 @@
#pragma once
#include "game/classicnote.h"
#include "graphics/classicgraphicsmanager.h"
#include "core/timeline.h"
class ClassicSprite;
class ClassicTimelineGraphicsManager : public ClassicGraphicsManager
{
public:
explicit ClassicTimelineGraphicsManager(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicSpriteFactory>& factory,
const kku::microsec& visibility_offset);
virtual void display() const override;
virtual void update(const kku::microsec& offset) override;
virtual void display(const std::vector<ArrowElement>& elements) const override;
protected:
using Iterator = kku::Timeline<ClassicNote>::Iterator;
Iterator _first;
Iterator _last;
const std::shared_ptr<kku::Timeline<ClassicNote>> _timeline;
kku::microsec _display_offset;
mutable std::map<std::shared_ptr<ClassicSprite>, Type::COUNT> _sprites;
inline bool nothingToDraw() const noexcept;
inline bool isVisiblyClose(const Iterator& iterator, const kku::microsec& music_offset) const noexcept;
void fetchFirstNote(const kku::microsec& offset);
void fetchLastNote(const kku::microsec& offset);
};

View File

@ -1,9 +0,0 @@
#pragma once
#include <vector>
#include <memory>
class ClassicNotePainter
{
virtual ~ClassicNotePainter() = default;
};

View File

@ -4,11 +4,12 @@
#include "core/game.h" #include "core/game.h"
#include "core/editor.h" #include "core/editor.h"
#include "core/corefactory.h"
class ClassicFactory namespace classic
{ {
public:
virtual ~ClassicFactory() = default; std::unique_ptr<kku::Game> getGame(const std::shared_ptr<kku::CoreFactory>& core_factory);
virtual std::unique_ptr<kku::Game> getGame() const = 0; std::unique_ptr<kku::Editor> getEditor(const std::shared_ptr<kku::CoreFactory>& core_factory);
virtual std::unique_ptr<kku::Editor> getEditor() const = 0;
}; }

View File

@ -7,11 +7,10 @@ auto beat_utils::calculateBeatRateInfo(const std::vector<kku::microsec>& approxi
if (approximate_deltas.empty()) if (approximate_deltas.empty())
return {}; return {};
const kku::microsec sum = std::accumulate(approximate_deltas.begin(), approximate_deltas.end(), 0); const long double sum = std::accumulate(approximate_deltas.begin(), approximate_deltas.end(), 0);
const std::size_t amount = approximate_deltas.size(); const long double amount = approximate_deltas.size();
long double average = static_cast<long double>(sum) long double average = sum / amount;
/ static_cast<long double>(amount);
const int bpm = static_cast<int>(60000000. / average); const int bpm = static_cast<int>(60000000. / average);