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; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										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.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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user