forked from NaiJi/project-kyoku
Encapsulate note switches into state objects
This commit is contained in:
parent
89a80992cb
commit
d9788b31b8
|
@ -5,7 +5,13 @@ project(project-kyoku LANGUAGES CXX)
|
|||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g")
|
||||
file(GLOB SOURCES "src/*.cpp" "src/classicgame/*")
|
||||
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
set(CMAKE_USE_WIN32_THREADS_INIT 0)
|
||||
set(CMAKE_USE_PTHREADS_INIT 1)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
file(GLOB SOURCES "src/*.cpp" "src/classicgame/*.*" "src/classicgame/classicnotestate/*")
|
||||
|
||||
# STATIC #
|
||||
# You need to build SFML from sources with cmake
|
||||
|
|
|
@ -13,11 +13,14 @@ 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 draw(sf::RenderTarget& target, sf::RenderStates states) const = 0;
|
||||
|
||||
virtual microsec offset() const
|
||||
virtual void putToGame(const microsec &offset) = 0;
|
||||
virtual bool isExpired() const = 0;
|
||||
|
||||
microsec offset() const
|
||||
{
|
||||
return _perfect_offset;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
||||
|
||||
Application::Application() :
|
||||
_game_window({1280, 720}, "Test", sf::Style::Fullscreen ),
|
||||
_game_window({1280, 720}, "Test", sf::Style::Default ),
|
||||
_game(std::make_unique<ClassicGame>())
|
||||
{
|
||||
_game_window.setFramerateLimit(60);
|
||||
|
|
|
@ -9,14 +9,27 @@ ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfec
|
|||
_coordinates(coord),
|
||||
_evaluator(intervals, _perfect_offset),
|
||||
_action(action),
|
||||
_state(State::NONE),
|
||||
_appearance_time(0),
|
||||
_last_offset(0)
|
||||
_current_state(ClassicNoteState::NONE)
|
||||
{}
|
||||
|
||||
bool ClassicNote::isActive(const microsec& music_offset) const
|
||||
bool ClassicNote::isActive() const
|
||||
{
|
||||
return _evaluator.isActive(music_offset);
|
||||
return _states.at(_current_state)->value() == ClassicNoteState::ACTIVE;
|
||||
}
|
||||
|
||||
void ClassicNote::putToGame(const microsec &offset)
|
||||
{
|
||||
_appearance_time = offset; // To animation manager
|
||||
_trail_path_percent = ((_perfect_offset - _appearance_time) * 0.01);
|
||||
|
||||
_current_state = ClassicNoteState::FLYING;
|
||||
_states.at(_current_state)->onEntering(this);
|
||||
}
|
||||
|
||||
bool ClassicNote::isExpired() const
|
||||
{
|
||||
return _states.at(_current_state)->value() == ClassicNoteState::NONE;
|
||||
}
|
||||
|
||||
static int getPt( float n1 , float n2 , float perc )
|
||||
|
@ -28,29 +41,20 @@ static int getPt( float n1 , float n2 , float perc )
|
|||
|
||||
void ClassicNote::update(const microsec& music_offset)
|
||||
{
|
||||
switch (_state) // States will be objects
|
||||
_states.at(_current_state)->update(this, music_offset);
|
||||
/*switch (_state) // States will be objects
|
||||
{
|
||||
case State::DYING:
|
||||
_sprite->update();
|
||||
if (_sprite->isDead())
|
||||
setState(State::DEAD);
|
||||
setState(State::NONE);
|
||||
break;
|
||||
|
||||
case State::FLYING:
|
||||
{
|
||||
float i;
|
||||
if (music_offset != _last_offset)
|
||||
{
|
||||
auto update_time = music_offset - _appearance_time; // This all will be inside ::update
|
||||
i = update_time / _trail_path_percent * 0.01; // of an animation object
|
||||
}
|
||||
else
|
||||
{
|
||||
auto update_time = music_offset + 10000 - _appearance_time;
|
||||
i = update_time / _trail_path_percent * 0.01;
|
||||
}
|
||||
|
||||
_last_offset = music_offset;
|
||||
|
||||
float xa = getPt( _coordinates.x + 20. , _coordinates.x + 90. , i );
|
||||
float ya = getPt( _coordinates.y - 600. , _coordinates.y - 150. , i );
|
||||
|
@ -59,13 +63,40 @@ void ClassicNote::update(const microsec& music_offset)
|
|||
|
||||
_sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i ));
|
||||
if (i >= 1)
|
||||
{
|
||||
_sprite->trailFade();
|
||||
}
|
||||
|
||||
if (_evaluator.isActive(music_offset))
|
||||
setState(State::ACTIVE);
|
||||
break;
|
||||
}
|
||||
|
||||
case State::ACTIVE:
|
||||
{
|
||||
float i;
|
||||
auto update_time = music_offset - _appearance_time; // This all will be inside ::update
|
||||
i = update_time / _trail_path_percent * 0.01; // of an animation object
|
||||
|
||||
float xa = getPt( _coordinates.x + 20. , _coordinates.x + 90. , i );
|
||||
float ya = getPt( _coordinates.y - 600. , _coordinates.y - 150. , i );
|
||||
float xb = getPt( _coordinates.x + 90. , _coordinates.x , i );
|
||||
float yb = getPt( _coordinates.y - 150. , _coordinates.y , i );
|
||||
|
||||
_sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i ));
|
||||
if (i >= 1)
|
||||
{
|
||||
_sprite->trailFade();
|
||||
}
|
||||
|
||||
if (!_evaluator.isActive(music_offset))
|
||||
setState(State::DYING);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
void ClassicNote::draw(sf::RenderTarget& target, sf::RenderStates states) const
|
||||
|
@ -80,7 +111,8 @@ auto ClassicNote::input(ClassicInputType&& input_data) -> Grade
|
|||
if (input_data == _action)
|
||||
grade = _evaluator.calculatePrecision(input_data.timestamp());
|
||||
|
||||
setState(State::DYING);
|
||||
_current_state = ClassicNoteState::DYING;
|
||||
_states.at(_current_state)->onEntering(this);
|
||||
|
||||
std::cout << "User input: " << static_cast<int>(grade) << "\n";
|
||||
|
||||
|
@ -92,12 +124,7 @@ Action ClassicNote::action() const
|
|||
return _action;
|
||||
}
|
||||
|
||||
auto ClassicNote::state() const -> State
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
void ClassicNote::setState(State next_state)
|
||||
/*void ClassicNote::setState(State next_state)
|
||||
{
|
||||
switch (next_state) // States will be objects
|
||||
{
|
||||
|
@ -118,24 +145,16 @@ void ClassicNote::setState(State next_state)
|
|||
}
|
||||
|
||||
_state = next_state;
|
||||
}
|
||||
} */
|
||||
|
||||
std::shared_ptr<ClassicSprite> ClassicNote::sprite() const noexcept
|
||||
{
|
||||
return _sprite;
|
||||
}
|
||||
|
||||
void ClassicNote::saveAppearanceTime(const microsec &offset)
|
||||
{
|
||||
_appearance_time = offset;
|
||||
_trail_path_percent = ((_perfect_offset - _appearance_time) * 0.01);
|
||||
}
|
||||
|
||||
void ClassicNote::setSprite(const std::shared_ptr<ClassicSprite>& sprite) noexcept
|
||||
{
|
||||
_sprite = sprite;
|
||||
if (_sprite)
|
||||
setState(State::FLYING);
|
||||
}
|
||||
|
||||
const Coordinates& ClassicNote::getCoordinates() const noexcept
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
#include "note.h"
|
||||
#include "precisionevaluator.h"
|
||||
#include "classicinputtype.h"
|
||||
#include "classicnotestate/classicnotestate.h"
|
||||
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
struct Coordinates
|
||||
{
|
||||
|
@ -30,28 +32,19 @@ public:
|
|||
BAD
|
||||
};
|
||||
|
||||
enum class State
|
||||
{
|
||||
NONE,
|
||||
|
||||
FLYING,
|
||||
DYING,
|
||||
DEAD
|
||||
};
|
||||
|
||||
explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset,
|
||||
Action action, const Coordinates& coord);
|
||||
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 draw(sf::RenderTarget& target, sf::RenderStates states) const override;
|
||||
|
||||
virtual void putToGame(const microsec &offset) override;
|
||||
virtual bool isExpired() const override;
|
||||
|
||||
Grade input(ClassicInputType&& input_data);
|
||||
Action action() const;
|
||||
State state() const;
|
||||
|
||||
void setState(State next_state);
|
||||
|
||||
std::shared_ptr<ClassicSprite> sprite() const noexcept;
|
||||
void saveAppearanceTime(const microsec& offset);
|
||||
|
@ -62,10 +55,11 @@ private:
|
|||
const Coordinates _coordinates;
|
||||
const PrecisionEvaluator<Grade> _evaluator;
|
||||
const Action _action;
|
||||
State _state;
|
||||
|
||||
std::shared_ptr<ClassicSprite> _sprite;
|
||||
microsec _appearance_time;
|
||||
microsec _last_offset;
|
||||
float _trail_path_percent; //100% for sprite falling trajectory
|
||||
|
||||
std::array<std::shared_ptr<ClassicNoteState>, ClassicNoteState::COUNT> _states;
|
||||
ClassicNoteState::Value _current_state;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CLASSICNOTESTATE_H
|
||||
#define CLASSICNOTESTATE_H
|
||||
|
||||
#include <SFML/System/Clock.hpp>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
class ClassicNote;
|
||||
|
||||
class ClassicNoteState
|
||||
{
|
||||
public:
|
||||
|
||||
enum Value
|
||||
{
|
||||
NONE,
|
||||
DYING,
|
||||
FLYING,
|
||||
ACTIVE,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
virtual Value value() const = 0;
|
||||
virtual Value update(const ClassicNote* note, const microsec& offset) = 0;
|
||||
virtual void onEntering(const ClassicNote* note) = 0;
|
||||
};
|
||||
|
||||
#endif // CLASSICNOTESTATE_H
|
|
@ -18,12 +18,10 @@ ClassicTimeline::ClassicTimeline()
|
|||
_music.openFromFile(song_filename);
|
||||
_music.setVolume(10);
|
||||
|
||||
_timeline.reserve(1000);
|
||||
|
||||
microsec starting_beat_offset = 352162;
|
||||
int amount_of_beats = 209;
|
||||
microsec interval = 1412162;
|
||||
microsec tempo_interval = interval / 4;
|
||||
microsec tempo_interval = interval / 2;
|
||||
microsec note_input_offset = 412162 / 3;
|
||||
microsec bpm_iterator = starting_beat_offset;
|
||||
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
|
||||
|
@ -71,34 +69,32 @@ void ClassicTimeline::clear()
|
|||
|
||||
void ClassicTimeline::update()
|
||||
{
|
||||
const microsec& offset = currentMusicOffset();
|
||||
checkCurrentActiveNote(offset);
|
||||
checkForNextActiveNote(offset);
|
||||
updateVisibleSprites(offset);
|
||||
checkCurrentActiveNote();
|
||||
checkForNextActiveNote();
|
||||
updateVisibleSprites(currentMusicOffset());
|
||||
}
|
||||
|
||||
void ClassicTimeline::checkCurrentActiveNote(const microsec& music_offset)
|
||||
void ClassicTimeline::checkCurrentActiveNote()
|
||||
{
|
||||
if (isExpired(_active_note))
|
||||
return;
|
||||
|
||||
auto note = *_active_note;
|
||||
|
||||
if (note->state() != ClassicNote::State::FLYING || !note->isActive(music_offset))
|
||||
if (!note->isActive())
|
||||
{
|
||||
note->setState(ClassicNote::State::DYING);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -158,8 +154,8 @@ void ClassicTimeline::initGraphicsForNewNotes(const std::unique_ptr<ClassicGraph
|
|||
|
||||
if (!note->sprite())
|
||||
{
|
||||
note->saveAppearanceTime(music_offset);
|
||||
graphics_manager->initSprite(note);
|
||||
note->putToGame(music_offset);
|
||||
}
|
||||
|
||||
++note_iterator;
|
||||
|
@ -177,9 +173,8 @@ void ClassicTimeline::discardGraphicsForDeadNotes(const std::unique_ptr<ClassicG
|
|||
while (note_iterator != _last_visible_note)
|
||||
{
|
||||
auto note = *note_iterator;
|
||||
if (note->state() == ClassicNote::State::DEAD)
|
||||
if (note->isExpired())
|
||||
{
|
||||
note->setState(ClassicNote::State::NONE);
|
||||
graphics_manager->resetSprite(note);
|
||||
|
||||
++_first_visible_note;
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
Iterator getActiveNote() noexcept;
|
||||
|
||||
inline bool isExpired(const Iterator& iterator) const;
|
||||
bool isExpired(const Iterator& iterator) const;
|
||||
inline void expire(Iterator& iterator);
|
||||
|
||||
private:
|
||||
|
@ -39,8 +39,8 @@ private:
|
|||
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