Implement more precise active note detection

This commit is contained in:
NaiJi ✨ 2021-06-11 20:39:47 +03:00
parent 192e371d2f
commit ad1b31c95c
12 changed files with 62 additions and 209 deletions

View File

@ -4,7 +4,6 @@
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
#include <SFML/Window/Keyboard.hpp> #include <SFML/Window/Keyboard.hpp>
#include "debughelper.h"
#include "timeline.h" #include "timeline.h"
#include "note.h" #include "note.h"
#include "game.h" #include "game.h"
@ -13,7 +12,6 @@ class Application
{ {
public: public:
Application(); Application();
~Application();
void run(); void run();
void input(); void input();
void update(); void update();
@ -21,13 +19,7 @@ public:
private: private:
sf::RenderWindow _game_window; sf::RenderWindow _game_window;
sf::Font _font;
sf::Text _grade;
std::unique_ptr<Timeline> _timeline; std::unique_ptr<Timeline> _timeline;
DebugHelper _debug;
std::unique_ptr<Game> _game; std::unique_ptr<Game> _game;
void exec(); void exec();

View File

@ -1,47 +0,0 @@
#ifndef DEBUGHELPER_H
#define DEBUGHELPER_H
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Text.hpp>
using microsec = sf::Int64;
class DebugHelper : public sf::Drawable
{
public:
DebugHelper(bool init = true);
void toggle();
void update(const microsec& microseconds);
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
void spawnGreenPulse();
void spawnRedPulse();
void spawnBluePulse();
private:
bool _toggled;
sf::Font _font;
sf::Text _time_print;
class Pulse : public sf::Drawable
{
public:
Pulse(sf::Vector2f position, sf::Color fill_color);
void appear();
void fade();
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
private:
sf::RectangleShape _pulse_shape;
};
Pulse _red_pulse;
Pulse _green_pulse;
Pulse _blue_pulse;
};
#endif // DEBUGHELPER_H

View File

@ -7,18 +7,7 @@ const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f);
Application::Application() : Application::Application() :
_game_window({1280, 720}, "Test"), _game_window({1280, 720}, "Test"),
_debug(true),
_game(std::make_unique<ClassicGame>()) _game(std::make_unique<ClassicGame>())
{
_font.loadFromFile("/usr/share/qtcreator/fonts/SourceCodePro-Regular.ttf");
_grade.setFont(_font);
_grade.setPosition(160, 160);
_grade.setFillColor(sf::Color(255, 0, 0));
_grade.setCharacterSize(35);
_grade.setString("NOT INIT");
}
Application::~Application()
{} {}
void Application::run() void Application::run()

View File

@ -8,7 +8,6 @@ ClassicGame::ClassicGame() :
_timeline(std::make_unique<ClassicTimeline>()), _timeline(std::make_unique<ClassicTimeline>()),
_view_manager(std::make_unique<ClassicViewManager>()) _view_manager(std::make_unique<ClassicViewManager>())
{ {
_font.loadFromFile("VeraMono.ttf");
_keys_to_buttons = _keys_to_buttons =
{ {
{sf::Keyboard::Up, Button::UP}, // Load from settings {sf::Keyboard::Up, Button::UP}, // Load from settings
@ -83,25 +82,9 @@ void ClassicGame::input(const sf::Event& event)
auto note = _timeline->getActiveNote(); auto note = _timeline->getActiveNote();
if (!_timeline->isExpired(note) || (*note)->state() != ClassicNote::State::DEAD) if (!_timeline->isExpired(note) && (*note)->state() == ClassicNote::State::FLYING)
{ {
auto grade = (*note)->input(ClassicInputType(timestamp, new_action)); (*note)->input(ClassicInputType(timestamp, new_action));
sf::Text new_grade;
new_grade.setFillColor(sf::Color::White);
new_grade.setPosition((*note)->getCoordinates().x, (*note)->getCoordinates().y - 40);
switch (grade)
{
case ClassicNote::Grade::PERFECT:
new_grade.setString("PERFECT"); break;
case ClassicNote::Grade::GOOD:
new_grade.setString("GOOD"); break;
case ClassicNote::Grade::BAD:
new_grade.setString("BAD"); break;
}
new_grade.setFont(_font);
_grades.emplace_back(new_grade);
} }
} }
@ -119,24 +102,9 @@ void ClassicGame::update()
{ {
_timeline->update(); _timeline->update();
_timeline->fetchVisibleNotes(_view_manager); _timeline->fetchVisibleNotes(_view_manager);
for (auto& grade : _grades)
{
if (grade.getFillColor().a > 20)
{
grade.setFillColor(sf::Color(255, 255, 255, grade.getFillColor().a - 20));
}
}
_grades.remove_if([](const auto& grade) { return grade.getFillColor().a <= 20; });
} }
void ClassicGame::draw(sf::RenderWindow& window) const void ClassicGame::draw(sf::RenderWindow& window) const
{ {
_timeline->drawVisibleNotes(window); _timeline->drawVisibleNotes(window);
for (auto& grade : _grades)
{
window.draw(grade);
}
} }

View File

@ -3,7 +3,6 @@
#include <map> #include <map>
#include <list> #include <list>
#include <SFML/Graphics/Text.hpp>
#include "game.h" #include "game.h"
#include "classicactions.h" #include "classicactions.h"
@ -32,9 +31,6 @@ private:
std::unique_ptr<ClassicTimeline> _timeline; std::unique_ptr<ClassicTimeline> _timeline;
std::unique_ptr<ClassicViewManager> _view_manager; std::unique_ptr<ClassicViewManager> _view_manager;
sf::Font _font;
std::list<sf::Text> _grades;
}; };
#endif // CLASSICGAME_H #endif // CLASSICGAME_H

View File

@ -34,7 +34,11 @@ void ClassicNote::update(const microsec& music_offset)
int xb = getPt( 1280./2. , _coordinates.x , i ); int xb = getPt( 1280./2. , _coordinates.x , i );
int yb = getPt( 720./2. , _coordinates.y , i ); int yb = getPt( 720./2. , _coordinates.y , i );
_sprite->setTrailCoordinates(getPt( xa , xb , i ), getPt( ya , yb , i )); _sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i ));
if (_state == State::DYING)
if (_sprite->isDead())
_state = State::DEAD;
} }
void ClassicNote::draw(sf::RenderTarget& target, sf::RenderStates states) const void ClassicNote::draw(sf::RenderTarget& target, sf::RenderStates states) const
@ -52,7 +56,8 @@ auto ClassicNote::input(ClassicInputType&& input_data) -> Grade
} }
std::cout << "User input: " << static_cast<int>(grade) << "\n"; std::cout << "User input: " << static_cast<int>(grade) << "\n";
_state = State::DEAD; _state = State::DYING;
_sprite->showGrade();
return grade; return grade;
} }

View File

@ -1,24 +1,53 @@
#include "classicsprite.h" #include "classicsprite.h"
#include <SFML/Graphics/RenderTarget.hpp> #include <SFML/Graphics/RenderTarget.hpp>
ClassicSprite::ClassicSprite(const sf::RectangleShape& shape) : ClassicSprite::ClassicSprite(const sf::RectangleShape& shape, const sf::Font& font) :
_shape(shape), _shape(shape),
_trail(shape) _trail(shape),
{} _font(font)
{
_grade_text.setFont(_font);
}
void ClassicSprite::draw(sf::RenderTarget& target, sf::RenderStates states) const void ClassicSprite::draw(sf::RenderTarget& target, sf::RenderStates states) const
{ {
target.draw(_shape, states); target.draw(_shape, states);
target.draw(_trail, states); target.draw(_trail, states);
target.draw(_grade_text, states);
} }
void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept
{ {
_shape.setPosition(x, y); _shape.setPosition(x, y);
_trail.setPosition(trail_x, trail_y); _trail.setPosition(trail_x, trail_y);
_grade_text.setPosition(x + _shape.getSize().x/2, y + 10);
} }
void ClassicSprite::setTrailCoordinates(float trail_x, float trail_y) noexcept void ClassicSprite::update(float trail_x, float trail_y) noexcept
{ {
_trail.setPosition(trail_x, trail_y); _trail.setPosition(trail_x, trail_y);
fade();
}
void ClassicSprite::showGrade()
{
_grade_text.setFillColor(sf::Color(255, 255, 255, 255));
}
void ClassicSprite::fade()
{
auto fill_color = _grade_text.getFillColor();
if (fill_color.a == 0)
return;
const auto new_alpha = fill_color.a - 55;
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
_grade_text.setFillColor(fill_color);
}
bool ClassicSprite::isDead() const
{
return _grade_text.getFillColor().a == 0;
} }

View File

@ -2,17 +2,23 @@
#include "sprite.h" #include "sprite.h"
#include "SFML/Graphics/RectangleShape.hpp" #include "SFML/Graphics/RectangleShape.hpp"
#include "SFML/Graphics/Text.hpp"
class ClassicSprite : public Sprite, public sf::Drawable class ClassicSprite : public Sprite, public sf::Drawable
{ {
public: public:
ClassicSprite(const sf::RectangleShape& shape); ClassicSprite(const sf::RectangleShape& shape, const sf::Font &font);
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
void setCoordinates(float x, float y, float trail_x, float trail_y) noexcept; void setCoordinates(float x, float y, float trail_x, float trail_y) noexcept;
void setTrailCoordinates(float trail_x, float trail_y) noexcept; void update(float trail_x, float trail_y) noexcept;
void showGrade();
void fade();
bool isDead() const;
private: private:
sf::RectangleShape _shape; sf::RectangleShape _shape;
sf::RectangleShape _trail; sf::RectangleShape _trail;
sf::Text _grade_text;
sf::Font _font;
}; };

View File

@ -79,7 +79,8 @@ void ClassicTimeline::update()
void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset)
{ {
if (!isExpired(_active_note) && !(*_active_note)->isActive(music_offset)) if (!isExpired(_active_note)
&& ((!(*_active_note)->isActive(music_offset)) || (*_active_note)->state() == ClassicNote::State::DEAD))
{ {
expire(_active_note); expire(_active_note);
++_top_note; ++_top_note;
@ -124,7 +125,9 @@ void ClassicTimeline::discardExpiredNotes(const std::unique_ptr<ClassicViewManag
Iterator past_note = _top_note - 1; Iterator past_note = _top_note - 1;
std::shared_ptr<ClassicSprite> sprite = (*past_note)->sprite(); std::shared_ptr<ClassicSprite> sprite = (*past_note)->sprite();
while (sprite) while (sprite)
{ // CAREFULLY REWRITE {
auto state = (*past_note)->state();
if (state == ClassicNote::State::DEAD || state == ClassicNote::State::FLYING)
view_manager->resetNoteSprite(*past_note); view_manager->resetNoteSprite(*past_note);
if (past_note == _timeline.begin()) if (past_note == _timeline.begin())
return; return;
@ -154,12 +157,9 @@ void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr<ClassicViewManager
} }
if (note->state() == ClassicNote::State::DEAD) if (note->state() == ClassicNote::State::DEAD)
{
view_manager->resetNoteSprite(note); view_manager->resetNoteSprite(note);
}
else
note->update(music_offset);
note->update(music_offset);
++note_iterator; ++note_iterator;
} }

View File

@ -13,6 +13,8 @@ ClassicViewManager::ClassicViewManager()
{ {
reallocatePoll(kind_of_action); reallocatePoll(kind_of_action);
} }
_font.loadFromFile("VeraMono.ttf");
} }
void ClassicViewManager::reallocatePoll(Action kind_of_action) void ClassicViewManager::reallocatePoll(Action kind_of_action)
@ -50,7 +52,7 @@ std::shared_ptr<ClassicSprite> ClassicViewManager::createSprite(Action kind_of_a
sprite.setFillColor(sf::Color(255, 239, 0)); sprite.setFillColor(sf::Color(255, 239, 0));
} }
return std::make_shared<ClassicSprite>(sprite); return std::make_shared<ClassicSprite>(sprite, _font);
} }
void ClassicViewManager::initNoteSprite(ClassicNote* note) void ClassicViewManager::initNoteSprite(ClassicNote* note)

View File

@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <stack> #include <stack>
#include <map> #include <map>
#include <SFML/Graphics/Font.hpp>
class ClassicSprite; class ClassicSprite;
class ClassicNote; class ClassicNote;
@ -25,6 +26,7 @@ private:
using SpritePoll = std::stack<std::shared_ptr<ClassicSprite>>; using SpritePoll = std::stack<std::shared_ptr<ClassicSprite>>;
std::map<Action, SpritePoll> _sprite_dispatcher; std::map<Action, SpritePoll> _sprite_dispatcher;
sf::Font _font;
}; };
#endif // CLASSICDIVAVIEWMANAGER_H #endif // CLASSICDIVAVIEWMANAGER_H

View File

@ -1,89 +0,0 @@
#include "debughelper.h"
DebugHelper::DebugHelper(bool 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))
{
_font.loadFromFile("/usr/share/qtcreator/fonts/SourceCodePro-Regular.ttf");
_time_print.setFont(_font);
_time_print.setPosition(60, 60);
_time_print.setFillColor(sf::Color(255, 255, 255));
_time_print.setCharacterSize(25);
}
void DebugHelper::toggle()
{
_toggled = !_toggled;
}
void DebugHelper::update(const microsec &microseconds)
{
_time_print.setString(std::to_string(microseconds));
_red_pulse.fade();
_green_pulse.fade();
_blue_pulse.fade();
}
void DebugHelper::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_toggled)
{
target.draw(_green_pulse, states);
target.draw(_red_pulse, states);
target.draw(_blue_pulse, states);
target.draw(_time_print, states);
}
}
void DebugHelper::spawnGreenPulse()
{
_green_pulse.appear();
}
void DebugHelper::spawnRedPulse()
{
_red_pulse.appear();
}
void DebugHelper::spawnBluePulse()
{
_blue_pulse.appear();
}
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::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(_pulse_shape, states);
}