Fix animation objects and note state machine

This commit is contained in:
NaiJi ✨ 2021-06-24 21:04:09 +03:00
parent 06d099c11f
commit 77a9d15caa
17 changed files with 127 additions and 78 deletions

View File

@ -1,10 +1,8 @@
#ifndef INPUTTYPE_H #ifndef INPUTTYPE_H
#define INPUTTYPE_H #define INPUTTYPE_H
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include "mathutils.h"
using microsec = sf::Int64;
struct PlayerInput struct PlayerInput
{ {

38
include/mathutils.h Normal file
View File

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

View File

@ -1,13 +1,7 @@
#pragma once #pragma once
#include <vector>
#include <SFML/System/Clock.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include "inputtype.h" #include "inputtype.h"
using microsec = sf::Int64;
class Note class Note
{ {
public: public:
@ -15,12 +9,13 @@ public:
_perfect_offset(perfect_offset) {} _perfect_offset(perfect_offset) {}
virtual ~Note() = default; 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 update(const microsec& music_offset) = 0;
virtual void input(PlayerInput&& inputdata) = 0; virtual void input(PlayerInput&& inputdata) = 0;
virtual void draw() const = 0; virtual void draw() const = 0;
virtual void putToGame(const microsec &offset) = 0; virtual void putToGame(const microsec &offset) = 0;
virtual bool isInGame() const = 0;
virtual bool isExpired() const = 0; virtual bool isExpired() const = 0;
microsec offset() const microsec offset() const

View File

@ -1,16 +1,13 @@
#ifndef PRECISIONEVALUATOR_H #ifndef PRECISIONEVALUATOR_H
#define PRECISIONEVALUATOR_H #define PRECISIONEVALUATOR_H
#include "mathutils.h"
#include <numeric> #include <numeric>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <SFML/System/Clock.hpp>
using microsec = sf::Int64;
template<typename Grade, typename = std::enable_if_t<std::is_enum<Grade>::value>> template<typename Grade, typename = std::enable_if_t<std::is_enum<Grade>::value>>
class PrecisionEvaluator class PrecisionEvaluator
{ {

View File

@ -1,11 +1,9 @@
#ifndef TIMELINE_H #ifndef TIMELINE_H
#define TIMELINE_H #define TIMELINE_H
#include <SFML/Graphics/RenderWindow.hpp> #include "mathutils.h"
#include <SFML/Config.hpp>
#include <memory> #include <memory>
#include <vector>
using microsec = sf::Int64;
class Note; class Note;

View File

@ -4,6 +4,8 @@
#include "classicgame/classicgame.h" #include "classicgame/classicgame.h"
#include "classicgame/classicgraphicsmanager.h" #include "classicgame/classicgraphicsmanager.h"
#include <iostream>
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f); const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
Application::Application() : Application::Application() :
@ -27,7 +29,6 @@ void Application::run()
void Application::exec() void Application::exec()
{ {
sf::Clock timer; sf::Clock timer;
sf::Clock game_timer;
sf::Time time_since_last_update = sf::Time::Zero; sf::Time time_since_last_update = sf::Time::Zero;
while (_game_window.isOpen()) while (_game_window.isOpen())
@ -41,7 +42,6 @@ void Application::exec()
if (isOneFramePassed) if (isOneFramePassed)
{ {
time_since_last_update -= TIME_PER_FRAME; time_since_last_update -= TIME_PER_FRAME;
game_timer.restart();
update(); update();
draw(); draw();
} }

View File

@ -1,10 +1,8 @@
#pragma once #pragma once
#include <SFML/Config.hpp> #include "mathutils.h"
#include <memory> #include <memory>
using microsec = sf::Int64;
class ClassicSprite; class ClassicSprite;
class ClassicAnimationScenario class ClassicAnimationScenario

View File

@ -24,10 +24,10 @@ void ClassicFlyingAnimationScenario::update(const microsec& music_offset)
auto update_time = music_offset - _time_begin; auto update_time = music_offset - _time_begin;
i = update_time / _percentage * 0.01; i = update_time / _percentage * 0.01;
float xa = getPoint( crd.first + 20. , crd.first + 90. , i ); float xa = getPoint( crd.x + 20. , crd.x + 90. , i );
float ya = getPoint( crd.second - 600. , crd.second - 150. , i ); float ya = getPoint( crd.y - 600. , crd.y - 150. , i );
float xb = getPoint( crd.first + 90. , crd.first , i ); float xb = getPoint( crd.x + 90. , crd.x , i );
float yb = getPoint( crd.second - 150. , crd.second , i ); float yb = getPoint( crd.y - 150. , crd.y , i );
_sprite->update(getPoint( xa , xb , i ), getPoint( ya , yb , i )); _sprite->update(getPoint( xa , xb , i ), getPoint( ya , yb , i ));
if (i >= 1) if (i >= 1)

View File

@ -11,12 +11,13 @@ ClassicGraphicsManager::ClassicGraphicsManager(sf::RenderTarget& target) :
void ClassicGraphicsManager::initGraphics(ClassicNote* note) void ClassicGraphicsManager::initGraphics(ClassicNote* note)
{ {
note->setSprite(_sprite_container.getSprite(note->type())); 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) void ClassicGraphicsManager::resetGraphics(ClassicNote* note)
{ {
_sprite_container.resetSprite(note->sprite(), note->type()); _sprite_container.resetSprite(note->sprite(), note->type());
note->setSprite(nullptr);
} }
void ClassicGraphicsManager::draw(const ClassicNote *note) void ClassicGraphicsManager::draw(const ClassicNote *note)

View File

@ -12,7 +12,7 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
microsec starting_beat_offset = 352162; microsec starting_beat_offset = 352162;
int amount_of_beats = 209; int amount_of_beats = 209;
microsec interval = 1412162; microsec interval = 1412162;
microsec tempo_interval = interval / 2; microsec tempo_interval = interval / 4;
microsec note_input_offset = 412162 / 3; microsec note_input_offset = 412162 / 3;
microsec bpm_iterator = starting_beat_offset; microsec bpm_iterator = starting_beat_offset;
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats); microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);

View File

@ -3,7 +3,6 @@
#include "classicgraphicsmanager.h" #include "classicgraphicsmanager.h"
#include "classicflyinganimationscenario.h" #include "classicflyinganimationscenario.h"
#include "classicdyinganimationscenario.h" #include "classicdyinganimationscenario.h"
#include <iostream>
ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset,
Type type, const Coordinates& coord, const std::unique_ptr<ClassicGraphicsManager> &manager) : 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), _evaluator(intervals, _perfect_offset),
_keys({sf::Keyboard::W, sf::Keyboard::Up}), _keys({sf::Keyboard::W, sf::Keyboard::Up}),
_graphics_manager(manager), _graphics_manager(manager),
_is_expired(true),
_type(type), _type(type),
_state(State::NONE) _state(State::NONE)
{ {
_animations[State::NONE] = nullptr; _animations[State::NONE] = nullptr;
_animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>(); _animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
_animations[State::ACTIVE] = _animations[State::FLYING];
_animations[State::DYING] = std::make_shared<ClassicDyingAnimationScenario>(); _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) void ClassicNote::putToGame(const microsec &music_offset)
{ {
_is_expired = false;
_graphics_manager->initGraphics(this); _graphics_manager->initGraphics(this);
_state = State::FLYING; _state = State::FLYING;
_animations[_state]->launch(_sprite, music_offset, offset()); _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 bool ClassicNote::isExpired() const
{ {
return _is_expired; return _state == State::DEAD;
} }
void ClassicNote::update(const microsec& music_offset) void ClassicNote::update(const microsec& music_offset)
{ {
if (!_animations[_state]) switch (_state)
return; {
default: return;
break;
bool is_not_active_anymore = (!_is_expired && !isActive(music_offset)); case State::FLYING:
if (_evaluator.isActive(music_offset))
_state = State::ACTIVE;
break;
if (is_not_active_anymore) case State::DYING:
if (_animations[_state]->isDone())
_state = State::DEAD;
break;
case State::ACTIVE:
if (!_evaluator.isActive(music_offset))
{ {
_state = State::DYING; _state = State::DYING;
_animations[_state]->launch(_sprite, music_offset, offset()); _animations[_state]->launch(_sprite, music_offset, offset());
} }
break;
}
if (_animations[_state])
_animations[_state]->update(music_offset); _animations[_state]->update(music_offset);
_is_expired = _animations[_state]->isDone();
} }
void ClassicNote::input(PlayerInput&& inputdata) void ClassicNote::input(PlayerInput&& inputdata)

View File

@ -7,17 +7,6 @@
#include <memory> #include <memory>
#include <array> #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 ClassicSprite;
class ClassicGraphicsManager; class ClassicGraphicsManager;
class ClassicAnimationScenario; class ClassicAnimationScenario;
@ -38,7 +27,9 @@ public:
NONE, NONE,
FLYING, FLYING,
DYING ACTIVE,
DYING,
DEAD
}; };
explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset,
@ -46,10 +37,11 @@ public:
const std::unique_ptr<ClassicGraphicsManager>& manager); const std::unique_ptr<ClassicGraphicsManager>& manager);
virtual ~ClassicNote() = default; 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 update(const microsec &music_offset) override;
virtual void input(PlayerInput&& inputdata) override; virtual void input(PlayerInput&& inputdata) override;
virtual void putToGame(const microsec &music_offset) override; virtual void putToGame(const microsec &music_offset) override;
virtual bool isInGame() const override;
virtual bool isExpired() const override; virtual bool isExpired() const override;
virtual void draw() const override; virtual void draw() const override;
@ -67,9 +59,8 @@ private:
const std::unique_ptr<ClassicGraphicsManager>& _graphics_manager; const std::unique_ptr<ClassicGraphicsManager>& _graphics_manager;
std::shared_ptr<ClassicSprite> _sprite; std::shared_ptr<ClassicSprite> _sprite;
bool _is_expired;
const Type _type; const Type _type;
State _state; State _state;
std::array<std::shared_ptr<ClassicAnimationScenario>, 3> _animations; std::array<std::shared_ptr<ClassicAnimationScenario>, 5> _animations;
}; };

View File

@ -29,16 +29,16 @@ void ClassicSprite::reset()
_trail_fade = false; _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); _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 void ClassicSprite::update(float trail_x, float trail_y) noexcept
@ -76,8 +76,12 @@ void ClassicSprite::fade()
{ {
auto fill_color = _grade_text.getFillColor(); 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; return;
}
auto new_alpha = fill_color.a - 15; auto new_alpha = fill_color.a - 15;
fill_color.a = new_alpha < 0 ? 0 : new_alpha; fill_color.a = new_alpha < 0 ? 0 : new_alpha;
@ -87,7 +91,11 @@ void ClassicSprite::fade()
fill_color = _shape.getFillColor(); fill_color = _shape.getFillColor();
if (fill_color.a == 0) if (fill_color.a == 0)
{
fill_color.a = 0;
_shape.setFillColor(fill_color);
return; return;
}
new_alpha = fill_color.a - 15; new_alpha = fill_color.a - 15;
fill_color.a = new_alpha < 0 ? 0 : new_alpha; fill_color.a = new_alpha < 0 ? 0 : new_alpha;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "mathutils.h"
#include "sprite.h" #include "sprite.h"
#include "SFML/Graphics/RectangleShape.hpp" #include "SFML/Graphics/RectangleShape.hpp"
#include "SFML/Graphics/Text.hpp" #include "SFML/Graphics/Text.hpp"
@ -11,8 +12,8 @@ public:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void reset() override; virtual void reset() override;
void setCoordinates(float x, float y, float trail_x, float trail_y) noexcept; void setCoordinates(const Coordinates &coordinates, float trail_x, float trail_y) noexcept;
std::pair<float, float> coordinates() const; Coordinates coordinates() const;
void update(float trail_x, float trail_y) noexcept; void update(float trail_x, float trail_y) noexcept;
void update() noexcept; void update() noexcept;

View File

@ -12,6 +12,7 @@ ClassicTimeline::ClassicTimeline()
_music.openFromFile(song_filename); _music.openFromFile(song_filename);
_music.setVolume(10); _music.setVolume(10);
_last_timestamp = -1;
} }
void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility) void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility)
@ -44,32 +45,37 @@ void ClassicTimeline::clear()
void ClassicTimeline::update() void ClassicTimeline::update()
{ {
const auto& music_offset = currentMusicOffset(); const auto& music_offset = currentMusicOffset();
checkCurrentActiveNote(music_offset); if (music_offset != _last_timestamp)
checkForNextActiveNote(music_offset); {
checkCurrentActiveNote();
checkForNextActiveNote();
updateVisibleSprites(music_offset); updateVisibleSprites(music_offset);
} }
void ClassicTimeline::checkCurrentActiveNote(const microsec& music_offset) _last_timestamp = music_offset;
}
void ClassicTimeline::checkCurrentActiveNote()
{ {
if (isExpired(_active_note)) if (isExpired(_active_note))
return; return;
auto note = *_active_note; auto note = *_active_note;
if (!note->isActive(music_offset)) if (!note->isActive())
{ {
expire(_active_note); expire(_active_note);
++_top_note; ++_top_note;
} }
} }
void ClassicTimeline::checkForNextActiveNote(const microsec& music_offset) void ClassicTimeline::checkForNextActiveNote()
{ {
if (!isExpired(_active_note)) if (!isExpired(_active_note))
return; return;
auto top_note = *_top_note; auto top_note = *_top_note;
if (top_note->isActive(music_offset)) if (top_note->isActive())
_active_note = _top_note; _active_note = _top_note;
} }
@ -127,7 +133,7 @@ void ClassicTimeline::findLastVisibleNote(const microsec &music_offset)
auto note = *note_iterator; auto note = *note_iterator;
if (note->isExpired()) if (!note->isInGame())
note->putToGame(music_offset); note->putToGame(music_offset);
++note_iterator; ++note_iterator;

View File

@ -33,12 +33,13 @@ private:
std::vector<microsec> _input_intervals; std::vector<microsec> _input_intervals;
std::vector<Note*> _timeline; std::vector<Note*> _timeline;
microsec _visibility_offset; microsec _visibility_offset;
microsec _last_timestamp;
sf::Music _music; sf::Music _music;
void updateVisibleSprites(const microsec& music_offset); void updateVisibleSprites(const microsec& music_offset);
void checkCurrentActiveNote(const microsec& music_offset); void checkCurrentActiveNote();
void checkForNextActiveNote(const microsec& music_offset); void checkForNextActiveNote();
bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const;
inline bool nothingToDraw() const noexcept; inline bool nothingToDraw() const noexcept;