Improve and encapsulate DebugHelper, work on Note

This commit is contained in:
NaiJi ✨ 2021-04-06 20:39:29 +03:00
parent e37fb7b539
commit 47277ee754
6 changed files with 162 additions and 79 deletions

4
.gitignore vendored
View File

@ -1,6 +1,10 @@
# This file is used to ignore files which are generated # This file is used to ignore files which are generated
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
SFML*
CMake*
*~ *~
*.autosave *.autosave
*.a *.a

View File

@ -20,16 +20,26 @@ void Application::run()
// BPM of METEOR is 170. // BPM of METEOR is 170.
// Length is 1:14 // Length is 1:14
// I calculated that the time between beats is about 1412162 microseconds // I calculated that the time between beats is about 1412162 microseconds
sf::Int64 iter = 1412162 * 25;
std::string song_filename = "/home/naiji/METEOR.flac";
microsec starting_beat_offset = 372162;
int amount_of_beats = 209;
microsec time_between_beats = 1412162;
microsec note_input_offset = 412162;
sf::Int64 iter = starting_beat_offset + (time_between_beats * amount_of_beats);
Note::setPrecisionQualifier(note_input_offset / 2);
while (iter > 0) while (iter > 0)
{ {
Note note(iter, iter + 412162); Note note(iter, note_input_offset);
_timeline.push(note); _timeline.push(note);
iter -= 1412162; iter -= time_between_beats;
} }
// // // // // // // // // // // // // // // //
_music.openFromFile("/home/naiji/METEOR.flac"); _music.openFromFile(song_filename);
_music.play(); _music.play();
_music.setVolume(5); _music.setVolume(5);
@ -154,7 +164,7 @@ void Application::onKeyPressed(const sf::Keyboard::Key &key)
if (arrow != Note::Arrow::NONE) if (arrow != Note::Arrow::NONE)
{ {
_debug.onUserTap(); _debug.spawnGreenPulse();
if (!_timeline.empty()) if (!_timeline.empty())
{ {
@ -169,17 +179,29 @@ void Application::update()
{ {
const auto microseconds = _music.getPlayingOffset().asMicroseconds(); const auto microseconds = _music.getPlayingOffset().asMicroseconds();
if (!_timeline.empty() && _timeline.top().offset() <= microseconds) // To Do: Here we notice when next note becomes active and ready for user input.
// Here I explicitly calculate its birth time for now.
if (!_timeline.empty() && _timeline.top().offset() - 412162 <= microseconds)
{ {
_debug.onBeat(); _debug.spawnBluePulse();
} }
if (!_timeline.empty() && _timeline.top().deathOffset() <= microseconds) // To do: Actual note offset should pulse only once and the note shouldn't die right after it,
// because there is also "after pulse" offset, like, you know, player can be a little late
if (!_timeline.empty() && _timeline.top().offset() <= microseconds)
{ {
_timeline.pop(); _timeline.pop();
_debug.onDeath(); _debug.spawnRedPulse();
} }
// To do: Here should be the end of "after pulse" time. When user fucked up all the time and the
// note dies with "Missed" grade.
//
// if ( . . . _timeline.top().offset() + 412162 <= microseconds)
// {
//
// }
_debug.update(microseconds); _debug.update(microseconds);
if (_grade.getFillColor().a > 0) if (_grade.getFillColor().a > 0)

View File

@ -1,18 +1,11 @@
#include "debughelper.h" #include "debughelper.h"
DebugHelper::DebugHelper(bool init) : DebugHelper::DebugHelper(bool init) :
_toggled(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))
{ {
_bpm_pulse.setSize({460, 360});
_bpm_pulse.setOrigin(0.f, 0.f);
_bpm_pulse.setFillColor(sf::Color(255, 0, 0, 0));
_tap_pulse.setSize({460, 360});
_tap_pulse.move(460.f, 0.f);
_tap_pulse.setFillColor(sf::Color(0, 255, 0, 0));
_death_pulse.setSize({460, 360});
_death_pulse.move(460.f, 360.f);
_death_pulse.setFillColor(sf::Color(0, 100, 255, 0));
_font.loadFromFile("VeraMono.ttf"); _font.loadFromFile("VeraMono.ttf");
_time_print.setFont(_font); _time_print.setFont(_font);
@ -26,59 +19,71 @@ void DebugHelper::toggle()
_toggled = !_toggled; _toggled = !_toggled;
} }
static bool isVisible(const sf::Shape* shape) void DebugHelper::update(const microsec &microseconds)
{
return shape->getFillColor().a > 0;
}
void DebugHelper::update(const sf::Int64 &microseconds)
{ {
_time_print.setString(std::to_string(microseconds)); _time_print.setString(std::to_string(microseconds));
if (isVisible(&_bpm_pulse)) _red_pulse.fade();
{ _green_pulse.fade();
const auto new_alpha = _bpm_pulse.getFillColor().a - 25; _blue_pulse.fade();
_bpm_pulse.setFillColor(sf::Color(255, 0, 0, (new_alpha < 0) ? 0 : new_alpha));
}
if (isVisible(&_tap_pulse))
{
const auto new_alpha = _tap_pulse.getFillColor().a - 25;
_tap_pulse.setFillColor(sf::Color(0, 255, 0, (new_alpha < 0) ? 0 : new_alpha));
}
if (isVisible(&_death_pulse))
{
const auto new_alpha = _death_pulse.getFillColor().a - 25;
_death_pulse.setFillColor(sf::Color(0, 100, 255, (new_alpha < 0) ? 0 : new_alpha));
}
} }
void DebugHelper::drawOn(sf::RenderWindow &game_window) const void DebugHelper::drawOn(sf::RenderWindow &game_window) const
{ {
if (_toggled) if (_toggled)
{ {
game_window.draw(_bpm_pulse); _red_pulse.drawOn(game_window);
game_window.draw(_tap_pulse); _green_pulse.drawOn(game_window);
game_window.draw(_death_pulse); _blue_pulse.drawOn(game_window);
game_window.draw(_time_print); game_window.draw(_time_print);
} }
} }
void DebugHelper::onUserTap() void DebugHelper::spawnGreenPulse()
{ {
const sf::Uint8 alpha = 255; _green_pulse.appear();
_tap_pulse.setFillColor(sf::Color(255, 0, 0, alpha));
} }
void DebugHelper::onBeat() void DebugHelper::spawnRedPulse()
{ {
const sf::Uint8 alpha = 255; _red_pulse.appear();
_bpm_pulse.setFillColor(sf::Color(0, 255, 0, alpha));
} }
void DebugHelper::onDeath() void DebugHelper::spawnBluePulse()
{ {
const sf::Uint8 alpha = 255; _blue_pulse.appear();
_death_pulse.setFillColor(sf::Color(0, 100, 255, alpha)); }
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::drawOn(sf::RenderWindow &game_window) const
{
game_window.draw(_pulse_shape);
} }

View File

@ -6,25 +6,42 @@
#include <SFML/Graphics/Font.hpp> #include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Text.hpp> #include <SFML/Graphics/Text.hpp>
using microsec = sf::Int64;
class DebugHelper class DebugHelper
{ {
public: public:
DebugHelper(bool init = true); DebugHelper(bool init = true);
void toggle(); void toggle();
void update(const sf::Int64& microseconds); void update(const microsec& microseconds);
void drawOn(sf::RenderWindow &game_window) const; void drawOn(sf::RenderWindow &game_window) const;
void onUserTap();
void onBeat(); void spawnGreenPulse();
void onDeath(); void spawnRedPulse();
void spawnBluePulse();
private: private:
bool _toggled; bool _toggled;
sf::RectangleShape _bpm_pulse;
sf::RectangleShape _tap_pulse;
sf::RectangleShape _death_pulse;
sf::Font _font; sf::Font _font;
sf::Text _time_print; sf::Text _time_print;
class Pulse
{
public:
Pulse(sf::Vector2f position, sf::Color fill_color);
void appear();
void fade();
void drawOn(sf::RenderWindow &game_window) const;
private:
sf::RectangleShape _pulse_shape;
};
Pulse _red_pulse;
Pulse _green_pulse;
Pulse _blue_pulse;
}; };
#endif // DEBUGHELPER_H #endif // DEBUGHELPER_H

View File

@ -1,22 +1,28 @@
#include "note.h" #include "note.h"
#include <cmath> #include <cmath>
Note::Note(microsec offset, microsec death_offset, Note::Arrow type) : Note::Note(microsec offset, microsec life_span_offset, Note::Arrow type) :
_offset(offset), _offset(offset),
_death_offset(death_offset), _start_handling_offset(_offset + life_span_offset),
_end_handling_offset(_offset - life_span_offset),
_type(type) _type(type)
{} {}
void Note::setPosition(coordinates position)
{
_position = position;
}
coordinates Note::position() const noexcept
{
return _position;
}
microsec Note::offset() const noexcept microsec Note::offset() const noexcept
{ {
return _offset; return _offset;
} }
microsec Note::deathOffset() const noexcept
{
return _death_offset;
}
NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const
{ {
if (arrow_type != _type) if (arrow_type != _type)
@ -28,12 +34,25 @@ NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const
NoteGrade Note::calculatePrecision(microsec odds) const NoteGrade Note::calculatePrecision(microsec odds) const
{ {
NoteGrade ret; NoteGrade ret(0, NoteGrade::Rating::BAD);
if (odds < 412162)
if (odds < _precision_qualifier)
{ {
ret.score = 50; ret = {50, NoteGrade::Rating::GREAT};
ret.rating = NoteGrade::Rating::GREAT;
} }
return ret; return ret;
} }
bool Note::isActive(microsec music_play_offset) const noexcept
{
return music_play_offset > _start_handling_offset
&& music_play_offset < _end_handling_offset;
}
void Note::setPrecisionQualifier(microsec qualifier)
{
_precision_qualifier = qualifier;
}
microsec Note::_precision_qualifier = 500000; // Default initialization as 0.5 second.

28
note.h
View File

@ -2,21 +2,29 @@
#define NOTE_H #define NOTE_H
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
#include <SFML/System/Vector2.hpp>
////////////////////////////////
using microsec = sf::Int64; using microsec = sf::Int64;
using coordinates = sf::Vector2i;
struct NoteGrade struct NoteGrade
{ {
int score = 0; int score;
enum class Rating enum class Rating
{ {
WRONG, WRONG,
BAD, BAD,
GOOD, GOOD,
GREAT GREAT
} rating = Rating::BAD; } rating;
NoteGrade(int s, Rating r) : score(s), rating(r) {}
}; };
////////////////////////////////
class Note class Note
{ {
public: public:
@ -30,17 +38,25 @@ public:
NONE NONE
}; };
Note(microsec offset, microsec death_offset, Note::Arrow type = Note::Arrow::UP); Note(microsec offset, microsec life_span_offset, Note::Arrow type = Note::Arrow::UP);
void setPosition(coordinates position);
coordinates position() const noexcept;
microsec offset() const noexcept;
NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const; NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const;
microsec offset() const noexcept; bool isActive(microsec music_play_offset) const noexcept;
microsec deathOffset() const noexcept;
static void setPrecisionQualifier(microsec qualifier);
private: private:
coordinates _position;
microsec _offset; microsec _offset;
microsec _death_offset; microsec _start_handling_offset;
microsec _end_handling_offset;
Arrow _type = Arrow::UP; Arrow _type = Arrow::UP;
static microsec _precision_qualifier;
NoteGrade calculatePrecision(microsec odds) const; NoteGrade calculatePrecision(microsec odds) const;
}; };