You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
project-kyoku/src/modes/classicmode/game/classicarrownote.h

140 lines
4.0 KiB
C++

#pragma once
#include "core/precisionevaluator.h"
#include "classicmode/classicnote.h"
#include "graphics/animations/classicanimationscenario.h"
#include <algorithm>
template <class Element>
class ClassicArrowNote : public ClassicNote
{
public:
struct Init
{
const kku::microsec perfect_offset = 0;
const std::vector<kku::microsec>& intervals = {};
const std::vector<Element>& elements = {};
};
enum class Grade
{
PERFECT,
GOOD,
BAD
};
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)
{
_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
{
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;
});
}
private:
const kku::PrecisionEvaluator<Grade> _evaluator;
std::vector<Element> _elements;
};