Improve work with timeline
This commit is contained in:
		
							parent
							
								
									f66951bcec
								
							
						
					
					
						commit
						e5969d1484
					
				| @ -1,7 +1,6 @@ | ||||
| #ifndef APPLICATION_H | ||||
| #define APPLICATION_H | ||||
| 
 | ||||
| #include <SFML/Audio/Music.hpp> | ||||
| #include <SFML/System/Clock.hpp> | ||||
| #include <SFML/Window/Keyboard.hpp> | ||||
| 
 | ||||
| @ -21,7 +20,6 @@ public: | ||||
| 
 | ||||
| private: | ||||
|     sf::RenderWindow _game_window; | ||||
|     sf::Music _music; | ||||
| 
 | ||||
|     sf::Font _font; | ||||
|     sf::Text _grade; | ||||
|  | ||||
| @ -12,6 +12,13 @@ public: | ||||
|         _perfect_offset(perfect_offset) {} | ||||
|     virtual ~Note() = 0; | ||||
| 
 | ||||
|     virtual bool isActive(microsec music_offset) const = 0; | ||||
| 
 | ||||
|     virtual microsec offset() const | ||||
|     { | ||||
|         return _perfect_offset; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     microsec _perfect_offset; | ||||
| }; | ||||
|  | ||||
| @ -11,9 +11,11 @@ class Timeline | ||||
| public: | ||||
|     virtual ~Timeline() = default; | ||||
| 
 | ||||
|     virtual void update(const microsec& music_offset) = 0; | ||||
|     virtual void update() = 0; | ||||
|     virtual void init() = 0; | ||||
|     virtual void clear() = 0; | ||||
| 
 | ||||
|     virtual microsec currentMusicOffset() const = 0; | ||||
| }; | ||||
| 
 | ||||
| #endif // TIMELINE_H
 | ||||
|  | ||||
| @ -20,12 +20,6 @@ Application::Application() : | ||||
| 
 | ||||
| void Application::run() | ||||
| { | ||||
|     std::string song_filename = "/home/naiji/METEOR.flac"; | ||||
| 
 | ||||
|     _music.openFromFile(song_filename); | ||||
|     _music.play(); | ||||
|     _music.setVolume(30); | ||||
| 
 | ||||
|     _game_window.display(); | ||||
| 
 | ||||
|     startGameLoop(); | ||||
| @ -63,10 +57,10 @@ void Application::input() | ||||
| 
 | ||||
| void Application::update() | ||||
| { | ||||
| 
 | ||||
|     _game->update(); | ||||
| } | ||||
| 
 | ||||
| void Application::draw() | ||||
| { | ||||
| 
 | ||||
| //  _game->draw();
 | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "classicgame.h" | ||||
| #include "classicinputtype.h" | ||||
| #include "classictimeline.h" | ||||
| #include "classicnote.h" | ||||
| 
 | ||||
| ClassicGame::ClassicGame() : | ||||
|     _timeline(std::make_unique<ClassicTimeline>()) | ||||
| @ -52,7 +53,7 @@ void ClassicGame::run() | ||||
| void ClassicGame::input(const sf::Event& event) | ||||
| { | ||||
|     Action new_action = Action::NONE; | ||||
|     microsec timestamp = 0; /* 0 is temp. get from timeline */ | ||||
|     microsec timestamp = _timeline->currentMusicOffset(); | ||||
| 
 | ||||
|     switch (event.type) | ||||
|     { | ||||
| @ -72,9 +73,10 @@ void ClassicGame::input(const sf::Event& event) | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     ClassicInputType input(timestamp, new_action); | ||||
|     auto note = _timeline->getActiveNote(timestamp); | ||||
|     note-> | ||||
|     auto note = _timeline->getActiveNote(); | ||||
| 
 | ||||
|     if (!_timeline->isExpired(note)) | ||||
|         (*note)->input(ClassicInputType(timestamp, new_action)); | ||||
| } | ||||
| 
 | ||||
| Action ClassicGame::getActionKeyPressed(Button button) const | ||||
| @ -89,7 +91,8 @@ Action ClassicGame::getActionKeyReleased(Button button) const | ||||
| 
 | ||||
| void ClassicGame::update() | ||||
| { | ||||
| 
 | ||||
|     _timeline->update(); | ||||
|     _timeline->fetchVisibleNotes(_view_manager); | ||||
| } | ||||
| 
 | ||||
| void ClassicGame::draw(const sf::RenderWindow& window) const | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
| #include "classicactions.h" | ||||
| 
 | ||||
| class ClassicTimeline; | ||||
| class ClassicViewManager; | ||||
| 
 | ||||
| class ClassicGame final : public Game | ||||
| { | ||||
| @ -29,7 +30,7 @@ private: | ||||
|     Action getActionKeyReleased(Button button) const; | ||||
| 
 | ||||
|     std::unique_ptr<ClassicTimeline> _timeline; | ||||
| 
 | ||||
|     std::unique_ptr<ClassicViewManager> _view_manager; | ||||
| }; | ||||
| 
 | ||||
| #endif // CLASSICGAME_H
 | ||||
|  | ||||
| @ -1,8 +1,22 @@ | ||||
| #include "classicnote.h" | ||||
| 
 | ||||
| ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset) : | ||||
| ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, Action action) : | ||||
|     Note(perfect_offset), | ||||
|     _evaluator(intervals, _perfect_offset) | ||||
| { | ||||
|     _evaluator(intervals, _perfect_offset), | ||||
|     _action(action) | ||||
| {} | ||||
| 
 | ||||
| bool ClassicNote::isActive(microsec music_offset) const | ||||
| { | ||||
|     return _evaluator.isActive(music_offset); | ||||
| } | ||||
| 
 | ||||
| ClassicNote::GRADE ClassicNote::input(ClassicInputType&& input_data) | ||||
| { | ||||
|     if (input_data == _action) | ||||
|     { | ||||
|         return _evaluator.calculatePrecision(input_data.timestamp()); | ||||
|     } | ||||
| 
 | ||||
|     return ClassicNote::GRADE::BAD; | ||||
| } | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| #include "note.h" | ||||
| #include "precisionevaluator.h" | ||||
| #include "classicinputtype.h" | ||||
| 
 | ||||
| class ClassicNote : public Note | ||||
| { | ||||
| @ -14,9 +15,13 @@ public: | ||||
|             BAD | ||||
|     }; | ||||
| 
 | ||||
|     explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset); | ||||
|     explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, Action action); | ||||
|     virtual ~ClassicNote() = default; | ||||
|     virtual bool isActive(microsec music_offset) const override; | ||||
| 
 | ||||
|     GRADE input(ClassicInputType&& input_data); | ||||
| 
 | ||||
| private: | ||||
|     PrecisionEvaluator<GRADE> _evaluator; | ||||
|     Action _action; | ||||
| }; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #include <iostream> | ||||
| #include "classicactions.h" | ||||
| #include "classictimeline.h" | ||||
| #include "note.h" | ||||
| #include "classicnote.h" | ||||
| 
 | ||||
| ClassicTimeline::ClassicTimeline() | ||||
| { | ||||
| @ -9,6 +9,12 @@ ClassicTimeline::ClassicTimeline() | ||||
|     // Length is 1:14
 | ||||
|     // I calculated that the time between beats is about 1412162 microseconds
 | ||||
| 
 | ||||
|     std::string song_filename = "/home/naiji/METEOR.flac"; | ||||
| 
 | ||||
|     _music.openFromFile(song_filename); | ||||
|     _music.play(); | ||||
|     _music.setVolume(30); | ||||
| 
 | ||||
|     _timeline.reserve(1000); | ||||
| 
 | ||||
|     microsec starting_beat_offset = 372162; | ||||
| @ -19,91 +25,100 @@ ClassicTimeline::ClassicTimeline() | ||||
|     microsec bpm_end = starting_beat_offset + (interval * amount_of_beats); | ||||
|     _visibility_offset = note_input_offset * 12; | ||||
| 
 | ||||
|     _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::DOWN)); | ||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_DOWN)); | ||||
|     bpm_iterator += interval; | ||||
| 
 | ||||
|     _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT)); | ||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT)); | ||||
|     bpm_iterator += interval; | ||||
| 
 | ||||
|     _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT)); | ||||
|     _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT)); | ||||
|     bpm_iterator += interval; | ||||
| 
 | ||||
|     while (bpm_iterator < bpm_end) | ||||
|     { | ||||
|         _timeline.emplace_back(new Note(bpm_iterator, note_input_offset)); | ||||
|         _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP)); | ||||
|         bpm_iterator += interval; | ||||
|     } | ||||
| 
 | ||||
|     _active_note = nullptr; | ||||
|     _last_visible_note = _timeline.end(); | ||||
|     expire(_active_note); | ||||
|     _top_note = _timeline.begin(); | ||||
| 
 | ||||
|     _last_visible_note = _top_note; | ||||
|     _view_manager->initNoteGraphics(*_top_note); | ||||
|     prepareNotesToDraw(0); | ||||
| } | ||||
| 
 | ||||
| void Timeline::prepareNotesToDraw(const microsec &music_offset) | ||||
| { | ||||
|     auto note_iterator = _top_note; | ||||
| 
 | ||||
|     while (((*note_iterator)->offset() - _visibility_offset) <= music_offset) | ||||
|     { | ||||
|         ++note_iterator; | ||||
|         if (note_iterator > _last_visible_note) | ||||
|             _view_manager->initNoteGraphics((*note_iterator)); | ||||
|     } | ||||
| 
 | ||||
|     _last_visible_note = note_iterator; | ||||
| } | ||||
| 
 | ||||
| Timeline::~Timeline() | ||||
| ClassicTimeline::~ClassicTimeline() | ||||
| { | ||||
|     clear(); | ||||
| } | ||||
| 
 | ||||
| void Timeline::clear() | ||||
| void ClassicTimeline::clear() | ||||
| { | ||||
|     for (auto note : _timeline) | ||||
|         delete note; | ||||
| 
 | ||||
|     _timeline.clear(); | ||||
|     _top_note = _timeline.end(); | ||||
|     _last_visible_note = _timeline.end(); | ||||
|     _active_note = nullptr; | ||||
| 
 | ||||
|     Note::resetPrecisionQualifier(); | ||||
|     expire(_top_note); | ||||
|     expire(_last_visible_note); | ||||
|     expire(_active_note); | ||||
| } | ||||
| 
 | ||||
| void Timeline::update(const microsec &music_offset) | ||||
| void ClassicTimeline::update() | ||||
| { | ||||
|     checkCurrentActiveNote(music_offset); | ||||
|     checkForNextActiveNote(music_offset); | ||||
|     prepareNotesToDraw(music_offset); | ||||
|     const auto& offset = currentMusicOffset(); | ||||
|     std::cout << "Upadting at: " << offset << '\n'; | ||||
|     checkCurrentActiveNote(offset); | ||||
|     checkForNextActiveNote(offset); | ||||
| } | ||||
| 
 | ||||
| void Timeline::checkCurrentActiveNote(const microsec &music_offset) | ||||
| void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) | ||||
| { | ||||
|     if (_active_note && !_active_note->isActive(music_offset)) | ||||
|     if (!isExpired(_active_note) && !(*_active_note)->isActive(music_offset)) | ||||
|     { | ||||
|         _active_note = nullptr; | ||||
|         (*_top_note)->resetSprite(); | ||||
|         expire(_active_note); | ||||
|         ++_top_note; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Timeline::checkForNextActiveNote(const microsec &music_offset) | ||||
| void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset) | ||||
| { | ||||
|     if (!_active_note && (*_top_note)->isActive(music_offset)) | ||||
|     if (isExpired(_active_note) && (*_top_note)->isActive(music_offset)) | ||||
|     { | ||||
|         std::cout << "New active note: " << music_offset << '\n'; | ||||
|         _active_note = *_top_note; | ||||
|         _active_note = _top_note; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Note* Timeline::fetchActiveNote(const microsec &music_offset) noexcept | ||||
| ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept | ||||
| { | ||||
|     std::cout << "Clicked at: " << music_offset << '\n'; | ||||
|     update(music_offset); | ||||
|     update(); | ||||
|     return _active_note; | ||||
| } | ||||
| 
 | ||||
| bool ClassicTimeline::isExpired(const Iterator &iterator) | ||||
| { | ||||
|     return iterator == _timeline.end(); | ||||
| } | ||||
| 
 | ||||
| void ClassicTimeline::expire(Iterator &iterator) | ||||
| { | ||||
|     iterator = _timeline.end(); | ||||
| } | ||||
| 
 | ||||
| microsec ClassicTimeline::currentMusicOffset() const | ||||
| { | ||||
|     return _music.getPlayingOffset().asMicroseconds(); | ||||
| } | ||||
| 
 | ||||
| void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr<ClassicViewManager>& view_manager) | ||||
| { | ||||
|     Iterator note_iterator = _top_note; | ||||
|     auto music_offset = currentMusicOffset(); | ||||
| 
 | ||||
|     while (((*note_iterator)->offset() - _visibility_offset) <= music_offset) | ||||
|     { | ||||
|         ++note_iterator; | ||||
|         if (note_iterator > _last_visible_note) | ||||
|             (void) view_manager;//_view_manager->initNoteGraphics((*note_iterator));
 | ||||
|     } | ||||
| 
 | ||||
|     _last_visible_note = note_iterator; | ||||
| } | ||||
|  | ||||
| @ -1,31 +1,45 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <memory> | ||||
| #include "timeline.h" | ||||
| #include <SFML/Audio/Music.hpp> | ||||
| 
 | ||||
| class Note; | ||||
| class ClassicNote; | ||||
| class ClassicViewManager; | ||||
| 
 | ||||
| class ClassicTimeline : public Timeline | ||||
| { | ||||
| public: | ||||
|     explicit ClassicTimeline(); | ||||
|     virtual void update(const microsec& music_offset) override; | ||||
|     virtual ~ClassicTimeline(); | ||||
|     virtual void update() override; | ||||
|     virtual void init() override; | ||||
|     virtual void clear() override; | ||||
| 
 | ||||
|     Note *getActiveNote(const microsec &music_offset) noexcept; | ||||
|     virtual microsec currentMusicOffset() const override; | ||||
| 
 | ||||
|     void fetchVisibleNotes(const std::unique_ptr<ClassicViewManager>& view_manager); | ||||
| 
 | ||||
|     using Iterator = std::vector<ClassicNote*>::const_iterator; | ||||
| 
 | ||||
|     Iterator getActiveNote() noexcept; | ||||
| 
 | ||||
|     bool isExpired(const Iterator& iterator); | ||||
|     void expire(Iterator& iterator); | ||||
| 
 | ||||
| private: | ||||
|     std::vector<Note*> _timeline; | ||||
|     std::vector<Note*>::const_iterator _top_note; | ||||
|     Note* _active_note; | ||||
|     std::vector<ClassicNote*> _timeline; | ||||
|     Iterator _top_note; | ||||
|     Iterator _active_note; | ||||
|     Iterator _last_visible_note; | ||||
| 
 | ||||
|     std::vector<Note*>::const_iterator _last_visible_note; | ||||
|     microsec _visibility_offset; | ||||
| 
 | ||||
|     sf::Music _music; | ||||
| 
 | ||||
|     void checkCurrentActiveNote(const microsec &music_offset); | ||||
|     void checkForNextActiveNote(const microsec &music_offset); | ||||
|     void prepareNotesToDraw(const microsec &music_offset); | ||||
| 
 | ||||
|     /* Difference between top and active note is that
 | ||||
|      * top note is the note handling input right now | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user