forked from NaiJi/project-kyoku
Add new abstraction Context
Implement GameContext and move all logic from ClassicArrowNote to there
This commit is contained in:
parent
f1d24460a6
commit
14c201e28d
|
@ -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);
|
||||
}
|
|
@ -2,138 +2,44 @@
|
|||
|
||||
#include "core/precisionevaluator.h"
|
||||
#include "classicmode/classicnote.h"
|
||||
#include "graphics/animations/classicanimationscenario.h"
|
||||
#include "game/arrowelement.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template <class Element>
|
||||
class Context;
|
||||
|
||||
class ClassicArrowNote : public ClassicNote
|
||||
{
|
||||
public:
|
||||
|
||||
struct Init
|
||||
{
|
||||
const Context * const context;
|
||||
const kku::microsec perfect_offset = 0;
|
||||
|
||||
const std::vector<kku::microsec>& intervals = {};
|
||||
const std::vector<Element>& elements = {};
|
||||
const std::vector<ArrowElement>& elements = {};
|
||||
};
|
||||
|
||||
enum class Grade
|
||||
{
|
||||
PERFECT,
|
||||
GOOD,
|
||||
BAD
|
||||
PERFECT = 0,
|
||||
GOOD = 1,
|
||||
BAD = 2
|
||||
};
|
||||
|
||||
explicit ClassicArrowNote(Init&& init) :
|
||||
ClassicNote(init.perfect_offset),
|
||||
_evaluator(init.intervals, init.perfect_offset)
|
||||
{
|
||||
_elements.resize(init.elements.size());
|
||||
explicit ClassicArrowNote(Init&& init);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 bool isActive(const kku::microsec& offset) const override
|
||||
{
|
||||
return _evaluator.isActive(offset)
|
||||
&& _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;
|
||||
});
|
||||
}
|
||||
bool isHold() const;
|
||||
std::vector<ArrowElement>& getElements();
|
||||
Grade calculatePrecision(const kku::microsec& offset) const;
|
||||
|
||||
private:
|
||||
const kku::PrecisionEvaluator<Grade> _evaluator;
|
||||
std::vector<Element> _elements;
|
||||
std::vector<ArrowElement> _elements;
|
||||
const Context * const _context;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -12,12 +12,12 @@ class ClassicGraphicsManager;
|
|||
class HoldManager
|
||||
{
|
||||
public:
|
||||
void emplace(ClassicArrowNote<ArrowElement>* note);
|
||||
void emplace(ClassicArrowNote* note);
|
||||
void checkRelease(kku::SystemEvent::Key::Code released_key);
|
||||
|
||||
void drawHoldBar();
|
||||
|
||||
private:
|
||||
std::vector<ClassicArrowNote<ArrowElement>*> _notes_on_hold;
|
||||
std::vector<ClassicArrowNote*> _notes_on_hold;
|
||||
std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||
};
|
||||
|
|
|
@ -8,11 +8,11 @@ public:
|
|||
|
||||
enum State
|
||||
{
|
||||
NONE,
|
||||
NONE = 0,
|
||||
|
||||
FLYING,
|
||||
DYING,
|
||||
DEAD
|
||||
FLYING = 1,
|
||||
DYING = 2,
|
||||
DEAD = 3
|
||||
};
|
||||
|
||||
explicit ClassicNote(const kku::microsec& perfect_offset);
|
||||
|
|
|
@ -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;
|
||||
};
|
Loading…
Reference in New Issue