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 14) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g") | 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 # | # STATIC # | ||||||
| # You need to build SFML from sources with cmake | # You need to build SFML from sources with cmake | ||||||
|  | |||||||
| @ -13,11 +13,14 @@ 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 draw(sf::RenderTarget& target, sf::RenderStates states) const = 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; |         return _perfect_offset; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
| 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() : | ||||||
|     _game_window({1280, 720}, "Test", sf::Style::Fullscreen ), |     _game_window({1280, 720}, "Test", sf::Style::Default ), | ||||||
|     _game(std::make_unique<ClassicGame>()) |     _game(std::make_unique<ClassicGame>()) | ||||||
| { | { | ||||||
|     _game_window.setFramerateLimit(60); |     _game_window.setFramerateLimit(60); | ||||||
|  | |||||||
| @ -9,14 +9,27 @@ ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfec | |||||||
|     _coordinates(coord), |     _coordinates(coord), | ||||||
|     _evaluator(intervals, _perfect_offset), |     _evaluator(intervals, _perfect_offset), | ||||||
|     _action(action), |     _action(action), | ||||||
|     _state(State::NONE), |  | ||||||
|     _appearance_time(0), |     _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 ) | 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) | 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: |     case State::DYING: | ||||||
|         _sprite->update(); |         _sprite->update(); | ||||||
|         if (_sprite->isDead()) |         if (_sprite->isDead()) | ||||||
|             setState(State::DEAD); |             setState(State::NONE); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case State::FLYING: |     case State::FLYING: | ||||||
|     { |     { | ||||||
|         float i; |         float i; | ||||||
|         if (music_offset != _last_offset) |  | ||||||
|         { |  | ||||||
|         auto update_time = music_offset - _appearance_time;   // This all will be inside ::update
 |         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
 |         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 xa = getPt( _coordinates.x + 20.  , _coordinates.x + 90. , i ); | ||||||
|         float ya = getPt( _coordinates.y - 600. , _coordinates.y - 150. , 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 )); |         _sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i )); | ||||||
|         if (i >= 1) |         if (i >= 1) | ||||||
|  |         { | ||||||
|             _sprite->trailFade(); |             _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; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClassicNote::draw(sf::RenderTarget& target, sf::RenderStates states) const | 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) |     if (input_data == _action) | ||||||
|         grade = _evaluator.calculatePrecision(input_data.timestamp()); |         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"; |     std::cout << "User input: " << static_cast<int>(grade) << "\n"; | ||||||
| 
 | 
 | ||||||
| @ -92,12 +124,7 @@ Action ClassicNote::action() const | |||||||
|     return _action; |     return _action; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| auto ClassicNote::state() const -> State | /*void ClassicNote::setState(State next_state)
 | ||||||
| { |  | ||||||
|     return _state; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ClassicNote::setState(State next_state) |  | ||||||
| { | { | ||||||
|     switch (next_state)   // States will be objects
 |     switch (next_state)   // States will be objects
 | ||||||
|     { |     { | ||||||
| @ -118,24 +145,16 @@ void ClassicNote::setState(State next_state) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     _state = next_state; |     _state = next_state; | ||||||
| } | } */ | ||||||
| 
 | 
 | ||||||
| std::shared_ptr<ClassicSprite> ClassicNote::sprite() const noexcept | std::shared_ptr<ClassicSprite> ClassicNote::sprite() const noexcept | ||||||
| { | { | ||||||
|     return _sprite; |     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 | void ClassicNote::setSprite(const std::shared_ptr<ClassicSprite>& sprite) noexcept | ||||||
| { | { | ||||||
|     _sprite = sprite; |     _sprite = sprite; | ||||||
|     if (_sprite) |  | ||||||
|         setState(State::FLYING); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const Coordinates& ClassicNote::getCoordinates() const noexcept | const Coordinates& ClassicNote::getCoordinates() const noexcept | ||||||
|  | |||||||
| @ -3,8 +3,10 @@ | |||||||
| #include "note.h" | #include "note.h" | ||||||
| #include "precisionevaluator.h" | #include "precisionevaluator.h" | ||||||
| #include "classicinputtype.h" | #include "classicinputtype.h" | ||||||
|  | #include "classicnotestate/classicnotestate.h" | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <array> | ||||||
| 
 | 
 | ||||||
| struct Coordinates | struct Coordinates | ||||||
| { | { | ||||||
| @ -30,28 +32,19 @@ public: | |||||||
|             BAD |             BAD | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     enum class State |  | ||||||
|     { |  | ||||||
|           NONE, |  | ||||||
| 
 |  | ||||||
|         FLYING, |  | ||||||
|          DYING, |  | ||||||
|           DEAD |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, |     explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, | ||||||
|                          Action action, const Coordinates& coord); |                          Action action, const Coordinates& coord); | ||||||
|     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 draw(sf::RenderTarget& target, sf::RenderStates states) const 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); |     Grade input(ClassicInputType&& input_data); | ||||||
|     Action action() const; |     Action action() const; | ||||||
|     State state() const; |  | ||||||
| 
 |  | ||||||
|     void setState(State next_state); |  | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<ClassicSprite> sprite() const noexcept; |     std::shared_ptr<ClassicSprite> sprite() const noexcept; | ||||||
|     void saveAppearanceTime(const microsec& offset); |     void saveAppearanceTime(const microsec& offset); | ||||||
| @ -62,10 +55,11 @@ private: | |||||||
|     const Coordinates _coordinates; |     const Coordinates _coordinates; | ||||||
|     const PrecisionEvaluator<Grade> _evaluator; |     const PrecisionEvaluator<Grade> _evaluator; | ||||||
|     const Action _action; |     const Action _action; | ||||||
|     State _state; |  | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<ClassicSprite> _sprite; |     std::shared_ptr<ClassicSprite> _sprite; | ||||||
|     microsec _appearance_time; |     microsec _appearance_time; | ||||||
|     microsec _last_offset; |  | ||||||
|     float _trail_path_percent; //100% for sprite falling trajectory
 |     float _trail_path_percent; //100% for sprite falling trajectory
 | ||||||
|  | 
 | ||||||
|  |     std::array<std::shared_ptr<ClassicNoteState>, ClassicNoteState::COUNT> _states; | ||||||
|  |     ClassicNoteState::Value _current_state; | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								src/classicgame/classicnotestate/classicnotestate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/classicgame/classicnotestate/classicnotestate.h
									
									
									
									
									
										Normal file
									
								
							| @ -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.openFromFile(song_filename); | ||||||
|     _music.setVolume(10); |     _music.setVolume(10); | ||||||
| 
 | 
 | ||||||
|     _timeline.reserve(1000); |  | ||||||
| 
 |  | ||||||
|     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 / 4; |     microsec tempo_interval = interval / 2; | ||||||
|     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); | ||||||
| @ -71,34 +69,32 @@ void ClassicTimeline::clear() | |||||||
| 
 | 
 | ||||||
| void ClassicTimeline::update() | void ClassicTimeline::update() | ||||||
| { | { | ||||||
|     const microsec& offset = currentMusicOffset(); |     checkCurrentActiveNote(); | ||||||
|     checkCurrentActiveNote(offset); |     checkForNextActiveNote(); | ||||||
|     checkForNextActiveNote(offset); |     updateVisibleSprites(currentMusicOffset()); | ||||||
|     updateVisibleSprites(offset); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClassicTimeline::checkCurrentActiveNote(const microsec& 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->state() != ClassicNote::State::FLYING || !note->isActive(music_offset)) |     if (!note->isActive()) | ||||||
|     { |     { | ||||||
|         note->setState(ClassicNote::State::DYING); |  | ||||||
|         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; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -158,8 +154,8 @@ void ClassicTimeline::initGraphicsForNewNotes(const std::unique_ptr<ClassicGraph | |||||||
| 
 | 
 | ||||||
|         if (!note->sprite()) |         if (!note->sprite()) | ||||||
|         { |         { | ||||||
|             note->saveAppearanceTime(music_offset); |  | ||||||
|             graphics_manager->initSprite(note); |             graphics_manager->initSprite(note); | ||||||
|  |             note->putToGame(music_offset); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ++note_iterator; |         ++note_iterator; | ||||||
| @ -177,9 +173,8 @@ void ClassicTimeline::discardGraphicsForDeadNotes(const std::unique_ptr<ClassicG | |||||||
|     while (note_iterator != _last_visible_note) |     while (note_iterator != _last_visible_note) | ||||||
|     { |     { | ||||||
|         auto note = *note_iterator; |         auto note = *note_iterator; | ||||||
|         if (note->state() == ClassicNote::State::DEAD) |         if (note->isExpired()) | ||||||
|         { |         { | ||||||
|             note->setState(ClassicNote::State::NONE); |  | ||||||
|             graphics_manager->resetSprite(note); |             graphics_manager->resetSprite(note); | ||||||
| 
 | 
 | ||||||
|             ++_first_visible_note; |             ++_first_visible_note; | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ public: | |||||||
| 
 | 
 | ||||||
|     Iterator getActiveNote() noexcept; |     Iterator getActiveNote() noexcept; | ||||||
| 
 | 
 | ||||||
|     inline bool isExpired(const Iterator& iterator) const; |     bool isExpired(const Iterator& iterator) const; | ||||||
|     inline void expire(Iterator& iterator); |     inline void expire(Iterator& iterator); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| @ -39,8 +39,8 @@ private: | |||||||
|     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; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user