Improve and encapsulate DebugHelper, work on Note
This commit is contained in:
		
							parent
							
								
									e37fb7b539
								
							
						
					
					
						commit
						47277ee754
					
				
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +1,10 @@ | |||||||
| # This file is used to ignore files which are generated | # This file is used to ignore files which are generated | ||||||
| # ---------------------------------------------------------------------------- | # ---------------------------------------------------------------------------- | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | SFML* | ||||||
|  | CMake* | ||||||
|  | 
 | ||||||
| *~ | *~ | ||||||
| *.autosave | *.autosave | ||||||
| *.a | *.a | ||||||
|  | |||||||
| @ -20,16 +20,26 @@ void Application::run() | |||||||
|     // BPM of METEOR is 170.
 |     // BPM of METEOR is 170.
 | ||||||
|     // Length is 1:14
 |     // Length is 1:14
 | ||||||
|     // I calculated that the time between beats is about 1412162 microseconds
 |     // I calculated that the time between beats is about 1412162 microseconds
 | ||||||
|     sf::Int64 iter = 1412162 * 25; | 
 | ||||||
|  |     std::string song_filename = "/home/naiji/METEOR.flac"; | ||||||
|  |     microsec starting_beat_offset = 372162; | ||||||
|  |     int amount_of_beats = 209; | ||||||
|  |     microsec time_between_beats = 1412162; | ||||||
|  |     microsec note_input_offset = 412162; | ||||||
|  |     sf::Int64 iter = starting_beat_offset + (time_between_beats * amount_of_beats); | ||||||
|  | 
 | ||||||
|  |     Note::setPrecisionQualifier(note_input_offset / 2); | ||||||
|  | 
 | ||||||
|     while (iter > 0) |     while (iter > 0) | ||||||
|     { |     { | ||||||
|         Note note(iter, iter + 412162); |         Note note(iter, note_input_offset); | ||||||
|         _timeline.push(note); |         _timeline.push(note); | ||||||
|         iter -= 1412162; |         iter -= time_between_beats; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     //    //    //    //    //    //    //    //
 |     //    //    //    //    //    //    //    //
 | ||||||
| 
 | 
 | ||||||
|     _music.openFromFile("/home/naiji/METEOR.flac"); |     _music.openFromFile(song_filename); | ||||||
|     _music.play(); |     _music.play(); | ||||||
|     _music.setVolume(5); |     _music.setVolume(5); | ||||||
| 
 | 
 | ||||||
| @ -154,7 +164,7 @@ void Application::onKeyPressed(const sf::Keyboard::Key &key) | |||||||
| 
 | 
 | ||||||
|     if (arrow != Note::Arrow::NONE) |     if (arrow != Note::Arrow::NONE) | ||||||
|     { |     { | ||||||
|         _debug.onUserTap(); |         _debug.spawnGreenPulse(); | ||||||
| 
 | 
 | ||||||
|         if (!_timeline.empty()) |         if (!_timeline.empty()) | ||||||
|         { |         { | ||||||
| @ -169,17 +179,29 @@ void Application::update() | |||||||
| { | { | ||||||
|     const auto microseconds = _music.getPlayingOffset().asMicroseconds(); |     const auto microseconds = _music.getPlayingOffset().asMicroseconds(); | ||||||
| 
 | 
 | ||||||
|     if (!_timeline.empty() && _timeline.top().offset() <= microseconds) |     // To Do: Here we notice when next note becomes active and ready for user input.
 | ||||||
|  |     //        Here I explicitly calculate its birth time for now.
 | ||||||
|  |     if (!_timeline.empty() && _timeline.top().offset() - 412162 <= microseconds) | ||||||
|     { |     { | ||||||
|         _debug.onBeat(); |         _debug.spawnBluePulse(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!_timeline.empty() && _timeline.top().deathOffset() <= microseconds) |     // To do: Actual note offset should pulse only once and the note shouldn't die right after it,
 | ||||||
|  |     //        because there is also "after pulse" offset, like, you know, player can be a little late
 | ||||||
|  |     if (!_timeline.empty() && _timeline.top().offset() <= microseconds) | ||||||
|     { |     { | ||||||
|         _timeline.pop(); |         _timeline.pop(); | ||||||
|         _debug.onDeath(); |         _debug.spawnRedPulse(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // To do: Here should be the end of "after pulse" time. When user fucked up all the time and the
 | ||||||
|  |     //        note dies with "Missed" grade.
 | ||||||
|  |     //
 | ||||||
|  |     // if ( . . . _timeline.top().offset() + 412162 <= microseconds)
 | ||||||
|  |     // {
 | ||||||
|  |     //
 | ||||||
|  |     // }
 | ||||||
|  | 
 | ||||||
|     _debug.update(microseconds); |     _debug.update(microseconds); | ||||||
| 
 | 
 | ||||||
|     if (_grade.getFillColor().a > 0) |     if (_grade.getFillColor().a > 0) | ||||||
|  | |||||||
| @ -1,18 +1,11 @@ | |||||||
| #include "debughelper.h" | #include "debughelper.h" | ||||||
| 
 | 
 | ||||||
| DebugHelper::DebugHelper(bool init) : | DebugHelper::DebugHelper(bool init) : | ||||||
|     _toggled(init) |     _toggled(init), | ||||||
|  |     _red_pulse({0.f, 0.f}, sf::Color(255, 0, 0)), | ||||||
|  |     _green_pulse({460.f, 0.f}, sf::Color(0, 255, 0)), | ||||||
|  |     _blue_pulse({460.f, 360.f}, sf::Color(0, 100, 255)) | ||||||
| { | { | ||||||
|     _bpm_pulse.setSize({460, 360}); |  | ||||||
|     _bpm_pulse.setOrigin(0.f, 0.f); |  | ||||||
|     _bpm_pulse.setFillColor(sf::Color(255, 0, 0, 0)); |  | ||||||
|     _tap_pulse.setSize({460, 360}); |  | ||||||
|     _tap_pulse.move(460.f, 0.f); |  | ||||||
|     _tap_pulse.setFillColor(sf::Color(0, 255, 0, 0)); |  | ||||||
|     _death_pulse.setSize({460, 360}); |  | ||||||
|     _death_pulse.move(460.f, 360.f); |  | ||||||
|     _death_pulse.setFillColor(sf::Color(0, 100, 255, 0)); |  | ||||||
| 
 |  | ||||||
|     _font.loadFromFile("VeraMono.ttf"); |     _font.loadFromFile("VeraMono.ttf"); | ||||||
| 
 | 
 | ||||||
|     _time_print.setFont(_font); |     _time_print.setFont(_font); | ||||||
| @ -26,59 +19,71 @@ void DebugHelper::toggle() | |||||||
|     _toggled = !_toggled; |     _toggled = !_toggled; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool isVisible(const sf::Shape* shape) | void DebugHelper::update(const microsec µseconds) | ||||||
| { |  | ||||||
|     return shape->getFillColor().a > 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DebugHelper::update(const sf::Int64 µseconds) |  | ||||||
| { | { | ||||||
|     _time_print.setString(std::to_string(microseconds)); |     _time_print.setString(std::to_string(microseconds)); | ||||||
| 
 | 
 | ||||||
|     if (isVisible(&_bpm_pulse)) |     _red_pulse.fade(); | ||||||
|     { |     _green_pulse.fade(); | ||||||
|         const auto new_alpha = _bpm_pulse.getFillColor().a - 25; |     _blue_pulse.fade(); | ||||||
|         _bpm_pulse.setFillColor(sf::Color(255, 0, 0, (new_alpha < 0) ? 0 : new_alpha)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (isVisible(&_tap_pulse)) |  | ||||||
|     { |  | ||||||
|         const auto new_alpha = _tap_pulse.getFillColor().a - 25; |  | ||||||
|         _tap_pulse.setFillColor(sf::Color(0, 255, 0, (new_alpha < 0) ? 0 : new_alpha)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (isVisible(&_death_pulse)) |  | ||||||
|     { |  | ||||||
|         const auto new_alpha = _death_pulse.getFillColor().a - 25; |  | ||||||
|         _death_pulse.setFillColor(sf::Color(0, 100, 255, (new_alpha < 0) ? 0 : new_alpha)); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DebugHelper::drawOn(sf::RenderWindow &game_window) const | void DebugHelper::drawOn(sf::RenderWindow &game_window) const | ||||||
| { | { | ||||||
|     if (_toggled) |     if (_toggled) | ||||||
|     { |     { | ||||||
|         game_window.draw(_bpm_pulse); |         _red_pulse.drawOn(game_window); | ||||||
|         game_window.draw(_tap_pulse); |         _green_pulse.drawOn(game_window); | ||||||
|         game_window.draw(_death_pulse); |         _blue_pulse.drawOn(game_window); | ||||||
|         game_window.draw(_time_print); |         game_window.draw(_time_print); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DebugHelper::onUserTap() | void DebugHelper::spawnGreenPulse() | ||||||
| { | { | ||||||
|     const sf::Uint8 alpha = 255; |     _green_pulse.appear(); | ||||||
|     _tap_pulse.setFillColor(sf::Color(255, 0, 0, alpha)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DebugHelper::onBeat() | void DebugHelper::spawnRedPulse() | ||||||
| { | { | ||||||
|     const sf::Uint8 alpha = 255; |     _red_pulse.appear(); | ||||||
|     _bpm_pulse.setFillColor(sf::Color(0, 255, 0, alpha)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DebugHelper::onDeath() | void DebugHelper::spawnBluePulse() | ||||||
| { | { | ||||||
|     const sf::Uint8 alpha = 255; |     _blue_pulse.appear(); | ||||||
|     _death_pulse.setFillColor(sf::Color(0, 100, 255, alpha)); | } | ||||||
|  | 
 | ||||||
|  | DebugHelper::Pulse::Pulse(sf::Vector2f position, sf::Color fill_color) | ||||||
|  | { | ||||||
|  |     _pulse_shape.setSize({480, 360}); | ||||||
|  |     _pulse_shape.move(position.x, position.y); | ||||||
|  | 
 | ||||||
|  |     fill_color.a = 0; | ||||||
|  |     _pulse_shape.setFillColor(fill_color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DebugHelper::Pulse::appear() | ||||||
|  | { | ||||||
|  |     auto fill_color = _pulse_shape.getFillColor(); | ||||||
|  |     fill_color.a = 255; | ||||||
|  |     _pulse_shape.setFillColor(fill_color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DebugHelper::Pulse::fade() | ||||||
|  | { | ||||||
|  |     auto fill_color = _pulse_shape.getFillColor(); | ||||||
|  | 
 | ||||||
|  |     if (fill_color.a == 0) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     const auto new_alpha = fill_color.a - 25; | ||||||
|  |     fill_color.a = new_alpha < 0 ? 0 : new_alpha; | ||||||
|  | 
 | ||||||
|  |     _pulse_shape.setFillColor(fill_color); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DebugHelper::Pulse::drawOn(sf::RenderWindow &game_window) const | ||||||
|  | { | ||||||
|  |     game_window.draw(_pulse_shape); | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,25 +6,42 @@ | |||||||
| #include <SFML/Graphics/Font.hpp> | #include <SFML/Graphics/Font.hpp> | ||||||
| #include <SFML/Graphics/Text.hpp> | #include <SFML/Graphics/Text.hpp> | ||||||
| 
 | 
 | ||||||
|  | using microsec = sf::Int64; | ||||||
|  | 
 | ||||||
| class DebugHelper | class DebugHelper | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     DebugHelper(bool init = true); |     DebugHelper(bool init = true); | ||||||
| 
 | 
 | ||||||
|     void toggle(); |     void toggle(); | ||||||
|     void update(const sf::Int64& microseconds); |     void update(const microsec& microseconds); | ||||||
|     void drawOn(sf::RenderWindow &game_window) const; |     void drawOn(sf::RenderWindow &game_window) const; | ||||||
|     void onUserTap(); | 
 | ||||||
|     void onBeat(); |     void spawnGreenPulse(); | ||||||
|     void onDeath(); |     void spawnRedPulse(); | ||||||
|  |     void spawnBluePulse(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     bool _toggled; |     bool _toggled; | ||||||
|     sf::RectangleShape _bpm_pulse; |  | ||||||
|     sf::RectangleShape _tap_pulse; |  | ||||||
|     sf::RectangleShape _death_pulse; |  | ||||||
|     sf::Font _font; |     sf::Font _font; | ||||||
|     sf::Text _time_print; |     sf::Text _time_print; | ||||||
|  | 
 | ||||||
|  |     class Pulse | ||||||
|  |     { | ||||||
|  |     public: | ||||||
|  |         Pulse(sf::Vector2f position, sf::Color fill_color); | ||||||
|  |         void appear(); | ||||||
|  |         void fade(); | ||||||
|  | 
 | ||||||
|  |         void drawOn(sf::RenderWindow &game_window) const; | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         sf::RectangleShape _pulse_shape; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     Pulse _red_pulse; | ||||||
|  |     Pulse _green_pulse; | ||||||
|  |     Pulse _blue_pulse; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif // DEBUGHELPER_H
 | #endif // DEBUGHELPER_H
 | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								note.cpp
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								note.cpp
									
									
									
									
									
								
							| @ -1,22 +1,28 @@ | |||||||
| #include "note.h" | #include "note.h" | ||||||
| #include <cmath> | #include <cmath> | ||||||
| 
 | 
 | ||||||
| Note::Note(microsec offset, microsec death_offset, Note::Arrow type) : | Note::Note(microsec offset, microsec life_span_offset, Note::Arrow type) : | ||||||
|     _offset(offset), |     _offset(offset), | ||||||
|     _death_offset(death_offset), |     _start_handling_offset(_offset + life_span_offset), | ||||||
|  |     _end_handling_offset(_offset - life_span_offset), | ||||||
|     _type(type) |     _type(type) | ||||||
| {} | {} | ||||||
| 
 | 
 | ||||||
|  | void Note::setPosition(coordinates position) | ||||||
|  | { | ||||||
|  |     _position = position; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | coordinates Note::position() const noexcept | ||||||
|  | { | ||||||
|  |     return _position; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| microsec Note::offset() const noexcept | microsec Note::offset() const noexcept | ||||||
| { | { | ||||||
|     return _offset; |     return _offset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| microsec Note::deathOffset() const noexcept |  | ||||||
| { |  | ||||||
|     return _death_offset; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const | NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const | ||||||
| { | { | ||||||
|     if (arrow_type != _type) |     if (arrow_type != _type) | ||||||
| @ -28,12 +34,25 @@ NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const | |||||||
| 
 | 
 | ||||||
| NoteGrade Note::calculatePrecision(microsec odds) const | NoteGrade Note::calculatePrecision(microsec odds) const | ||||||
| { | { | ||||||
|     NoteGrade ret; |     NoteGrade ret(0, NoteGrade::Rating::BAD); | ||||||
|     if (odds < 412162) | 
 | ||||||
|  |     if (odds < _precision_qualifier) | ||||||
|     { |     { | ||||||
|         ret.score = 50; |         ret = {50, NoteGrade::Rating::GREAT}; | ||||||
|         ret.rating = NoteGrade::Rating::GREAT; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool Note::isActive(microsec music_play_offset) const noexcept | ||||||
|  | { | ||||||
|  |     return music_play_offset > _start_handling_offset | ||||||
|  |         && music_play_offset < _end_handling_offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Note::setPrecisionQualifier(microsec qualifier) | ||||||
|  | { | ||||||
|  |     _precision_qualifier = qualifier; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | microsec Note::_precision_qualifier = 500000; // Default initialization as 0.5 second.
 | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								note.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								note.h
									
									
									
									
									
								
							| @ -2,21 +2,29 @@ | |||||||
| #define NOTE_H | #define NOTE_H | ||||||
| 
 | 
 | ||||||
| #include <SFML/System/Clock.hpp> | #include <SFML/System/Clock.hpp> | ||||||
|  | #include <SFML/System/Vector2.hpp> | ||||||
|  | 
 | ||||||
|  | ////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| using microsec = sf::Int64; | using microsec = sf::Int64; | ||||||
|  | using coordinates = sf::Vector2i; | ||||||
| 
 | 
 | ||||||
| struct NoteGrade | struct NoteGrade | ||||||
| { | { | ||||||
|     int score = 0; |     int score; | ||||||
|     enum class Rating |     enum class Rating | ||||||
|     { |     { | ||||||
|         WRONG, |         WRONG, | ||||||
|         BAD, |         BAD, | ||||||
|         GOOD, |         GOOD, | ||||||
|         GREAT |         GREAT | ||||||
|     } rating = Rating::BAD; |     } rating; | ||||||
|  | 
 | ||||||
|  |     NoteGrade(int s, Rating r) : score(s), rating(r) {} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | ////////////////////////////////
 | ||||||
|  | 
 | ||||||
| class Note | class Note | ||||||
| { | { | ||||||
| public: | public: | ||||||
| @ -30,17 +38,25 @@ public: | |||||||
|         NONE |         NONE | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     Note(microsec offset, microsec death_offset, Note::Arrow type = Note::Arrow::UP); |     Note(microsec offset, microsec life_span_offset, Note::Arrow type = Note::Arrow::UP); | ||||||
|  | 
 | ||||||
|  |     void setPosition(coordinates position); | ||||||
|  |     coordinates position() const noexcept; | ||||||
|  |     microsec offset() const noexcept; | ||||||
| 
 | 
 | ||||||
|     NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const; |     NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const; | ||||||
|     microsec offset() const noexcept; |     bool isActive(microsec music_play_offset) const noexcept; | ||||||
|     microsec deathOffset() const noexcept; | 
 | ||||||
|  |     static void setPrecisionQualifier(microsec qualifier); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     coordinates _position; | ||||||
|     microsec _offset; |     microsec _offset; | ||||||
|     microsec _death_offset; |     microsec _start_handling_offset; | ||||||
|  |     microsec _end_handling_offset; | ||||||
|     Arrow _type = Arrow::UP; |     Arrow _type = Arrow::UP; | ||||||
| 
 | 
 | ||||||
|  |     static microsec _precision_qualifier; | ||||||
|     NoteGrade calculatePrecision(microsec odds) const; |     NoteGrade calculatePrecision(microsec odds) const; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user