From d9788b31b8ab6cf6373edc15d724420b6e09d749 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 21 Jun 2021 22:10:50 +0300 Subject: [PATCH] Encapsulate note switches into state objects --- CMakeLists.txt | 8 +- include/note.h | 7 +- src/application.cpp | 2 +- src/classicgame/classicnote.cpp | 89 +++++++++++-------- src/classicgame/classicnote.h | 24 ++--- .../classicnotestate/classicnotestate.h | 29 ++++++ src/classicgame/classictimeline.cpp | 25 +++--- src/classicgame/classictimeline.h | 6 +- 8 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 src/classicgame/classicnotestate/classicnotestate.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 214dd08..fab34fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/note.h b/include/note.h index ffd9165..b52298b 100644 --- a/include/note.h +++ b/include/note.h @@ -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; } diff --git a/src/application.cpp b/src/application.cpp index 282d375..0d41426 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -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()) { _game_window.setFramerateLimit(60); diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp index ed56c88..c9d7558 100644 --- a/src/classicgame/classicnote.cpp +++ b/src/classicgame/classicnote.cpp @@ -9,14 +9,27 @@ ClassicNote::ClassicNote(const std::vector& 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; + 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 ); @@ -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(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 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& sprite) noexcept { _sprite = sprite; - if (_sprite) - setState(State::FLYING); } const Coordinates& ClassicNote::getCoordinates() const noexcept diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h index f731baf..0670b5e 100644 --- a/src/classicgame/classicnote.h +++ b/src/classicgame/classicnote.h @@ -3,8 +3,10 @@ #include "note.h" #include "precisionevaluator.h" #include "classicinputtype.h" +#include "classicnotestate/classicnotestate.h" #include +#include struct Coordinates { @@ -30,28 +32,19 @@ public: BAD }; - enum class State - { - NONE, - - FLYING, - DYING, - DEAD - }; - explicit ClassicNote(const std::vector& 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 sprite() const noexcept; void saveAppearanceTime(const microsec& offset); @@ -62,10 +55,11 @@ private: const Coordinates _coordinates; const PrecisionEvaluator _evaluator; const Action _action; - State _state; std::shared_ptr _sprite; microsec _appearance_time; - microsec _last_offset; float _trail_path_percent; //100% for sprite falling trajectory + + std::array, ClassicNoteState::COUNT> _states; + ClassicNoteState::Value _current_state; }; diff --git a/src/classicgame/classicnotestate/classicnotestate.h b/src/classicgame/classicnotestate/classicnotestate.h new file mode 100644 index 0000000..3399faf --- /dev/null +++ b/src/classicgame/classicnotestate/classicnotestate.h @@ -0,0 +1,29 @@ +#ifndef CLASSICNOTESTATE_H +#define CLASSICNOTESTATE_H + +#include + +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 diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp index fad1be9..2337bb1 100644 --- a/src/classicgame/classictimeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -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_ptrsprite()) { - note->saveAppearanceTime(music_offset); graphics_manager->initSprite(note); + note->putToGame(music_offset); } ++note_iterator; @@ -177,9 +173,8 @@ void ClassicTimeline::discardGraphicsForDeadNotes(const std::unique_ptrstate() == ClassicNote::State::DEAD) + if (note->isExpired()) { - note->setState(ClassicNote::State::NONE); graphics_manager->resetSprite(note); ++_first_visible_note; diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h index defc5c5..acf85a7 100644 --- a/src/classicgame/classictimeline.h +++ b/src/classicgame/classictimeline.h @@ -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;