Turn ArrowNote into a template with T for note element

This commit is contained in:
NaiJi ✨ 2022-03-15 20:11:17 +03:00
parent 70d3284eeb
commit 41541e0757
14 changed files with 135 additions and 341 deletions

View File

@ -27,9 +27,8 @@ std::unique_ptr<kku::Editor> classic::getEditor(const std::shared_ptr<kku::CoreF
const kku::microsec visibility_offset = 1648648; const kku::microsec visibility_offset = 1648648;
const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory); const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory);
const auto timeline = std::make_shared<kku::Timeline<ClassicMockNote>>(); const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>();
const auto selection_manager = std::make_shared<SelectionManager<ClassicMockNote>>(); const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager<ClassicNote>>(timeline, factory, visibility_offset);
const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager<ClassicMockNote>>(timeline, factory, visibility_offset);
return std::make_unique<ClassicEditor>(timeline, graphics_manager, selection_manager); return std::make_unique<ClassicEditor>(timeline, graphics_manager);
} }

View File

@ -1,7 +1,7 @@
#include "classicmode/classicnote.h" #include "classicmode/classicnote.h"
ClassicNote::ClassicNote(NoteInitializer &&init) : ClassicNote::ClassicNote(const kku::microsec& perfect_offset) :
Note(init.perfect_offset), Note(perfect_offset),
_state(State::NONE) _state(State::NONE)
{} {}

View File

@ -1,6 +1,5 @@
#include "classiceditor.h" #include "classiceditor.h"
#include "classicmocknote.h"
#include "graphics/classicgraphicsmanager.h" #include "graphics/classicgraphicsmanager.h"
#include "editor/selectionmanager.h" #include "editor/selectionmanager.h"
@ -11,9 +10,9 @@
#include "callbacks/callbacksimple.h" #include "callbacks/callbacksimple.h"
ClassicEditor::ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicMockNote>>& timeline, ClassicEditor::ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager, const std::shared_ptr<ClassicGraphicsManager>& graphics_manager,
const std::shared_ptr<SelectionManager<ClassicMockNote>>& selection_manager) : const std::shared_ptr<SelectionManager<ClassicNote>>& selection_manager) :
_timeline(timeline), _timeline(timeline),
_graphics_manager(graphics_manager), _graphics_manager(graphics_manager),
_selection_manager(selection_manager), _selection_manager(selection_manager),
@ -31,7 +30,7 @@ ClassicEditor::ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicMockNote
kku::microsec bpm_end = starting_beat_offset + (interval * amount_of_beats); 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::vector<kku::microsec> input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset};
std::set<ClassicMockNote*, kku::NotePtrComparator> notes; std::set<ClassicNote*, kku::NotePtrComparator> notes;
input_intervals.shrink_to_fit(); input_intervals.shrink_to_fit();
bpm_iterator += tempo_interval; bpm_iterator += tempo_interval;

View File

@ -6,7 +6,7 @@
#include "core/timeline.h" #include "core/timeline.h"
#include "selectionmanager.h" #include "selectionmanager.h"
#include "classicmocknote.h" #include "classicmode/classicnote.h"
#include "classicmode/classicactions.h" #include "classicmode/classicactions.h"
class ClassicGraphicsManager; class ClassicGraphicsManager;
@ -14,9 +14,9 @@ class ClassicGraphicsManager;
class ClassicEditor : public kku::Editor class ClassicEditor : public kku::Editor
{ {
public: public:
explicit ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicMockNote>>& timeline, explicit ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager, const std::shared_ptr<ClassicGraphicsManager>& graphics_manager,
const std::shared_ptr<SelectionManager<ClassicMockNote>>& selection_manager); const std::shared_ptr<SelectionManager<ClassicNote>>& selection_manager);
virtual void input(kku::GameEvent&& input) override; virtual void input(kku::GameEvent&& input) override;
virtual void update(kku::UpdateData&& updatedata) override; virtual void update(kku::UpdateData&& updatedata) override;
@ -28,9 +28,9 @@ public:
private: private:
inline kku::microsec adjustOffset(kku::microsec offset) const noexcept; inline kku::microsec adjustOffset(kku::microsec offset) const noexcept;
const std::shared_ptr<kku::Timeline<ClassicMockNote>> _timeline; const std::shared_ptr<kku::Timeline<ClassicNote>> _timeline;
const std::shared_ptr<ClassicGraphicsManager> _graphics_manager; const std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
const std::shared_ptr<SelectionManager<ClassicMockNote>> _selection_manager; const std::shared_ptr<SelectionManager<ClassicNote>> _selection_manager;
Type _selected_type; Type _selected_type;
kku::microsec _current_time; kku::microsec _current_time;

View File

@ -1,101 +0,0 @@
#include "classicmocknote.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "graphics/animations/classicanimationscenario.h"
#include "editor/selectionmanager.h"
ClassicMockNote::ClassicMockNote(ArrowNoteInitializer&& init, const std::shared_ptr<SelectionManager<ClassicMockNote>>& selection_manager) :
ClassicNote(std::move(init.initializer)),
_selection_manager(selection_manager)
{
_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:
{
bool selection_changed = false;
std::size_t amount_selected = 0;
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;
selection_changed = true;
if (element.selected)
++amount_selected;
}
}
if (selection_changed)
{
if (amount_selected > 0)
_selection_manager->fetch(this);
else
_selection_manager->remove(this);
}
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);
}
std::vector<MockElement>& ClassicMockNote::getElements()
{
return _elements;
}
void ClassicMockNote::deselect()
{
for (auto& element : _elements)
element.selected = false;
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "classicmode/classicnote.h"
#include "mockelement.h"
#include "classicmode/arrownoteinitializer.h"
#include "selectionmanager.h"
class ClassicMockNote : public ClassicNote
{
public:
explicit ClassicMockNote(ArrowNoteInitializer&& init, const std::shared_ptr<SelectionManager<ClassicMockNote>>& selection_manager);
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;
std::vector<MockElement>& getElements();
void deselect();
private:
const std::shared_ptr<SelectionManager<ClassicMockNote>> _selection_manager;
std::vector<MockElement> _elements;
};
using MockElements = std::vector<MockElement>;

View File

@ -1,124 +0,0 @@
#include "classicarrownote.h"
#include "graphics/animations/classicanimationscenario.h"
#include "holdmanager.h"
#include <algorithm>
ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init, const std::shared_ptr<HoldManager>& hold_manager) :
ClassicNote(std::move(init.initializer)),
_evaluator(init.initializer.intervals, _perfect_offset),
_hold_manager(hold_manager),
_is_hold(init.hold)
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].keys = init.elements[i].keys;
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
bool ClassicArrowNote::isActive(const kku::microsec& offset) const
{
return _evaluator.isActive(offset)
&& _state != State::DYING;
}
void ClassicArrowNote::input(kku::GameEvent&& input)
{
auto grade = Grade::BAD;
bool input_valid = std::any_of(_elements.begin(), _elements.end(),
[input=input](auto& element)
{
if (element.pressed)
return false;
const auto code = std::get<kku::SystemEvent::Key>(input.event.data).view;
auto key_iterator = std::find(element.keys.begin(), element.keys.end(), code);
bool found_key = key_iterator != element.keys.end();
if (found_key)
{
element.pressed = true;
element.pressed_as = code;
}
return found_key;
});
bool all_pressed = allElementsPressed();
if (all_pressed)
{
grade = _evaluator.calculatePrecision(input.timestamp);
if (isHold())
_hold_manager->emplace(this);
}
if (all_pressed || !input_valid)
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, input.timestamp, getPerfectOffset());
}
std::cout << "User input: " << static_cast<int>(grade) << "\n";
}
void ClassicArrowNote::update(const kku::microsec& music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (!_evaluator.isActive(music_offset) && 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);
}
bool ClassicArrowNote::allElementsPressed() const
{
return std::all_of(_elements.begin(), _elements.end(),
[](const auto& element)
{
return element.pressed;
});
}
bool ClassicArrowNote::isPressedAs(kku::SystemEvent::Key::Code key) const
{
return std::any_of(_elements.begin(), _elements.end(),
[key](const auto& element)
{
return key == element.pressed_as;
});
}
bool ClassicArrowNote::isHold() const
{
return _is_hold;
}
std::vector<ArrowElement>& ClassicArrowNote::getElements()
{
return _elements;
}

View File

@ -1,14 +1,24 @@
#pragma once #pragma once
#include "arrowelement.h" #include "core/precisionevaluator.h"
#include "classicmode/classicnote.h" #include "classicmode/classicnote.h"
#include "classicmode/arrownoteinitializer.h" #include "graphics/animations/classicanimationscenario.h"
class HoldManager; #include <algorithm>
template <class Element>
class ClassicArrowNote : public ClassicNote class ClassicArrowNote : public ClassicNote
{ {
public: public:
struct Init
{
const kku::microsec perfect_offset = 0;
const std::vector<kku::microsec>& intervals = {};
const std::vector<Element>& elements = {};
};
enum class Grade enum class Grade
{ {
PERFECT, PERFECT,
@ -16,25 +26,114 @@ public:
BAD BAD
}; };
explicit ClassicArrowNote(ArrowNoteInitializer&& init, const std::shared_ptr<HoldManager>& hold_manager); explicit ClassicArrowNote(Init&& init) :
virtual ~ClassicArrowNote() = default; ClassicNote(init.perfect_offset),
_evaluator(init.intervals, init.perfect_offset)
{
_elements.resize(init.elements.size());
virtual bool isActive(const kku::microsec& offset) const override; for (std::size_t i = 0; i < _elements.size(); ++i)
virtual void update(const kku::microsec &music_offset) override; {
virtual void input(kku::GameEvent&& input) override; _elements[i].keys = init.elements[i].keys;
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
bool allElementsPressed() const; virtual bool isActive(const kku::microsec& offset) const override
bool isPressedAs(kku::SystemEvent::Key::Code key) const; {
inline bool isHold() const; return _evaluator.isActive(offset)
&& _state != State::DYING;
}
std::vector<ArrowElement>& getElements(); virtual void update(const kku::microsec &music_offset) override
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (!_evaluator.isActive(music_offset) && 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);
}
virtual void input(kku::GameEvent&& input) override
{
auto grade = Grade::BAD;
bool input_valid = std::any_of(_elements.begin(), _elements.end(),
[input=input](auto& element)
{
if (element.pressed)
return false;
const auto code = std::get<kku::SystemEvent::Key>(input.event.data).view;
auto key_iterator = std::find(element.keys.begin(), element.keys.end(), code);
bool found_key = key_iterator != element.keys.end();
if (found_key)
{
element.pressed = true;
element.pressed_as = code;
}
return found_key;
});
bool all_pressed = allElementsPressed();
if (all_pressed)
{
grade = _evaluator.calculatePrecision(input.timestamp);
//if (isHold())
//_hold_manager->emplace(this);
}
if (all_pressed || !input_valid)
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, input.timestamp, getPerfectOffset());
}
std::cout << "User input: " << static_cast<int>(grade) << "\n";
}
bool allElementsPressed() const
{
return std::all_of(_elements.begin(), _elements.end(),
[](const auto& element)
{
return element.pressed;
});
}
bool isPressedAs(kku::SystemEvent::Key::Code key) const
{
return std::any_of(_elements.begin(), _elements.end(),
[key](const auto& element)
{
return key == element.pressed_as;
});
}
private: private:
const kku::PrecisionEvaluator<Grade> _evaluator; const kku::PrecisionEvaluator<Grade> _evaluator;
const std::shared_ptr<HoldManager> _hold_manager; std::vector<Element> _elements;
std::vector<ArrowElement> _elements;
bool _is_hold;
}; };
using ArrowElements = std::vector<ArrowElement>;

View File

@ -1,22 +1,23 @@
#pragma once #pragma once
#include "classicarrownote.h"
#include "game/arrowelement.h"
#include "core/gameevent.h" #include "core/gameevent.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
class ClassicArrowNote;
class ClassicGraphicsManager; class ClassicGraphicsManager;
class HoldManager class HoldManager
{ {
public: public:
void emplace(ClassicArrowNote* note); void emplace(ClassicArrowNote<ArrowElement>* note);
void checkRelease(kku::SystemEvent::Key::Code released_key); void checkRelease(kku::SystemEvent::Key::Code released_key);
void drawHoldBar(); void drawHoldBar();
private: private:
std::vector<ClassicArrowNote*> _notes_on_hold; std::vector<ClassicArrowNote<ArrowElement>*> _notes_on_hold;
std::shared_ptr<ClassicGraphicsManager> _graphics_manager; std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
}; };

View File

@ -1,9 +0,0 @@
#pragma once
#include "classicmode/elementinitializer.h"
struct ArrowElementInitializer
{
ElementInitializer element;
std::array<kku::SystemEvent::Key::Code, 2> keys;
};

View File

@ -1,12 +0,0 @@
#pragma once
#include "classicmode/noteinitializer.h"
#include "arrowelementinitializer.h"
struct ArrowNoteInitializer
{
NoteInitializer initializer;
bool hold = false;
std::vector<ArrowElementInitializer> elements;
};

View File

@ -1,10 +1,6 @@
#pragma once #pragma once
#include "core/note.h" #include "core/note.h"
#include "core/precisionevaluator.h"
#include "classicmode/noteinitializer.h"
class ClassicGraphicsManager;
class ClassicNote : public kku::Note class ClassicNote : public kku::Note
{ {
@ -19,7 +15,7 @@ public:
DEAD DEAD
}; };
explicit ClassicNote(NoteInitializer&& init); explicit ClassicNote(const kku::microsec& perfect_offset);
virtual ~ClassicNote() override = default; virtual ~ClassicNote() override = default;
virtual bool isActive(const kku::microsec& offset) const override = 0; virtual bool isActive(const kku::microsec& offset) const override = 0;

View File

@ -1,15 +0,0 @@
#pragma once
#include "classicactions.h"
#include "core/gameevent.h"
#include "core/point.h"
#include <vector>
struct ElementInitializer
{
Type type = Type::NONE;
kku::Point position;
std::vector<kku::Point> falling_curve_interpolation;
};

View File

@ -1,12 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include "core/time.h"
struct NoteInitializer
{
std::vector<kku::microsec> intervals;
kku::microsec perfect_offset = 0;
};