Improve and encapsulate DebugHelper, work on Note
This commit is contained in:
parent
e37fb7b539
commit
47277ee754
|
@ -1,6 +1,10 @@
|
|||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
SFML*
|
||||
CMake*
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
|
|
|
@ -20,16 +20,26 @@ void Application::run()
|
|||
// BPM of METEOR is 170.
|
||||
// Length is 1:14
|
||||
// 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)
|
||||
{
|
||||
Note note(iter, iter + 412162);
|
||||
Note note(iter, note_input_offset);
|
||||
_timeline.push(note);
|
||||
iter -= 1412162;
|
||||
iter -= time_between_beats;
|
||||
}
|
||||
|
||||
// // // // // // // //
|
||||
|
||||
_music.openFromFile("/home/naiji/METEOR.flac");
|
||||
_music.openFromFile(song_filename);
|
||||
_music.play();
|
||||
_music.setVolume(5);
|
||||
|
||||
|
@ -154,7 +164,7 @@ void Application::onKeyPressed(const sf::Keyboard::Key &key)
|
|||
|
||||
if (arrow != Note::Arrow::NONE)
|
||||
{
|
||||
_debug.onUserTap();
|
||||
_debug.spawnGreenPulse();
|
||||
|
||||
if (!_timeline.empty())
|
||||
{
|
||||
|
@ -169,17 +179,29 @@ void Application::update()
|
|||
{
|
||||
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();
|
||||
_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);
|
||||
|
||||
if (_grade.getFillColor().a > 0)
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
#include "debughelper.h"
|
||||
|
||||
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");
|
||||
|
||||
_time_print.setFont(_font);
|
||||
|
@ -26,59 +19,71 @@ void DebugHelper::toggle()
|
|||
_toggled = !_toggled;
|
||||
}
|
||||
|
||||
static bool isVisible(const sf::Shape* shape)
|
||||
{
|
||||
return shape->getFillColor().a > 0;
|
||||
}
|
||||
|
||||
void DebugHelper::update(const sf::Int64 µseconds)
|
||||
void DebugHelper::update(const microsec µseconds)
|
||||
{
|
||||
_time_print.setString(std::to_string(microseconds));
|
||||
|
||||
if (isVisible(&_bpm_pulse))
|
||||
{
|
||||
const auto new_alpha = _bpm_pulse.getFillColor().a - 25;
|
||||
_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));
|
||||
}
|
||||
_red_pulse.fade();
|
||||
_green_pulse.fade();
|
||||
_blue_pulse.fade();
|
||||
}
|
||||
|
||||
void DebugHelper::drawOn(sf::RenderWindow &game_window) const
|
||||
{
|
||||
if (_toggled)
|
||||
{
|
||||
game_window.draw(_bpm_pulse);
|
||||
game_window.draw(_tap_pulse);
|
||||
game_window.draw(_death_pulse);
|
||||
_red_pulse.drawOn(game_window);
|
||||
_green_pulse.drawOn(game_window);
|
||||
_blue_pulse.drawOn(game_window);
|
||||
game_window.draw(_time_print);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHelper::onUserTap()
|
||||
void DebugHelper::spawnGreenPulse()
|
||||
{
|
||||
const sf::Uint8 alpha = 255;
|
||||
_tap_pulse.setFillColor(sf::Color(255, 0, 0, alpha));
|
||||
_green_pulse.appear();
|
||||
}
|
||||
|
||||
void DebugHelper::onBeat()
|
||||
void DebugHelper::spawnRedPulse()
|
||||
{
|
||||
const sf::Uint8 alpha = 255;
|
||||
_bpm_pulse.setFillColor(sf::Color(0, 255, 0, alpha));
|
||||
_red_pulse.appear();
|
||||
}
|
||||
|
||||
void DebugHelper::onDeath()
|
||||
void DebugHelper::spawnBluePulse()
|
||||
{
|
||||
const sf::Uint8 alpha = 255;
|
||||
_death_pulse.setFillColor(sf::Color(0, 100, 255, alpha));
|
||||
_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::drawOn(sf::RenderWindow &game_window) const
|
||||
{
|
||||
game_window.draw(_pulse_shape);
|
||||
}
|
||||
|
|
|
@ -6,25 +6,42 @@
|
|||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
|
||||
using microsec = sf::Int64;
|
||||
|
||||
class DebugHelper
|
||||
{
|
||||
public:
|
||||
DebugHelper(bool init = true);
|
||||
|
||||
void toggle();
|
||||
void update(const sf::Int64& microseconds);
|
||||
void update(const microsec& microseconds);
|
||||
void drawOn(sf::RenderWindow &game_window) const;
|
||||
void onUserTap();
|
||||
void onBeat();
|
||||
void onDeath();
|
||||
|
||||
void spawnGreenPulse();
|
||||
void spawnRedPulse();
|
||||
void spawnBluePulse();
|
||||
|
||||
private:
|
||||
bool _toggled;
|
||||
sf::RectangleShape _bpm_pulse;
|
||||
sf::RectangleShape _tap_pulse;
|
||||
sf::RectangleShape _death_pulse;
|
||||
sf::Font _font;
|
||||
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
|
||||
|
|
41
note.cpp
41
note.cpp
|
@ -1,22 +1,28 @@
|
|||
#include "note.h"
|
||||
#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),
|
||||
_death_offset(death_offset),
|
||||
_start_handling_offset(_offset + life_span_offset),
|
||||
_end_handling_offset(_offset - life_span_offset),
|
||||
_type(type)
|
||||
{}
|
||||
|
||||
void Note::setPosition(coordinates position)
|
||||
{
|
||||
_position = position;
|
||||
}
|
||||
|
||||
coordinates Note::position() const noexcept
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
||||
microsec Note::offset() const noexcept
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
|
||||
microsec Note::deathOffset() const noexcept
|
||||
{
|
||||
return _death_offset;
|
||||
}
|
||||
|
||||
NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const
|
||||
{
|
||||
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 ret;
|
||||
if (odds < 412162)
|
||||
NoteGrade ret(0, NoteGrade::Rating::BAD);
|
||||
|
||||
if (odds < _precision_qualifier)
|
||||
{
|
||||
ret.score = 50;
|
||||
ret.rating = NoteGrade::Rating::GREAT;
|
||||
ret = {50, NoteGrade::Rating::GREAT};
|
||||
}
|
||||
|
||||
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
28
note.h
|
@ -2,21 +2,29 @@
|
|||
#define NOTE_H
|
||||
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
using microsec = sf::Int64;
|
||||
using coordinates = sf::Vector2i;
|
||||
|
||||
struct NoteGrade
|
||||
{
|
||||
int score = 0;
|
||||
int score;
|
||||
enum class Rating
|
||||
{
|
||||
WRONG,
|
||||
BAD,
|
||||
GOOD,
|
||||
GREAT
|
||||
} rating = Rating::BAD;
|
||||
} rating;
|
||||
|
||||
NoteGrade(int s, Rating r) : score(s), rating(r) {}
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
class Note
|
||||
{
|
||||
public:
|
||||
|
@ -30,17 +38,25 @@ public:
|
|||
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;
|
||||
microsec offset() const noexcept;
|
||||
microsec deathOffset() const noexcept;
|
||||
bool isActive(microsec music_play_offset) const noexcept;
|
||||
|
||||
static void setPrecisionQualifier(microsec qualifier);
|
||||
|
||||
private:
|
||||
coordinates _position;
|
||||
microsec _offset;
|
||||
microsec _death_offset;
|
||||
microsec _start_handling_offset;
|
||||
microsec _end_handling_offset;
|
||||
Arrow _type = Arrow::UP;
|
||||
|
||||
static microsec _precision_qualifier;
|
||||
NoteGrade calculatePrecision(microsec odds) const;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue