project-kyoku/modes/classicmode/game/classicnote.cpp

163 lines
4.7 KiB
C++

#include "classicnote.h"
#include "classicsprite.h"
#include "classicgraphicsmanager.h"
// Replace with interface by dependency injection
#include "classicflyinganimationscenario.h"
#include "classicdyinganimationscenario.h"
//
ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::shared_ptr<ClassicGraphicsManager>& manager) :
Note(init.perfect_offset),
_evaluator(init.intervals, _perfect_offset),
_graphics_manager(manager),
_state(State::NONE)
{
_elements.resize(init.elements.size());
_isHold = init.hold;
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].keys = init.elements[i].keys;
_elements[i].coordinates = init.elements[i].coordinates;
_elements[i].type = init.elements[i].type;
// Animations will be injected into note.
_elements[i].animations[State::NONE] = nullptr;
_elements[i].animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
_elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING];
_elements[i].animations[State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
_elements[i].animations[State::DEAD] = nullptr;
}
}
bool ClassicNote::isActive() const
{
return _state == State::ACTIVE;
}
void ClassicNote::putToGame(const microsec &music_offset)
{
_state = State::FLYING;
for (auto& element : _elements)
{
element.sprite = _graphics_manager->getSprite(element.type);
element.sprite->setCoordinates(element.coordinates, 0., 9.);
element.animations[_state]->launch(element.sprite, music_offset, offset());
}
}
bool ClassicNote::isInGame() const
{
return _state == State::FLYING
|| _state == State::ACTIVE
|| _state == State::DYING;
}
bool ClassicNote::shouldRemove() const
{
return _state == State::DEAD;
}
void ClassicNote::update(const microsec& music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (_evaluator.isActive(music_offset))
_state = State::ACTIVE;
break;
case State::DYING:
if (_elements[0].animations[_state]->isDone())
_state = State::DEAD;
break;
case State::ACTIVE:
if (!_evaluator.isActive(music_offset))
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, music_offset, offset());
}
break;
}
for (auto& element : _elements)
if (element.animations[_state])
element.animations[_state]->update(music_offset);
}
void ClassicNote::input(PlayerInput&& inputdata)
{
auto grade = ClassicNote::Grade::BAD;
bool input_valid = std::any_of(_elements.begin(), _elements.end(),
[inputdata=inputdata](auto& element)
{
if (element.pressed)
return false;
auto key_iterator = std::find(element.keys.begin(), element.keys.end(), inputdata.event.key.code);
bool found_key = key_iterator != element.keys.end();
if (found_key)
{
element.pressed = true;
element.pressed_as = inputdata.event.key.code;
}
return found_key;
});
bool all_pressed = allElementsPressed();
if (all_pressed)
grade = _evaluator.calculatePrecision(inputdata.timestamp);
if (all_pressed || !input_valid)
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, inputdata.timestamp, offset());
}
std::cout << "User input: " << static_cast<int>(grade) << "\n";
}
void ClassicNote::draw() const
{
for (std::size_t i = 0; i < _elements.size(); ++i)
{
if (i >= 1)
_graphics_manager->drawLine(_elements[i-1].sprite->trailCoordinates(), _elements[i].sprite->trailCoordinates());
_graphics_manager->draw(_elements[i].sprite);
}
}
bool ClassicNote::isHold() const
{
return _isHold;
}
bool ClassicNote::allElementsPressed() const
{
return std::all_of(_elements.begin(), _elements.end(),
[](const auto& element)
{
return element.pressed;
});
}
bool ClassicNote::isPressedAs(sf::Keyboard::Key key) const
{
return std::any_of(_elements.begin(), _elements.end(),
[key=key](const auto& element)
{
return key == element.pressed_as;
});
}