From e5969d148468a1249f2c6c16d259d68bf8fe5467 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Tue, 8 Jun 2021 21:32:36 +0300 Subject: [PATCH] Improve work with timeline --- include/application.h | 2 - include/note.h | 7 ++ include/timeline.h | 4 +- src/application.cpp | 10 +-- src/classicgame/classicgame.cpp | 13 ++-- src/classicgame/classicgame.h | 3 +- src/classicgame/classicnote.cpp | 18 ++++- src/classicgame/classicnote.h | 7 +- src/classicgame/classictimeline.cpp | 105 ++++++++++++++++------------ src/classicgame/classictimeline.h | 30 +++++--- 10 files changed, 126 insertions(+), 73 deletions(-) diff --git a/include/application.h b/include/application.h index 7a97e75..25b99c9 100644 --- a/include/application.h +++ b/include/application.h @@ -1,7 +1,6 @@ #ifndef APPLICATION_H #define APPLICATION_H -#include #include #include @@ -21,7 +20,6 @@ public: private: sf::RenderWindow _game_window; - sf::Music _music; sf::Font _font; sf::Text _grade; diff --git a/include/note.h b/include/note.h index 17884ee..96b8489 100644 --- a/include/note.h +++ b/include/note.h @@ -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; }; diff --git a/include/timeline.h b/include/timeline.h index 92c8fb5..6c69a6a 100644 --- a/include/timeline.h +++ b/include/timeline.h @@ -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 diff --git a/src/application.cpp b/src/application.cpp index 65b8a71..31d060d 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -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(); } diff --git a/src/classicgame/classicgame.cpp b/src/classicgame/classicgame.cpp index 9e819b2..ec19c86 100644 --- a/src/classicgame/classicgame.cpp +++ b/src/classicgame/classicgame.cpp @@ -1,6 +1,7 @@ #include "classicgame.h" #include "classicinputtype.h" #include "classictimeline.h" +#include "classicnote.h" ClassicGame::ClassicGame() : _timeline(std::make_unique()) @@ -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 diff --git a/src/classicgame/classicgame.h b/src/classicgame/classicgame.h index 4c7f6b9..e11d569 100644 --- a/src/classicgame/classicgame.h +++ b/src/classicgame/classicgame.h @@ -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 _timeline; - + std::unique_ptr _view_manager; }; #endif // CLASSICGAME_H diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp index bd41958..c6b6419 100644 --- a/src/classicgame/classicnote.cpp +++ b/src/classicgame/classicnote.cpp @@ -1,8 +1,22 @@ #include "classicnote.h" -ClassicNote::ClassicNote(const std::vector& intervals, microsec perfect_offset) : +ClassicNote::ClassicNote(const std::vector& 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; } diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h index 0713bfb..05ef038 100644 --- a/src/classicgame/classicnote.h +++ b/src/classicgame/classicnote.h @@ -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& intervals, microsec perfect_offset); + explicit ClassicNote(const std::vector& intervals, microsec perfect_offset, Action action); virtual ~ClassicNote() = default; + virtual bool isActive(microsec music_offset) const override; + + GRADE input(ClassicInputType&& input_data); private: PrecisionEvaluator _evaluator; + Action _action; }; diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp index addc696..a1f9f6f 100644 --- a/src/classicgame/classictimeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -1,7 +1,7 @@ #include #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& 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; +} diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h index 796518c..30ece9f 100644 --- a/src/classicgame/classictimeline.h +++ b/src/classicgame/classictimeline.h @@ -1,31 +1,45 @@ #pragma once #include +#include #include "timeline.h" +#include -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& view_manager); + + using Iterator = std::vector::const_iterator; + + Iterator getActiveNote() noexcept; + + bool isExpired(const Iterator& iterator); + void expire(Iterator& iterator); private: - std::vector _timeline; - std::vector::const_iterator _top_note; - Note* _active_note; + std::vector _timeline; + Iterator _top_note; + Iterator _active_note; + Iterator _last_visible_note; - std::vector::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