forked from NaiJi/project-kyoku
Fix animation objects and note state machine
This commit is contained in:
parent
06d099c11f
commit
77a9d15caa
|
@ -1,10 +1,8 @@
|
|||
#ifndef INPUTTYPE_H
|
||||
#define INPUTTYPE_H
|
||||
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/Window/Event.hpp>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
#include "mathutils.h"
|
||||
|
||||
struct PlayerInput
|
||||
{
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
#include <SFML/System/Clock.hpp>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
struct Coordinates
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
constexpr inline Coordinates operator+(const Coordinates& right) const noexcept
|
||||
{
|
||||
return {right.x + x, right.y + y};
|
||||
}
|
||||
|
||||
constexpr inline Coordinates operator-(const Coordinates& right) const noexcept
|
||||
{
|
||||
return {right.x - x, right.y - y};
|
||||
}
|
||||
|
||||
inline void moveBy(float x, float y) noexcept
|
||||
{
|
||||
this->x += x;
|
||||
this->y += y;
|
||||
}
|
||||
|
||||
inline void moveBy(const Coordinates& right) noexcept
|
||||
{
|
||||
this->x += right.x;
|
||||
this->y += right.y;
|
||||
}
|
||||
|
||||
inline void scale(float factor) noexcept
|
||||
{
|
||||
x *= factor;
|
||||
y *= factor;
|
||||
}
|
||||
};
|
|
@ -1,13 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/Graphics/Drawable.hpp>
|
||||
|
||||
#include "inputtype.h"
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
class Note
|
||||
{
|
||||
public:
|
||||
|
@ -15,12 +9,13 @@ public:
|
|||
_perfect_offset(perfect_offset) {}
|
||||
virtual ~Note() = default;
|
||||
|
||||
virtual bool isActive(const microsec& music_offset) const = 0;
|
||||
virtual bool isActive() const = 0;
|
||||
virtual void update(const microsec& music_offset) = 0;
|
||||
virtual void input(PlayerInput&& inputdata) = 0;
|
||||
virtual void draw() const = 0;
|
||||
|
||||
virtual void putToGame(const microsec &offset) = 0;
|
||||
virtual bool isInGame() const = 0;
|
||||
virtual bool isExpired() const = 0;
|
||||
|
||||
microsec offset() const
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
#ifndef PRECISIONEVALUATOR_H
|
||||
#define PRECISIONEVALUATOR_H
|
||||
|
||||
#include "mathutils.h"
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
#include <SFML/System/Clock.hpp>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
template<typename Grade, typename = std::enable_if_t<std::is_enum<Grade>::value>>
|
||||
class PrecisionEvaluator
|
||||
{
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#ifndef TIMELINE_H
|
||||
#define TIMELINE_H
|
||||
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Config.hpp>
|
||||
#include "mathutils.h"
|
||||
#include <memory>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
#include <vector>
|
||||
|
||||
class Note;
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "classicgame/classicgame.h"
|
||||
#include "classicgame/classicgraphicsmanager.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
||||
|
||||
Application::Application() :
|
||||
|
@ -27,7 +29,6 @@ void Application::run()
|
|||
void Application::exec()
|
||||
{
|
||||
sf::Clock timer;
|
||||
sf::Clock game_timer;
|
||||
sf::Time time_since_last_update = sf::Time::Zero;
|
||||
|
||||
while (_game_window.isOpen())
|
||||
|
@ -41,7 +42,6 @@ void Application::exec()
|
|||
if (isOneFramePassed)
|
||||
{
|
||||
time_since_last_update -= TIME_PER_FRAME;
|
||||
game_timer.restart();
|
||||
update();
|
||||
draw();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <SFML/Config.hpp>
|
||||
#include "mathutils.h"
|
||||
#include <memory>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
class ClassicSprite;
|
||||
|
||||
class ClassicAnimationScenario
|
||||
|
|
|
@ -24,10 +24,10 @@ void ClassicFlyingAnimationScenario::update(const microsec& music_offset)
|
|||
auto update_time = music_offset - _time_begin;
|
||||
i = update_time / _percentage * 0.01;
|
||||
|
||||
float xa = getPoint( crd.first + 20. , crd.first + 90. , i );
|
||||
float ya = getPoint( crd.second - 600. , crd.second - 150. , i );
|
||||
float xb = getPoint( crd.first + 90. , crd.first , i );
|
||||
float yb = getPoint( crd.second - 150. , crd.second , i );
|
||||
float xa = getPoint( crd.x + 20. , crd.x + 90. , i );
|
||||
float ya = getPoint( crd.y - 600. , crd.y - 150. , i );
|
||||
float xb = getPoint( crd.x + 90. , crd.x , i );
|
||||
float yb = getPoint( crd.y - 150. , crd.y , i );
|
||||
|
||||
_sprite->update(getPoint( xa , xb , i ), getPoint( ya , yb , i ));
|
||||
if (i >= 1)
|
||||
|
|
|
@ -11,12 +11,13 @@ ClassicGraphicsManager::ClassicGraphicsManager(sf::RenderTarget& target) :
|
|||
void ClassicGraphicsManager::initGraphics(ClassicNote* note)
|
||||
{
|
||||
note->setSprite(_sprite_container.getSprite(note->type()));
|
||||
note->sprite()->setCoordinates(note->getCoordinates().x, note->getCoordinates().y, 0, 0);
|
||||
note->sprite()->setCoordinates(note->getCoordinates(), 0, 0);
|
||||
}
|
||||
|
||||
void ClassicGraphicsManager::resetGraphics(ClassicNote* note)
|
||||
{
|
||||
_sprite_container.resetSprite(note->sprite(), note->type());
|
||||
note->setSprite(nullptr);
|
||||
}
|
||||
|
||||
void ClassicGraphicsManager::draw(const ClassicNote *note)
|
||||
|
|
|
@ -12,7 +12,7 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
|
|||
microsec starting_beat_offset = 352162;
|
||||
int amount_of_beats = 209;
|
||||
microsec interval = 1412162;
|
||||
microsec tempo_interval = interval / 2;
|
||||
microsec tempo_interval = interval / 4;
|
||||
microsec note_input_offset = 412162 / 3;
|
||||
microsec bpm_iterator = starting_beat_offset;
|
||||
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "classicgraphicsmanager.h"
|
||||
#include "classicflyinganimationscenario.h"
|
||||
#include "classicdyinganimationscenario.h"
|
||||
#include <iostream>
|
||||
|
||||
ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset,
|
||||
Type type, const Coordinates& coord, const std::unique_ptr<ClassicGraphicsManager> &manager) :
|
||||
|
@ -12,48 +11,66 @@ ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfec
|
|||
_evaluator(intervals, _perfect_offset),
|
||||
_keys({sf::Keyboard::W, sf::Keyboard::Up}),
|
||||
_graphics_manager(manager),
|
||||
_is_expired(true),
|
||||
_type(type),
|
||||
_state(State::NONE)
|
||||
{
|
||||
_animations[State::NONE] = nullptr;
|
||||
_animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
|
||||
_animations[State::ACTIVE] = _animations[State::FLYING];
|
||||
_animations[State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
|
||||
_animations[State::DEAD] = nullptr;
|
||||
}
|
||||
|
||||
bool ClassicNote::isActive(const microsec &music_offset) const
|
||||
bool ClassicNote::isActive() const
|
||||
{
|
||||
return _evaluator.isActive(music_offset);
|
||||
return _state == State::ACTIVE;
|
||||
}
|
||||
|
||||
void ClassicNote::putToGame(const microsec &music_offset)
|
||||
{
|
||||
_is_expired = false;
|
||||
_graphics_manager->initGraphics(this);
|
||||
_state = State::FLYING;
|
||||
_animations[_state]->launch(_sprite, music_offset, offset());
|
||||
}
|
||||
|
||||
bool ClassicNote::isInGame() const
|
||||
{
|
||||
return _state == State::FLYING || _state == State::ACTIVE || _state == State::DYING;
|
||||
}
|
||||
|
||||
bool ClassicNote::isExpired() const
|
||||
{
|
||||
return _is_expired;
|
||||
return _state == State::DEAD;
|
||||
}
|
||||
|
||||
void ClassicNote::update(const microsec& music_offset)
|
||||
{
|
||||
if (!_animations[_state])
|
||||
return;
|
||||
|
||||
bool is_not_active_anymore = (!_is_expired && !isActive(music_offset));
|
||||
|
||||
if (is_not_active_anymore)
|
||||
switch (_state)
|
||||
{
|
||||
_state = State::DYING;
|
||||
_animations[_state]->launch(_sprite, music_offset, offset());
|
||||
default: return;
|
||||
break;
|
||||
|
||||
case State::FLYING:
|
||||
if (_evaluator.isActive(music_offset))
|
||||
_state = State::ACTIVE;
|
||||
break;
|
||||
|
||||
case State::DYING:
|
||||
if (_animations[_state]->isDone())
|
||||
_state = State::DEAD;
|
||||
break;
|
||||
|
||||
case State::ACTIVE:
|
||||
if (!_evaluator.isActive(music_offset))
|
||||
{
|
||||
_state = State::DYING;
|
||||
_animations[_state]->launch(_sprite, music_offset, offset());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_animations[_state]->update(music_offset);
|
||||
_is_expired = _animations[_state]->isDone();
|
||||
if (_animations[_state])
|
||||
_animations[_state]->update(music_offset);
|
||||
}
|
||||
|
||||
void ClassicNote::input(PlayerInput&& inputdata)
|
||||
|
|
|
@ -7,17 +7,6 @@
|
|||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
struct Coordinates
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
inline Coordinates operator+(const Coordinates& right) noexcept
|
||||
{
|
||||
return {right.x + x, right.y - y};
|
||||
}
|
||||
}; // MOVE TO OWN HEADER ^
|
||||
|
||||
class ClassicSprite;
|
||||
class ClassicGraphicsManager;
|
||||
class ClassicAnimationScenario;
|
||||
|
@ -38,7 +27,9 @@ public:
|
|||
NONE,
|
||||
|
||||
FLYING,
|
||||
DYING
|
||||
ACTIVE,
|
||||
DYING,
|
||||
DEAD
|
||||
};
|
||||
|
||||
explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset,
|
||||
|
@ -46,10 +37,11 @@ public:
|
|||
const std::unique_ptr<ClassicGraphicsManager>& manager);
|
||||
virtual ~ClassicNote() = default;
|
||||
|
||||
virtual bool isActive(const microsec &music_offset) const override;
|
||||
virtual bool isActive() const override;
|
||||
virtual void update(const microsec &music_offset) override;
|
||||
virtual void input(PlayerInput&& inputdata) override;
|
||||
virtual void putToGame(const microsec &music_offset) override;
|
||||
virtual bool isInGame() const override;
|
||||
virtual bool isExpired() const override;
|
||||
virtual void draw() const override;
|
||||
|
||||
|
@ -67,9 +59,8 @@ private:
|
|||
const std::unique_ptr<ClassicGraphicsManager>& _graphics_manager;
|
||||
std::shared_ptr<ClassicSprite> _sprite;
|
||||
|
||||
bool _is_expired;
|
||||
const Type _type;
|
||||
|
||||
State _state;
|
||||
std::array<std::shared_ptr<ClassicAnimationScenario>, 3> _animations;
|
||||
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> _animations;
|
||||
};
|
||||
|
|
|
@ -29,16 +29,16 @@ void ClassicSprite::reset()
|
|||
_trail_fade = false;
|
||||
}
|
||||
|
||||
void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept
|
||||
void ClassicSprite::setCoordinates(const Coordinates& coordinates, float trail_x, float trail_y) noexcept
|
||||
{
|
||||
_shape.setPosition(x, y);
|
||||
_shape.setPosition(coordinates.x, coordinates.y);
|
||||
_trail.setPosition(trail_x, trail_y);
|
||||
_grade_text.setPosition(x + _shape.getSize().x/2, y + 10);
|
||||
_grade_text.setPosition(coordinates.x + _shape.getSize().x/2, coordinates.y + 10);
|
||||
}
|
||||
|
||||
std::pair<float, float> ClassicSprite::coordinates() const
|
||||
Coordinates ClassicSprite::coordinates() const
|
||||
{
|
||||
return std::make_pair(_shape.getPosition().x, _shape.getPosition().y);
|
||||
return {_shape.getPosition().x, _shape.getPosition().y};
|
||||
}
|
||||
|
||||
void ClassicSprite::update(float trail_x, float trail_y) noexcept
|
||||
|
@ -76,8 +76,12 @@ void ClassicSprite::fade()
|
|||
{
|
||||
auto fill_color = _grade_text.getFillColor();
|
||||
|
||||
if (fill_color.a == 0)
|
||||
if (fill_color.a <= 15)
|
||||
{
|
||||
fill_color.a = 0;
|
||||
_grade_text.setFillColor(fill_color);
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_alpha = fill_color.a - 15;
|
||||
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
|
||||
|
@ -87,7 +91,11 @@ void ClassicSprite::fade()
|
|||
fill_color = _shape.getFillColor();
|
||||
|
||||
if (fill_color.a == 0)
|
||||
{
|
||||
fill_color.a = 0;
|
||||
_shape.setFillColor(fill_color);
|
||||
return;
|
||||
}
|
||||
|
||||
new_alpha = fill_color.a - 15;
|
||||
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "mathutils.h"
|
||||
#include "sprite.h"
|
||||
#include "SFML/Graphics/RectangleShape.hpp"
|
||||
#include "SFML/Graphics/Text.hpp"
|
||||
|
@ -11,8 +12,8 @@ public:
|
|||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||
virtual void reset() override;
|
||||
|
||||
void setCoordinates(float x, float y, float trail_x, float trail_y) noexcept;
|
||||
std::pair<float, float> coordinates() const;
|
||||
void setCoordinates(const Coordinates &coordinates, float trail_x, float trail_y) noexcept;
|
||||
Coordinates coordinates() const;
|
||||
void update(float trail_x, float trail_y) noexcept;
|
||||
void update() noexcept;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ ClassicTimeline::ClassicTimeline()
|
|||
|
||||
_music.openFromFile(song_filename);
|
||||
_music.setVolume(10);
|
||||
_last_timestamp = -1;
|
||||
}
|
||||
|
||||
void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility)
|
||||
|
@ -44,32 +45,37 @@ void ClassicTimeline::clear()
|
|||
void ClassicTimeline::update()
|
||||
{
|
||||
const auto& music_offset = currentMusicOffset();
|
||||
checkCurrentActiveNote(music_offset);
|
||||
checkForNextActiveNote(music_offset);
|
||||
updateVisibleSprites(music_offset);
|
||||
if (music_offset != _last_timestamp)
|
||||
{
|
||||
checkCurrentActiveNote();
|
||||
checkForNextActiveNote();
|
||||
updateVisibleSprites(music_offset);
|
||||
}
|
||||
|
||||
_last_timestamp = music_offset;
|
||||
}
|
||||
|
||||
void ClassicTimeline::checkCurrentActiveNote(const microsec& music_offset)
|
||||
void ClassicTimeline::checkCurrentActiveNote()
|
||||
{
|
||||
if (isExpired(_active_note))
|
||||
return;
|
||||
|
||||
auto note = *_active_note;
|
||||
|
||||
if (!note->isActive(music_offset))
|
||||
if (!note->isActive())
|
||||
{
|
||||
expire(_active_note);
|
||||
++_top_note;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicTimeline::checkForNextActiveNote(const microsec& music_offset)
|
||||
void ClassicTimeline::checkForNextActiveNote()
|
||||
{
|
||||
if (!isExpired(_active_note))
|
||||
return;
|
||||
|
||||
auto top_note = *_top_note;
|
||||
if (top_note->isActive(music_offset))
|
||||
if (top_note->isActive())
|
||||
_active_note = _top_note;
|
||||
}
|
||||
|
||||
|
@ -127,7 +133,7 @@ void ClassicTimeline::findLastVisibleNote(const microsec &music_offset)
|
|||
|
||||
auto note = *note_iterator;
|
||||
|
||||
if (note->isExpired())
|
||||
if (!note->isInGame())
|
||||
note->putToGame(music_offset);
|
||||
|
||||
++note_iterator;
|
||||
|
|
|
@ -33,12 +33,13 @@ private:
|
|||
std::vector<microsec> _input_intervals;
|
||||
std::vector<Note*> _timeline;
|
||||
microsec _visibility_offset;
|
||||
microsec _last_timestamp;
|
||||
|
||||
sf::Music _music;
|
||||
|
||||
void updateVisibleSprites(const microsec& music_offset);
|
||||
void checkCurrentActiveNote(const microsec& music_offset);
|
||||
void checkForNextActiveNote(const microsec& music_offset);
|
||||
void checkCurrentActiveNote();
|
||||
void checkForNextActiveNote();
|
||||
bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const;
|
||||
inline bool nothingToDraw() const noexcept;
|
||||
|
||||
|
|
Loading…
Reference in New Issue