Add new abstraction Context

Implement GameContext and move all logic from ClassicArrowNote to there
This commit is contained in:
NaiJi ✨ 2022-05-14 07:48:46 +03:00
parent f1d24460a6
commit 14c201e28d
7 changed files with 185 additions and 117 deletions

View File

@ -0,0 +1,43 @@
#include "game/classicarrownote.h"
#include "classicmode/context.h"
ClassicArrowNote::ClassicArrowNote(Init&& init) :
ClassicNote(init.perfect_offset),
_evaluator(init.intervals, init.perfect_offset),
_context(init.context)
{
_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].position;
_elements[i].type = init.elements[i].type;
}
}
bool ClassicArrowNote::isActive(const kku::microsec& offset) const
{
return _evaluator.isActive(offset)
&& _state != State::DYING;
}
void ClassicArrowNote::update(const kku::microsec &music_offset)
{
_context->update(this, music_offset);
}
void ClassicArrowNote::input(kku::GameEvent&& input)
{
_context->input(this, std::move(input));
}
std::vector<ArrowElement>& ClassicArrowNote::getElements()
{
return _elements;
}
auto ClassicArrowNote::calculatePrecision(const kku::microsec& offset) const -> Grade
{
return _evaluator.calculatePrecision(offset);
}

View File

@ -2,138 +2,44 @@
#include "core/precisionevaluator.h" #include "core/precisionevaluator.h"
#include "classicmode/classicnote.h" #include "classicmode/classicnote.h"
#include "graphics/animations/classicanimationscenario.h" #include "game/arrowelement.h"
#include <algorithm> #include <algorithm>
template <class Element> class Context;
class ClassicArrowNote : public ClassicNote class ClassicArrowNote : public ClassicNote
{ {
public: public:
struct Init struct Init
{ {
const Context * const context;
const kku::microsec perfect_offset = 0; const kku::microsec perfect_offset = 0;
const std::vector<kku::microsec>& intervals = {}; const std::vector<kku::microsec>& intervals = {};
const std::vector<Element>& elements = {}; const std::vector<ArrowElement>& elements = {};
}; };
enum class Grade enum class Grade
{ {
PERFECT, PERFECT = 0,
GOOD, GOOD = 1,
BAD BAD = 2
}; };
explicit ClassicArrowNote(Init&& init) : explicit ClassicArrowNote(Init&& init);
ClassicNote(init.perfect_offset),
_evaluator(init.intervals, init.perfect_offset)
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i) virtual bool isActive(const kku::microsec& offset) const override;
{ virtual void update(const kku::microsec &music_offset) override;
_elements[i].keys = init.elements[i].keys; virtual void input(kku::GameEvent&& input) override;
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
virtual bool isActive(const kku::microsec& offset) const override bool isHold() const;
{ std::vector<ArrowElement>& getElements();
return _evaluator.isActive(offset) Grade calculatePrecision(const kku::microsec& offset) const;
&& _state != State::DYING;
}
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;
std::vector<Element> _elements; std::vector<ArrowElement> _elements;
const Context * const _context;
}; };

View File

@ -0,0 +1,85 @@
#include "gamecontext.h"
#include "game/classicarrownote.h"
#include "game/holdmanager.h"
#include "graphics/animations/classicanimationscenario.h"
GameContext::GameContext(HoldManager *hold_manager, ClassicGraphicsManager *graphics_manager) :
_hold_manager(hold_manager),
_graphics_manager(graphics_manager)
{}
void GameContext::input(ClassicArrowNote *note, kku::GameEvent&& input) const
{
auto grade = ClassicArrowNote::Grade::BAD;
auto& elements = note->getElements();
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 = std::all_of(elements.begin(), elements.end(),
[](const auto& element)
{
return element.pressed;
});
if (all_pressed)
{
grade = note->calculatePrecision(input.timestamp);
if (note->isHold())
_hold_manager->emplace(note);
}
if (all_pressed || !input_valid)
{
note->setState(ClassicArrowNote::State::DYING);
for (auto& element : elements)
element.animations[note->getState()]->launch(element.sprite, input.timestamp, note->getPerfectOffset());
}
std::cout << "User input: " << static_cast<int>(grade) << "\n";
}
void GameContext::update(ClassicArrowNote *note, const kku::microsec& music_offset) const
{
auto& elements = note->getElements();
switch (note->getState())
{
default: return;
break;
case ClassicArrowNote::State::FLYING:
if (!note->isActive(music_offset) && music_offset > note->getPerfectOffset())
{
note->setState(ClassicArrowNote::State::DYING);
for (auto& element : elements)
element.animations[note->getState()]->launch(element.sprite, music_offset, note->getPerfectOffset());
}
break;
case ClassicArrowNote::State::DYING:
if (elements[0].animations[note->getState()]->isDone())
note->setState(ClassicArrowNote::State::DEAD);
break;
}
for (auto& element : elements)
if (element.animations[note->getState()])
element.animations[note->getState()]->update(music_offset);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "classicmode/context.h"
class HoldManager;
class ClassicGraphicsManager;
class GameContext : public Context
{
public:
explicit GameContext(HoldManager *hold_manager, ClassicGraphicsManager *graphics_manager);
virtual void input(ClassicArrowNote *note, kku::GameEvent&& input) const override;
virtual void update(ClassicArrowNote *note, const kku::microsec &music_offset) const override;
private:
HoldManager * const _hold_manager;
ClassicGraphicsManager * const _graphics_manager;
};

View File

@ -12,12 +12,12 @@ class ClassicGraphicsManager;
class HoldManager class HoldManager
{ {
public: public:
void emplace(ClassicArrowNote<ArrowElement>* note); void emplace(ClassicArrowNote* 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<ArrowElement>*> _notes_on_hold; std::vector<ClassicArrowNote*> _notes_on_hold;
std::shared_ptr<ClassicGraphicsManager> _graphics_manager; std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
}; };

View File

@ -8,11 +8,11 @@ public:
enum State enum State
{ {
NONE, NONE = 0,
FLYING, FLYING = 1,
DYING, DYING = 2,
DEAD DEAD = 3
}; };
explicit ClassicNote(const kku::microsec& perfect_offset); explicit ClassicNote(const kku::microsec& perfect_offset);

View File

@ -0,0 +1,15 @@
#pragma once
#include "core/time.h"
#include "core/gameevent.h"
class ClassicArrowNote;
class Context
{
public:
virtual ~Context() = default;
virtual void input(ClassicArrowNote *note, kku::GameEvent&& input) const = 0;
virtual void update(ClassicArrowNote *note, const kku::microsec &music_offset) const = 0;
};