diff --git a/include/application.h b/include/application.h index ea0d2e7..d46e189 100644 --- a/include/application.h +++ b/include/application.h @@ -20,7 +20,7 @@ public: private: sf::RenderWindow _game_window; std::unique_ptr _timeline; - std::unique_ptr _game; + std::shared_ptr _game; void exec(); }; diff --git a/include/precisionevaluator.h b/include/precisionevaluator.h index 97a4d7e..b3ecdd9 100644 --- a/include/precisionevaluator.h +++ b/include/precisionevaluator.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -18,9 +19,8 @@ public: _offset(offset), _intervals(intervals) { - microsec&& handling_offset = std::accumulate(intervals.begin(), intervals.end(), 0); - _start_handling_offset = _offset - handling_offset; - _end_handling_offset = _offset + handling_offset; + _start_handling_offset = _offset - intervals.back(); + _end_handling_offset = _offset + intervals.back(); } inline microsec offset() const noexcept @@ -38,6 +38,8 @@ public: { microsec shift_from_perfect = std::abs(odds - offset()); + std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ") << shift_from_perfect << "\n"; + std::size_t raw_grade; for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade) { diff --git a/src/application.cpp b/src/application.cpp index 8b28b7e..282d375 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -2,13 +2,21 @@ #include "classicgame/classicgame.h" #include #include +#include +#include +#include -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() : - _game_window({1280, 720}, "Test"), + _game_window({1280, 720}, "Test", sf::Style::Fullscreen ), _game(std::make_unique()) -{} +{ + _game_window.setFramerateLimit(60); + _game_window.setKeyRepeatEnabled(false); + _game_window.setMouseCursorGrabbed(false); + _game_window.setVerticalSyncEnabled(true); +} void Application::run() { @@ -21,18 +29,21 @@ void Application::run() void Application::exec() { sf::Clock timer; + sf::Clock game_timer; sf::Time time_since_last_update = sf::Time::Zero; while (_game_window.isOpen()) { - input(); time_since_last_update += timer.restart(); + input(); + bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME; if (isOneFramePassed) { time_since_last_update -= TIME_PER_FRAME; + game_timer.restart(); update(); draw(); } @@ -50,9 +61,15 @@ void Application::input() _game_window.close(); break; - default: + case sf::Event::KeyPressed: + case sf::Event::KeyReleased: + if (event.key.code == sf::Keyboard::Escape) + _game_window.close(); _game->input(event); break; + + default: + break; } } } diff --git a/src/classicgame/classicgame.cpp b/src/classicgame/classicgame.cpp index 47fcc78..28181b7 100644 --- a/src/classicgame/classicgame.cpp +++ b/src/classicgame/classicgame.cpp @@ -9,6 +9,10 @@ ClassicGame::ClassicGame() : _timeline(std::make_unique()), _graphics_manager(std::make_unique()) { + _slap_buffer.loadFromFile("very-final-slap.wav"); + _slap.setBuffer(_slap_buffer); + _slap.setVolume(50); + _keys_to_buttons = { {sf::Keyboard::Up, Button::UP}, // Load from settings @@ -86,6 +90,7 @@ void ClassicGame::input(const sf::Event& event) if (!_timeline->isExpired(note)) { (*note)->input(ClassicInputType(timestamp, new_action)); + _slap.play(); } } diff --git a/src/classicgame/classicgame.h b/src/classicgame/classicgame.h index a87311f..d08fa04 100644 --- a/src/classicgame/classicgame.h +++ b/src/classicgame/classicgame.h @@ -6,6 +6,8 @@ #include "game.h" #include "classicactions.h" #include "spritecontainer.h" +#include +#include class ClassicTimeline; class ClassicSprite; @@ -33,6 +35,8 @@ private: std::unique_ptr _timeline; std::unique_ptr _graphics_manager; + sf::SoundBuffer _slap_buffer; + sf::Sound _slap; }; #endif // CLASSICGAME_H diff --git a/src/classicgame/classicnote.cpp b/src/classicgame/classicnote.cpp index 00741e5..ed56c88 100644 --- a/src/classicgame/classicnote.cpp +++ b/src/classicgame/classicnote.cpp @@ -10,7 +10,8 @@ ClassicNote::ClassicNote(const std::vector& intervals, microsec perfec _evaluator(intervals, _perfect_offset), _action(action), _state(State::NONE), - _appearance_time(0) + _appearance_time(0), + _last_offset(0) {} 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); } -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 ); } @@ -37,15 +38,28 @@ void ClassicNote::update(const microsec& music_offset) case State::FLYING: { - 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 + float i; + if (music_offset != _last_offset) + { + auto update_time = music_offset - _appearance_time; // This all will be inside ::update + 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 ); - int ya = getPt( 0 , 720./2. , i ); - int xb = getPt( 1280./2. , _coordinates.x , i ); - int yb = getPt( 720./2. , _coordinates.y , i ); + _last_offset = music_offset; + + float xa = getPt( _coordinates.x + 20. , _coordinates.x + 90. , 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 )); + if (i >= 1) + _sprite->trailFade(); break; } @@ -92,7 +106,7 @@ void ClassicNote::setState(State next_state) break; 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; case State::NONE: diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h index 1ff2e16..f731baf 100644 --- a/src/classicgame/classicnote.h +++ b/src/classicgame/classicnote.h @@ -66,5 +66,6 @@ private: std::shared_ptr _sprite; microsec _appearance_time; + microsec _last_offset; float _trail_path_percent; //100% for sprite falling trajectory }; diff --git a/src/classicgame/classicsprite.cpp b/src/classicgame/classicsprite.cpp index 092368e..d28d05f 100644 --- a/src/classicgame/classicsprite.cpp +++ b/src/classicgame/classicsprite.cpp @@ -26,6 +26,7 @@ void ClassicSprite::reset() _shape = _prototype; _trail = _prototype; + _trail_fade = false; } 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 { _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 @@ -76,6 +90,11 @@ void ClassicSprite::fade() _shape.setFillColor(fill_color); } +void ClassicSprite::trailFade() +{ + _trail_fade = true; +} + bool ClassicSprite::isDead() const { return _grade_text.getFillColor().a == 0 diff --git a/src/classicgame/classicsprite.h b/src/classicgame/classicsprite.h index 4c13f7e..9820925 100644 --- a/src/classicgame/classicsprite.h +++ b/src/classicgame/classicsprite.h @@ -17,6 +17,7 @@ public: void pulse(); void fade(); + void trailFade(); bool isDead() const; private: @@ -26,4 +27,6 @@ private: sf::RectangleShape _trail; sf::Text _grade_text; sf::Font _font; + + bool _trail_fade = false; }; diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp index 3331b1f..fad1be9 100644 --- a/src/classicgame/classictimeline.cpp +++ b/src/classicgame/classictimeline.cpp @@ -23,27 +23,26 @@ ClassicTimeline::ClassicTimeline() microsec starting_beat_offset = 352162; int amount_of_beats = 209; 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_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})); - bpm_iterator += interval; + _input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset}; - _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {190, 90})); - bpm_iterator += interval; - - _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {290, 90})); - bpm_iterator += interval; + bpm_iterator += tempo_interval; float x = 90.; while (bpm_iterator < bpm_end) { - _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP, {x, 390.})); - bpm_iterator += interval; + _timeline.emplace_back(new ClassicNote(_input_intervals, bpm_iterator, Action::PRESS_UP, {x, 390.})); + bpm_iterator += tempo_interval; x += 70; + + if (x >= 1200) + x = 90.; } expire(_first_visible_note); diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h index b703edc..defc5c5 100644 --- a/src/classicgame/classictimeline.h +++ b/src/classicgame/classictimeline.h @@ -28,16 +28,12 @@ public: Iterator getActiveNote() noexcept; - bool isExpired(const Iterator& iterator) const; - void expire(Iterator& iterator); + inline bool isExpired(const Iterator& iterator) const; + inline void expire(Iterator& iterator); private: + std::vector _input_intervals; std::vector _timeline; - Iterator _top_note; - Iterator _active_note; - Iterator _last_visible_note; - Iterator _first_visible_note; - microsec _visibility_offset; sf::Music _music; @@ -46,7 +42,7 @@ private: void checkCurrentActiveNote(const microsec& music_offset); void checkForNextActiveNote(const microsec& music_offset); 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 * 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 * is not always active note. * */ + + Iterator _top_note; + Iterator _active_note; + Iterator _last_visible_note; + Iterator _first_visible_note; };