From f66951bcec4001bd16d467de9c81ad9cd84eb28c Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 7 Jun 2021 21:19:58 +0300 Subject: [PATCH] Implement basic ClassicNote --- include/application.h | 5 +- include/note.h | 17 +++ include/notegraphicsentity.h | 31 ----- include/precisionevaluator.h | 8 +- include/sprite.h | 6 + include/timeline.h | 48 +------- include/timelineviewmanager.h | 3 +- src/application.cpp | 113 +----------------- src/classicgame/classicgame.cpp | 7 +- src/classicgame/classicgame.h | 5 + src/classicgame/classicnote.cpp | 8 ++ src/classicgame/classicnote.h | 22 ++++ src/classicgame/classicsprite.cpp | 0 src/classicgame/classicsprite.h | 0 .../classictimeline.cpp} | 45 ++----- src/classicgame/classictimeline.h | 43 +++++++ src/notegraphicsentity.cpp | 15 --- src/timelineviewmanager.cpp | 4 - 18 files changed, 130 insertions(+), 250 deletions(-) create mode 100644 include/note.h delete mode 100644 include/notegraphicsentity.h create mode 100644 include/sprite.h create mode 100644 src/classicgame/classicnote.cpp create mode 100644 src/classicgame/classicnote.h create mode 100644 src/classicgame/classicsprite.cpp create mode 100644 src/classicgame/classicsprite.h rename src/{timeline.cpp => classicgame/classictimeline.cpp} (68%) create mode 100644 src/classicgame/classictimeline.h delete mode 100644 src/notegraphicsentity.cpp delete mode 100644 src/timelineviewmanager.cpp diff --git a/include/application.h b/include/application.h index 0f6cfd5..7a97e75 100644 --- a/include/application.h +++ b/include/application.h @@ -8,6 +8,7 @@ #include "debughelper.h" #include "timeline.h" #include "note.h" +#include "game.h" class Application { @@ -28,9 +29,9 @@ private: std::unique_ptr _timeline; DebugHelper _debug; + std::unique_ptr _game; + void startGameLoop(); - void onKeyPressed(const sf::Keyboard::Key& key); - void onTap(const Note::Arrow& arrow); }; #endif // APPLICATION_H diff --git a/include/note.h b/include/note.h new file mode 100644 index 0000000..17884ee --- /dev/null +++ b/include/note.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +using microsec = sf::Int64; + +class Note +{ +public: + explicit Note(microsec perfect_offset) : + _perfect_offset(perfect_offset) {} + virtual ~Note() = 0; + +protected: + microsec _perfect_offset; +}; diff --git a/include/notegraphicsentity.h b/include/notegraphicsentity.h deleted file mode 100644 index 52e1f3d..0000000 --- a/include/notegraphicsentity.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef NOTEGRAPHICSENTITY_H -#define NOTEGRAPHICSENTITY_H - -#include -#include - -class NoteGraphicsEntity : public sf::Drawable, public sf::Transformable -{ -public: - explicit NoteGraphicsEntity(); - virtual ~NoteGraphicsEntity() = 0; - - virtual void update() = 0; - - virtual void attach() noexcept final; - virtual void detach() noexcept final; - - virtual void onKeyPressed() = 0; - virtual void onKeyReleased() = 0; - - virtual void show() = 0; - virtual void killAsExpired() = 0; - virtual void reset() = 0; - - virtual bool isActive() const = 0; - -protected: - bool _attached; -}; - -#endif diff --git a/include/precisionevaluator.h b/include/precisionevaluator.h index 66bdc70..8c4e4ab 100644 --- a/include/precisionevaluator.h +++ b/include/precisionevaluator.h @@ -14,9 +14,9 @@ template::value> class PrecisionEvaluator { public: - PrecisionEvaluator(std::vector&& intervals, microsec offset) : + PrecisionEvaluator(const std::vector& intervals, microsec offset) : _offset(offset), - _intervals(std::move(intervals)) + _intervals(intervals) { microsec&& handling_offset = std::accumulate(intervals.begin(), intervals.end(), 0); _start_handling_offset = _offset - handling_offset; @@ -41,7 +41,7 @@ public: std::size_t raw_grade; for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade) { - if (shift_from_perfect <= _intervals[raw_grade]) + if (shift_from_perfect <= _intervals.at(raw_grade)) break; } @@ -60,7 +60,7 @@ private: * V0 is PERFECT SCORE and the last V represents the worst * grades which is death of note by expiration */ - std::vector _intervals; + const std::vector& _intervals; }; #endif // PRECISIONEVALUATOR_H diff --git a/include/sprite.h b/include/sprite.h new file mode 100644 index 0000000..1cbca29 --- /dev/null +++ b/include/sprite.h @@ -0,0 +1,6 @@ +#pragma once + +class Sprite +{ + +}; diff --git a/include/timeline.h b/include/timeline.h index 6e7b956..92c8fb5 100644 --- a/include/timeline.h +++ b/include/timeline.h @@ -2,56 +2,18 @@ #define TIMELINE_H #include -#include - -#include #include using microsec = sf::Int64; -class Note; -class TimelineViewManager; -class Timeline : public sf::Drawable // Probably it's bad +class Timeline { public: - explicit Timeline(std::unique_ptr view_manager); - virtual ~Timeline(); + virtual ~Timeline() = default; - virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; - - void update(const microsec& music_offset); - Note *fetchActiveNote(const microsec &music_offset) noexcept; - - /* void init(); */ - void clear(); - -private: - std::vector _timeline; - std::vector::const_iterator _top_note; - Note* _active_note; - - std::vector::const_iterator _last_visible_note; - microsec _visibility_offset; - - std::unique_ptr _view_manager; - - 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 - * OR it's the closest note from current music offset - * position, not necessarily active. A note stops being top only - * after dying or being tapped by player, even if it's already - * past her perfect offset. - * - * Meanwhile active note is the note which is currently handling - * player input for grade. - * - * An active note is always top note but a top note - * is not always active note. - * */ + virtual void update(const microsec& music_offset) = 0; + virtual void init() = 0; + virtual void clear() = 0; }; #endif // TIMELINE_H diff --git a/include/timelineviewmanager.h b/include/timelineviewmanager.h index 24d5815..1fef402 100644 --- a/include/timelineviewmanager.h +++ b/include/timelineviewmanager.h @@ -6,8 +6,7 @@ class Note; class TimelineViewManager { public: - explicit TimelineViewManager(); - virtual ~TimelineViewManager() = 0; + virtual ~TimelineViewManager() = default; virtual void initNoteGraphics(Note *note) = 0; }; diff --git a/src/application.cpp b/src/application.cpp index 73cbe26..65b8a71 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,16 +1,15 @@ #include "application.h" - +#include "classicgame/classicgame.h" #include #include -#include "classicviewmanager.h" const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f); Application::Application() : _game_window({1280, 720}, "Test"), - _debug(true) + _debug(true), + _game(std::make_unique()) { - _timeline = std::make_unique(std::make_unique()); _font.loadFromFile("/usr/share/qtcreator/fonts/SourceCodePro-Regular.ttf"); _grade.setFont(_font); _grade.setPosition(160, 160); @@ -53,121 +52,17 @@ void Application::startGameLoop() } } -static void makeGradeString(const NoteGrade::Rating& rating, sf::Text& text) -{ - switch (rating) - { - case (NoteGrade::Rating::BAD): - text.setString("BAD"); - text.setFillColor(sf::Color(255, 255, 255, 255)); - break; - - case (NoteGrade::Rating::GREAT): - text.setString("GREAT"); - text.setFillColor(sf::Color(255, 255, 0, 255)); - break; - - case (NoteGrade::Rating::WRONG): - text.setString("WRONG"); - text.setFillColor(sf::Color(120, 120, 120, 255)); - break; - - case (NoteGrade::Rating::GOOD): - text.setString("GOOD"); - text.setFillColor(sf::Color(255, 100, 120, 255)); - break; - } -} - void Application::input() { sf::Event event; while (_game_window.pollEvent(event)) { - switch (event.type) - { - default: - break; - - case (sf::Event::Closed): - _game_window.close(); - break; - - case (sf::Event::KeyPressed): - onKeyPressed(event.key.code); - break; - } - } -} - -static Note::Arrow keyToArrow(const sf::Keyboard::Key &key) -{ - switch (key) - { - case sf::Keyboard::A: - case sf::Keyboard::Left: - case sf::Keyboard::Num4: - return Note::Arrow::LEFT; - - case sf::Keyboard::W: - case sf::Keyboard::Up: - case sf::Keyboard::Num8: - return Note::Arrow::UP; - - case sf::Keyboard::D: - case sf::Keyboard::Right: - case sf::Keyboard::Num6: - return Note::Arrow::RIGHT; - - case sf::Keyboard::S: - case sf::Keyboard::Down: - case sf::Keyboard::Num2: - return Note::Arrow::DOWN; - - default: - return Note::Arrow::NONE; - } -} - -void Application::onKeyPressed(const sf::Keyboard::Key &key) -{ - if (key == sf::Keyboard::D) - { - _debug.toggle(); - return; - } - - onTap(keyToArrow(key)); -} - -void Application::onTap(const Note::Arrow &arrow) -{ - if (arrow == Note::Arrow::NONE) - return; - - const auto music_offset = _music.getPlayingOffset().asMicroseconds(); - auto note = _timeline->fetchActiveNote(music_offset); - - if (note) - { - auto tap_result = note->onTap(arrow, music_offset); - makeGradeString(tap_result.rating, _grade); - _grade.setFillColor(sf::Color(255, 255, 255, 255)); + _game->input(event); } } void Application::update() { - const auto music_offset = _music.getPlayingOffset().asMicroseconds(); - - _timeline->update(music_offset); - _debug.update(music_offset); - - if (_grade.getFillColor().a > 0) // TODO: Encapsulate - { - const auto alpha = _grade.getFillColor().a - 20; - _grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha)); - } } diff --git a/src/classicgame/classicgame.cpp b/src/classicgame/classicgame.cpp index 0823b59..9e819b2 100644 --- a/src/classicgame/classicgame.cpp +++ b/src/classicgame/classicgame.cpp @@ -1,7 +1,9 @@ #include "classicgame.h" #include "classicinputtype.h" +#include "classictimeline.h" -ClassicGame::ClassicGame() +ClassicGame::ClassicGame() : + _timeline(std::make_unique()) { _keys_to_buttons = { @@ -71,7 +73,8 @@ void ClassicGame::input(const sf::Event& event) } ClassicInputType input(timestamp, new_action); - /* Here get active Note from timeline and pass the input object to it */ + auto note = _timeline->getActiveNote(timestamp); + note-> } Action ClassicGame::getActionKeyPressed(Button button) const diff --git a/src/classicgame/classicgame.h b/src/classicgame/classicgame.h index 2ed6c21..4c7f6b9 100644 --- a/src/classicgame/classicgame.h +++ b/src/classicgame/classicgame.h @@ -6,6 +6,8 @@ #include "game.h" #include "classicactions.h" +class ClassicTimeline; + class ClassicGame final : public Game { public: @@ -25,6 +27,9 @@ private: Action getActionKeyPressed(Button button) const; Action getActionKeyReleased(Button button) const; + + std::unique_ptr _timeline; + }; #endif // CLASSICGAME_H diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp new file mode 100644 index 0000000..bd41958 --- /dev/null +++ b/src/classicgame/classicnote.cpp @@ -0,0 +1,8 @@ +#include "classicnote.h" + +ClassicNote::ClassicNote(const std::vector& intervals, microsec perfect_offset) : + Note(perfect_offset), + _evaluator(intervals, _perfect_offset) +{ + +} diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h new file mode 100644 index 0000000..0713bfb --- /dev/null +++ b/src/classicgame/classicnote.h @@ -0,0 +1,22 @@ +#pragma once + +#include "note.h" +#include "precisionevaluator.h" + +class ClassicNote : public Note +{ +public: + + enum class GRADE + { + PERFECT, + GOOD, + BAD + }; + + explicit ClassicNote(const std::vector& intervals, microsec perfect_offset); + virtual ~ClassicNote() = default; + +private: + PrecisionEvaluator _evaluator; +}; diff --git a/src/classicgame/classicsprite.cpp b/src/classicgame/classicsprite.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/classicgame/classicsprite.h b/src/classicgame/classicsprite.h new file mode 100644 index 0000000..e69de29 diff --git a/src/timeline.cpp b/src/classicgame/classictimeline.cpp similarity index 68% rename from src/timeline.cpp rename to src/classicgame/classictimeline.cpp index 374b75f..addc696 100644 --- a/src/timeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -1,12 +1,9 @@ -#include "timeline.h" -#include "note.h" -#include "timelineviewmanager.h" - -#include #include +#include "classicactions.h" +#include "classictimeline.h" +#include "note.h" -Timeline::Timeline(std::unique_ptr view_manager) : - _view_manager(std::move(view_manager)) +ClassicTimeline::ClassicTimeline() { // BPM of METEOR is 170. // Length is 1:14 @@ -22,15 +19,13 @@ Timeline::Timeline(std::unique_ptr view_manager) : microsec bpm_end = starting_beat_offset + (interval * amount_of_beats); _visibility_offset = note_input_offset * 12; - Note::resetPrecisionQualifier(note_input_offset / 3); - - _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Note::Arrow::DOWN)); + _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::DOWN)); bpm_iterator += interval; - _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Note::Arrow::LEFT)); + _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT)); bpm_iterator += interval; - _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Note::Arrow::LEFT)); + _timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT)); bpm_iterator += interval; while (bpm_iterator < bpm_end) @@ -39,19 +34,6 @@ Timeline::Timeline(std::unique_ptr view_manager) : bpm_iterator += interval; } - _timeline[0]->setPosition({200, 200}); - _timeline[1]->setPosition({250, 200}); - _timeline[2]->setPosition({300, 200}); - _timeline[3]->setPosition({350, 200}); - _timeline[4]->setPosition({400, 200}); - _timeline[5]->setPosition({450, 200}); - _timeline[6]->setPosition({200, 300}); - _timeline[7]->setPosition({250, 300}); - _timeline[8]->setPosition({300, 300}); - _timeline[9]->setPosition({350, 300}); - _timeline[10]->setPosition({400, 300}); - _timeline[11]->setPosition({450, 300}); - _active_note = nullptr; _last_visible_note = _timeline.end(); _top_note = _timeline.begin(); @@ -93,19 +75,6 @@ void Timeline::clear() Note::resetPrecisionQualifier(); } -void Timeline::draw(sf::RenderTarget& target, sf::RenderStates states) const // Temporary solution -{ - if (_last_visible_note == _timeline.end() || _top_note > _last_visible_note) - return; - - auto note_to_draw = _top_note; - while (note_to_draw != (_last_visible_note + 1)) - { - target.draw(*(*note_to_draw), states); - ++note_to_draw; - } -} - void Timeline::update(const microsec &music_offset) { checkCurrentActiveNote(music_offset); diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h new file mode 100644 index 0000000..796518c --- /dev/null +++ b/src/classicgame/classictimeline.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include "timeline.h" + +class Note; + +class ClassicTimeline : public Timeline +{ +public: + explicit ClassicTimeline(); + virtual void update(const microsec& music_offset) override; + virtual void init() override; + virtual void clear() override; + + Note *getActiveNote(const microsec &music_offset) noexcept; + +private: + std::vector _timeline; + std::vector::const_iterator _top_note; + Note* _active_note; + + std::vector::const_iterator _last_visible_note; + microsec _visibility_offset; + + 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 + * OR it's the closest note from current music offset + * position, not necessarily active. A note stops being top only + * after dying or being tapped by player, even if it's already + * past her perfect offset. + * + * Meanwhile active note is the note which is currently handling + * player input for grade. + * + * An active note is always top note but a top note + * is not always active note. + * */ +}; diff --git a/src/notegraphicsentity.cpp b/src/notegraphicsentity.cpp deleted file mode 100644 index ff4f052..0000000 --- a/src/notegraphicsentity.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "notegraphicsentity.h" - -NoteGraphicsEntity::NoteGraphicsEntity() : - _attached(false) -{} - -void NoteGraphicsEntity::attach() noexcept -{ - _attached = true; -} - -void NoteGraphicsEntity::detach() noexcept -{ - _attached = false; -} diff --git a/src/timelineviewmanager.cpp b/src/timelineviewmanager.cpp deleted file mode 100644 index 5ea914e..0000000 --- a/src/timelineviewmanager.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "timelineviewmanager.h" - -TimelineViewManager::TimelineViewManager() -{}