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 "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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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