Implement smoother animation and fullscreen
This commit is contained in:
		
							parent
							
								
									cbe0fbb673
								
							
						
					
					
						commit
						89a80992cb
					
				| @ -20,7 +20,7 @@ public: | |||||||
| private: | private: | ||||||
|     sf::RenderWindow _game_window; |     sf::RenderWindow _game_window; | ||||||
|     std::unique_ptr<Timeline> _timeline; |     std::unique_ptr<Timeline> _timeline; | ||||||
|     std::unique_ptr<Game> _game; |     std::shared_ptr<Game> _game; | ||||||
| 
 | 
 | ||||||
|     void exec(); |     void exec(); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <cmath> | #include <cmath> | ||||||
|  | #include <iostream> | ||||||
| 
 | 
 | ||||||
| #include <SFML/System/Clock.hpp> | #include <SFML/System/Clock.hpp> | ||||||
| 
 | 
 | ||||||
| @ -18,9 +19,8 @@ public: | |||||||
|         _offset(offset), |         _offset(offset), | ||||||
|         _intervals(intervals) |         _intervals(intervals) | ||||||
|     { |     { | ||||||
|         microsec&& handling_offset = std::accumulate(intervals.begin(), intervals.end(), 0); |         _start_handling_offset = _offset - intervals.back(); | ||||||
|         _start_handling_offset = _offset - handling_offset; |         _end_handling_offset = _offset + intervals.back(); | ||||||
|         _end_handling_offset = _offset + handling_offset; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline microsec offset() const noexcept |     inline microsec offset() const noexcept | ||||||
| @ -38,6 +38,8 @@ public: | |||||||
|     { |     { | ||||||
|         microsec shift_from_perfect = std::abs(odds - offset()); |         microsec shift_from_perfect = std::abs(odds - offset()); | ||||||
| 
 | 
 | ||||||
|  |         std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ") << shift_from_perfect << "\n"; | ||||||
|  | 
 | ||||||
|         std::size_t raw_grade; |         std::size_t raw_grade; | ||||||
|         for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade) |         for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade) | ||||||
|         { |         { | ||||||
|  | |||||||
| @ -2,13 +2,21 @@ | |||||||
| #include "classicgame/classicgame.h" | #include "classicgame/classicgame.h" | ||||||
| #include <SFML/Graphics/Color.hpp> | #include <SFML/Graphics/Color.hpp> | ||||||
| #include <SFML/Window/Event.hpp> | #include <SFML/Window/Event.hpp> | ||||||
|  | #include <SFML/Window/ContextSettings.hpp> | ||||||
|  | #include <iostream> | ||||||
|  | #include <future> | ||||||
| 
 | 
 | ||||||
| const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f); | const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f); | ||||||
| 
 | 
 | ||||||
| Application::Application() : | Application::Application() : | ||||||
|     _game_window({1280, 720}, "Test"), |     _game_window({1280, 720}, "Test", sf::Style::Fullscreen ), | ||||||
|     _game(std::make_unique<ClassicGame>()) |     _game(std::make_unique<ClassicGame>()) | ||||||
| {} | { | ||||||
|  |     _game_window.setFramerateLimit(60); | ||||||
|  |     _game_window.setKeyRepeatEnabled(false); | ||||||
|  |     _game_window.setMouseCursorGrabbed(false); | ||||||
|  |     _game_window.setVerticalSyncEnabled(true); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void Application::run() | void Application::run() | ||||||
| { | { | ||||||
| @ -21,18 +29,21 @@ 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()) | ||||||
|     { |     { | ||||||
|         input(); |  | ||||||
| 
 | 
 | ||||||
|         time_since_last_update += timer.restart(); |         time_since_last_update += timer.restart(); | ||||||
| 
 | 
 | ||||||
|  |         input(); | ||||||
|  | 
 | ||||||
|         bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME; |         bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME; | ||||||
|         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(); | ||||||
|         } |         } | ||||||
| @ -50,9 +61,15 @@ void Application::input() | |||||||
|             _game_window.close(); |             _game_window.close(); | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         default: |         case sf::Event::KeyPressed: | ||||||
|  |         case sf::Event::KeyReleased: | ||||||
|  |             if (event.key.code == sf::Keyboard::Escape) | ||||||
|  |                 _game_window.close(); | ||||||
|             _game->input(event); |             _game->input(event); | ||||||
|             break; |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,6 +9,10 @@ ClassicGame::ClassicGame() : | |||||||
|     _timeline(std::make_unique<ClassicTimeline>()), |     _timeline(std::make_unique<ClassicTimeline>()), | ||||||
|     _graphics_manager(std::make_unique<ClassicGraphicsManager>()) |     _graphics_manager(std::make_unique<ClassicGraphicsManager>()) | ||||||
| { | { | ||||||
|  |     _slap_buffer.loadFromFile("very-final-slap.wav"); | ||||||
|  |     _slap.setBuffer(_slap_buffer); | ||||||
|  |     _slap.setVolume(50); | ||||||
|  | 
 | ||||||
|     _keys_to_buttons = |     _keys_to_buttons = | ||||||
|     { |     { | ||||||
|         {sf::Keyboard::Up, Button::UP},      // Load from settings
 |         {sf::Keyboard::Up, Button::UP},      // Load from settings
 | ||||||
| @ -86,6 +90,7 @@ void ClassicGame::input(const sf::Event& event) | |||||||
|     if (!_timeline->isExpired(note)) |     if (!_timeline->isExpired(note)) | ||||||
|     { |     { | ||||||
|         (*note)->input(ClassicInputType(timestamp, new_action)); |         (*note)->input(ClassicInputType(timestamp, new_action)); | ||||||
|  |         _slap.play(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,6 +6,8 @@ | |||||||
| #include "game.h" | #include "game.h" | ||||||
| #include "classicactions.h" | #include "classicactions.h" | ||||||
| #include "spritecontainer.h" | #include "spritecontainer.h" | ||||||
|  | #include <SFML/Audio/SoundBuffer.hpp> | ||||||
|  | #include <SFML/Audio/Sound.hpp> | ||||||
| 
 | 
 | ||||||
| class ClassicTimeline; | class ClassicTimeline; | ||||||
| class ClassicSprite; | class ClassicSprite; | ||||||
| @ -33,6 +35,8 @@ private: | |||||||
| 
 | 
 | ||||||
|     std::unique_ptr<ClassicTimeline> _timeline; |     std::unique_ptr<ClassicTimeline> _timeline; | ||||||
|     std::unique_ptr<ClassicGraphicsManager> _graphics_manager; |     std::unique_ptr<ClassicGraphicsManager> _graphics_manager; | ||||||
|  |     sf::SoundBuffer _slap_buffer; | ||||||
|  |     sf::Sound _slap; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif // CLASSICGAME_H
 | #endif // CLASSICGAME_H
 | ||||||
|  | |||||||
| @ -10,7 +10,8 @@ ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfec | |||||||
|     _evaluator(intervals, _perfect_offset), |     _evaluator(intervals, _perfect_offset), | ||||||
|     _action(action), |     _action(action), | ||||||
|     _state(State::NONE), |     _state(State::NONE), | ||||||
|     _appearance_time(0) |     _appearance_time(0), | ||||||
|  |     _last_offset(0) | ||||||
| {} | {} | ||||||
| 
 | 
 | ||||||
| bool ClassicNote::isActive(const microsec& music_offset) const | bool ClassicNote::isActive(const microsec& music_offset) const | ||||||
| @ -18,9 +19,9 @@ bool ClassicNote::isActive(const microsec& music_offset) const | |||||||
|     return _evaluator.isActive(music_offset); |     return _evaluator.isActive(music_offset); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int getPt( int n1 , int n2 , float perc ) | static int getPt( float n1 , float n2 , float perc ) | ||||||
| { | { | ||||||
|     int diff = n2 - n1; |     float diff = n2 - n1; | ||||||
| 
 | 
 | ||||||
|     return n1 + ( diff * perc ); |     return n1 + ( diff * perc ); | ||||||
| } | } | ||||||
| @ -36,16 +37,29 @@ void ClassicNote::update(const microsec& music_offset) | |||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case State::FLYING: |     case State::FLYING: | ||||||
|  |     { | ||||||
|  |         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
 | ||||||
|         auto i = update_time / _trail_path_percent / 100;      //         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; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         int xa = getPt( 720./2. , 1280./2. , i ); |         _last_offset = music_offset; | ||||||
|         int ya = getPt( 0 , 720./2. , i ); | 
 | ||||||
|         int xb = getPt( 1280./2. , _coordinates.x , i ); |         float xa = getPt( _coordinates.x + 20.  , _coordinates.x + 90. , i ); | ||||||
|         int yb = getPt( 720./2. , _coordinates.y , 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 )); |         _sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i )); | ||||||
|  |         if (i >= 1) | ||||||
|  |             _sprite->trailFade(); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -92,7 +106,7 @@ void ClassicNote::setState(State next_state) | |||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case State::FLYING: |     case State::FLYING: | ||||||
|         _sprite->setCoordinates(_coordinates.x, _coordinates.y, 720/2, 50); |         _sprite->setCoordinates(_coordinates.x, _coordinates.y, _coordinates.x + 20, _coordinates.y - 600); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|     case State::NONE: |     case State::NONE: | ||||||
|  | |||||||
| @ -66,5 +66,6 @@ private: | |||||||
| 
 | 
 | ||||||
|     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
 | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ void ClassicSprite::reset() | |||||||
| 
 | 
 | ||||||
|     _shape = _prototype; |     _shape = _prototype; | ||||||
|     _trail = _prototype; |     _trail = _prototype; | ||||||
|  |     _trail_fade = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept | void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept | ||||||
| @ -38,6 +39,19 @@ void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_ | |||||||
| void ClassicSprite::update(float trail_x, float trail_y) noexcept | void ClassicSprite::update(float trail_x, float trail_y) noexcept | ||||||
| { | { | ||||||
|     _trail.setPosition(trail_x, trail_y); |     _trail.setPosition(trail_x, trail_y); | ||||||
|  | 
 | ||||||
|  |     if (_trail_fade) | ||||||
|  |     { | ||||||
|  |         auto fill_color = _trail.getFillColor(); | ||||||
|  | 
 | ||||||
|  |         if (fill_color.a == 0) | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         auto new_alpha = fill_color.a - 35; | ||||||
|  |         fill_color.a = new_alpha < 0 ? 0 : new_alpha; | ||||||
|  | 
 | ||||||
|  |         _trail.setFillColor(fill_color); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClassicSprite::update() noexcept | void ClassicSprite::update() noexcept | ||||||
| @ -76,6 +90,11 @@ void ClassicSprite::fade() | |||||||
|     _shape.setFillColor(fill_color); |     _shape.setFillColor(fill_color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ClassicSprite::trailFade() | ||||||
|  | { | ||||||
|  |     _trail_fade = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool ClassicSprite::isDead() const | bool ClassicSprite::isDead() const | ||||||
| { | { | ||||||
|     return _grade_text.getFillColor().a == 0 |     return _grade_text.getFillColor().a == 0 | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ public: | |||||||
| 
 | 
 | ||||||
|     void pulse(); |     void pulse(); | ||||||
|     void fade(); |     void fade(); | ||||||
|  |     void trailFade(); | ||||||
|     bool isDead() const; |     bool isDead() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| @ -26,4 +27,6 @@ private: | |||||||
|     sf::RectangleShape _trail; |     sf::RectangleShape _trail; | ||||||
|     sf::Text _grade_text; |     sf::Text _grade_text; | ||||||
|     sf::Font _font; |     sf::Font _font; | ||||||
|  | 
 | ||||||
|  |     bool _trail_fade = false; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -23,27 +23,26 @@ ClassicTimeline::ClassicTimeline() | |||||||
|     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 note_input_offset = 412162; |     microsec tempo_interval = interval / 4; | ||||||
|  |     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); | ||||||
|     _visibility_offset = note_input_offset * 8; |     _visibility_offset = note_input_offset * 12; | ||||||
| 
 | 
 | ||||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_DOWN, {90, 90})); |     _input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset}; | ||||||
|     bpm_iterator += interval; |  | ||||||
| 
 | 
 | ||||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {190, 90})); |     bpm_iterator += tempo_interval; | ||||||
|     bpm_iterator += interval; |  | ||||||
| 
 |  | ||||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {290, 90})); |  | ||||||
|     bpm_iterator += interval; |  | ||||||
| 
 | 
 | ||||||
|     float x = 90.; |     float x = 90.; | ||||||
| 
 | 
 | ||||||
|     while (bpm_iterator < bpm_end) |     while (bpm_iterator < bpm_end) | ||||||
|     { |     { | ||||||
|         _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP, {x, 390.})); |         _timeline.emplace_back(new ClassicNote(_input_intervals, bpm_iterator, Action::PRESS_UP, {x, 390.})); | ||||||
|         bpm_iterator += interval; |         bpm_iterator += tempo_interval; | ||||||
|         x += 70; |         x += 70; | ||||||
|  | 
 | ||||||
|  |         if (x >= 1200) | ||||||
|  |             x = 90.; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     expire(_first_visible_note); |     expire(_first_visible_note); | ||||||
|  | |||||||
| @ -28,16 +28,12 @@ public: | |||||||
| 
 | 
 | ||||||
|     Iterator getActiveNote() noexcept; |     Iterator getActiveNote() noexcept; | ||||||
| 
 | 
 | ||||||
|     bool isExpired(const Iterator& iterator) const; |     inline bool isExpired(const Iterator& iterator) const; | ||||||
|     void expire(Iterator& iterator); |     inline void expire(Iterator& iterator); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     std::vector<microsec> _input_intervals; | ||||||
|     std::vector<ClassicNote*> _timeline; |     std::vector<ClassicNote*> _timeline; | ||||||
|     Iterator _top_note; |  | ||||||
|     Iterator _active_note; |  | ||||||
|     Iterator _last_visible_note; |  | ||||||
|     Iterator _first_visible_note; |  | ||||||
| 
 |  | ||||||
|     microsec _visibility_offset; |     microsec _visibility_offset; | ||||||
| 
 | 
 | ||||||
|     sf::Music _music; |     sf::Music _music; | ||||||
| @ -46,7 +42,7 @@ private: | |||||||
|     void checkCurrentActiveNote(const microsec& music_offset); |     void checkCurrentActiveNote(const microsec& music_offset); | ||||||
|     void checkForNextActiveNote(const microsec& music_offset); |     void checkForNextActiveNote(const microsec& music_offset); | ||||||
|     bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; |     bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; | ||||||
|     bool nothingToDraw() const noexcept; |     inline bool nothingToDraw() const noexcept; | ||||||
| 
 | 
 | ||||||
|     /* Difference between top and active note is that
 |     /* Difference between top and active note is that
 | ||||||
|      * top note is the note handling input right now |      * top note is the note handling input right now | ||||||
| @ -61,4 +57,9 @@ private: | |||||||
|      * An active note is always top note but a top note |      * An active note is always top note but a top note | ||||||
|      *    is not always active note. |      *    is not always active note. | ||||||
|      *                                         */ |      *                                         */ | ||||||
|  | 
 | ||||||
|  |     Iterator _top_note; | ||||||
|  |     Iterator _active_note; | ||||||
|  |     Iterator _last_visible_note; | ||||||
|  |     Iterator _first_visible_note; | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user