Add debug helper and clean init code
This commit is contained in:
parent
bf8e6be88f
commit
e37fb7b539
230
application.cpp
230
application.cpp
|
@ -1,81 +1,60 @@
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include <SFML/Graphics/Color.hpp>
|
#include <SFML/Graphics/Color.hpp>
|
||||||
#include <SFML/Window/Event.hpp>
|
#include <SFML/Window/Event.hpp>
|
||||||
#include <SFML/Window/Keyboard.hpp>
|
|
||||||
|
|
||||||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f);
|
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)
|
||||||
{
|
{
|
||||||
float x = game_window.getSize().x;
|
_font.loadFromFile("VeraMono.ttf");
|
||||||
float y = game_window.getSize().y;
|
_grade.setFont(_font);
|
||||||
pulse_mask.setSize({x, y});
|
_grade.setPosition(160, 160);
|
||||||
pulse_mask.setOrigin(0.f, 0.f);
|
_grade.setFillColor(sf::Color(255, 255, 255, 0));
|
||||||
pulse_mask.setFillColor(sf::Color(255, 0, 0, 0));
|
_grade.setCharacterSize(35);
|
||||||
pulse_mask_green.setSize({x, y});
|
|
||||||
pulse_mask_green.setOrigin(0.f, 0.f);
|
|
||||||
pulse_mask_green.setFillColor(sf::Color(0, 255, 0, 0));
|
|
||||||
font.loadFromFile("VeraMono.ttf");
|
|
||||||
font2.loadFromFile("VeraMono.ttf");
|
|
||||||
text.setFont(font);
|
|
||||||
text.setPosition(60, 60);
|
|
||||||
text.setFillColor(sf::Color(255, 255, 255));
|
|
||||||
text.setCharacterSize(25);
|
|
||||||
|
|
||||||
grade.setFont(font2);
|
|
||||||
grade.setPosition(100, 100);
|
|
||||||
grade.setFillColor(sf::Color(255, 255, 255, 0));
|
|
||||||
grade.setCharacterSize(35);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::run()
|
void Application::run()
|
||||||
{
|
{
|
||||||
game_window.display();
|
// BPM of METEOR is 170.
|
||||||
sf::Int64 iter = 9000 + (1412162 * 25);
|
// Length is 1:14
|
||||||
while (iter > 9000)
|
// I calculated that the time between beats is about 1412162 microseconds
|
||||||
|
sf::Int64 iter = 1412162 * 25;
|
||||||
|
while (iter > 0)
|
||||||
{
|
{
|
||||||
Note note(iter, iter + 412162);
|
Note note(iter, iter + 412162);
|
||||||
timeline.push(note);
|
_timeline.push(note);
|
||||||
iter -= 1412162;
|
iter -= 1412162;
|
||||||
}
|
}
|
||||||
|
// // // // // // // //
|
||||||
|
|
||||||
|
_music.openFromFile("/home/naiji/METEOR.flac");
|
||||||
|
_music.play();
|
||||||
|
_music.setVolume(5);
|
||||||
|
|
||||||
|
_game_window.display();
|
||||||
|
|
||||||
|
startGameLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool isOneFramePassed(const sf::Time& time_since_last_update)
|
||||||
|
{
|
||||||
|
return time_since_last_update >= TIME_PER_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::startGameLoop()
|
||||||
|
{
|
||||||
sf::Clock timer;
|
sf::Clock timer;
|
||||||
sf::Time time_since_last_update = sf::Time::Zero;
|
sf::Time time_since_last_update = sf::Time::Zero;
|
||||||
music.openFromFile("/home/naiji/METEOR.flac");
|
|
||||||
music.play();
|
while (_game_window.isOpen())
|
||||||
while (game_window.isOpen())
|
|
||||||
{
|
{
|
||||||
sf::Event event;
|
input();
|
||||||
while (game_window.pollEvent(event))
|
|
||||||
{
|
|
||||||
if (event.type == sf::Event::Closed)
|
|
||||||
game_window.close();
|
|
||||||
|
|
||||||
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Z && !timeline.empty())
|
|
||||||
{
|
|
||||||
const auto current_note = timeline.top();
|
|
||||||
const auto grade_result = current_note.onTap(Note::Arrow::UP, music.getPlayingOffset().asMicroseconds());
|
|
||||||
pulse_mask.setFillColor(sf::Color(255, 0, 0, 255));
|
|
||||||
switch (grade_result.rating)
|
|
||||||
{
|
|
||||||
case (NoteGrade::Rating::BAD):
|
|
||||||
grade.setString("BAD");
|
|
||||||
grade.setFillColor(sf::Color(255, 255, 255, 255));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (NoteGrade::Rating::GREAT):
|
|
||||||
grade.setString("GREAT");
|
|
||||||
grade.setFillColor(sf::Color(255, 255, 0, 255));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
time_since_last_update += timer.restart();
|
time_since_last_update += timer.restart();
|
||||||
if (time_since_last_update >= TIME_PER_FRAME)
|
if (isOneFramePassed(time_since_last_update))
|
||||||
{
|
{
|
||||||
time_since_last_update -= TIME_PER_FRAME;
|
time_since_last_update -= TIME_PER_FRAME;
|
||||||
update();
|
update();
|
||||||
|
@ -84,42 +63,137 @@ void Application::run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sf::Text makeGradeString(const NoteGrade::Rating& rating)
|
||||||
|
{
|
||||||
|
sf::Text ret;
|
||||||
|
switch (rating)
|
||||||
|
{
|
||||||
|
case (NoteGrade::Rating::BAD):
|
||||||
|
ret.setString("BAD");
|
||||||
|
ret.setFillColor(sf::Color(255, 255, 255, 255));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (NoteGrade::Rating::GREAT):
|
||||||
|
ret.setString("GREAT");
|
||||||
|
ret.setFillColor(sf::Color(255, 255, 0, 255));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (NoteGrade::Rating::WRONG):
|
||||||
|
ret.setString("WRONG");
|
||||||
|
ret.setFillColor(sf::Color(120, 120, 120, 255));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (NoteGrade::Rating::GOOD):
|
||||||
|
ret.setString("GOOD");
|
||||||
|
ret.setFillColor(sf::Color(255, 100, 120, 255));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto arrow = keyToArrow(key);
|
||||||
|
|
||||||
|
if (arrow != Note::Arrow::NONE)
|
||||||
|
{
|
||||||
|
_debug.onUserTap();
|
||||||
|
|
||||||
|
if (!_timeline.empty())
|
||||||
|
{
|
||||||
|
const auto current_note = _timeline.top();
|
||||||
|
const auto grade_result = current_note.onTap(arrow, _music.getPlayingOffset().asMicroseconds());
|
||||||
|
_grade = makeGradeString(grade_result.rating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::update()
|
void Application::update()
|
||||||
{
|
{
|
||||||
if (!timeline.empty() && timeline.top().deathOffset() <= music.getPlayingOffset().asMicroseconds())
|
const auto microseconds = _music.getPlayingOffset().asMicroseconds();
|
||||||
|
|
||||||
|
if (!_timeline.empty() && _timeline.top().offset() <= microseconds)
|
||||||
{
|
{
|
||||||
timeline.pop();
|
_debug.onBeat();
|
||||||
pulse_mask_green.setFillColor(sf::Color(0, 255, 0, 255));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text.setString(std::to_string(music.getPlayingOffset().asSeconds()));
|
if (!_timeline.empty() && _timeline.top().deathOffset() <= microseconds)
|
||||||
|
|
||||||
if (pulse_mask.getFillColor().a > 0)
|
|
||||||
{
|
{
|
||||||
const auto alpha = pulse_mask.getFillColor().a - 25;
|
_timeline.pop();
|
||||||
pulse_mask.setFillColor(sf::Color(255, 0, 0, alpha < 0 ? 0 : alpha));
|
_debug.onDeath();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pulse_mask_green.getFillColor().a > 0)
|
_debug.update(microseconds);
|
||||||
{
|
|
||||||
const auto alpha = pulse_mask_green.getFillColor().a - 25;
|
|
||||||
pulse_mask_green.setFillColor(sf::Color(0, 255, 0, alpha < 0 ? 0 : alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grade.getFillColor().a > 0)
|
if (_grade.getFillColor().a > 0)
|
||||||
{
|
{
|
||||||
const auto alpha = grade.getFillColor().a - 20;
|
const auto alpha = _grade.getFillColor().a - 20;
|
||||||
grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha));
|
_grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::draw()
|
void Application::draw()
|
||||||
{
|
{
|
||||||
game_window.clear();
|
_game_window.clear();
|
||||||
game_window.draw(pulse_mask);
|
_debug.drawOn(_game_window);
|
||||||
game_window.draw(pulse_mask_green);
|
_game_window.draw(_grade);
|
||||||
game_window.draw(text);
|
_game_window.display();
|
||||||
game_window.draw(grade);
|
|
||||||
game_window.display();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#ifndef APPLICATION_H
|
#ifndef APPLICATION_H
|
||||||
#define APPLICATION_H
|
#define APPLICATION_H
|
||||||
|
|
||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
|
||||||
#include <SFML/Audio/Music.hpp>
|
#include <SFML/Audio/Music.hpp>
|
||||||
#include <SFML/System/Clock.hpp>
|
#include <SFML/System/Clock.hpp>
|
||||||
#include <SFML/Graphics/Text.hpp>
|
#include <SFML/Window/Keyboard.hpp>
|
||||||
#include <SFML/Graphics/Font.hpp>
|
|
||||||
#include <SFML/Graphics/RectangleShape.hpp>
|
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
|
#include "debughelper.h"
|
||||||
#include "note.h"
|
#include "note.h"
|
||||||
|
|
||||||
class Application
|
class Application
|
||||||
|
@ -17,22 +15,24 @@ class Application
|
||||||
public:
|
public:
|
||||||
Application();
|
Application();
|
||||||
void run();
|
void run();
|
||||||
|
void input();
|
||||||
void update();
|
void update();
|
||||||
void draw();
|
void draw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::RenderWindow game_window;
|
sf::RenderWindow _game_window;
|
||||||
sf::Music music;
|
sf::Music _music;
|
||||||
sf::RectangleShape pulse_mask;
|
|
||||||
sf::RectangleShape pulse_mask_green;
|
|
||||||
|
|
||||||
std::stack<Note> timeline;
|
std::stack<Note> _timeline;
|
||||||
sf::Int64 time_since_last_tick;
|
sf::Int64 _time_since_last_tick;
|
||||||
sf::Int64 last_stamp;
|
sf::Int64 _last_stamp;
|
||||||
sf::Font font;
|
sf::Font _font;
|
||||||
sf::Font font2;
|
sf::Text _grade;
|
||||||
sf::Text text;
|
|
||||||
sf::Text grade;
|
DebugHelper _debug;
|
||||||
|
|
||||||
|
void startGameLoop();
|
||||||
|
void onKeyPressed(const sf::Keyboard::Key& key);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APPLICATION_H
|
#endif // APPLICATION_H
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include "debughelper.h"
|
||||||
|
|
||||||
|
DebugHelper::DebugHelper(bool init) :
|
||||||
|
_toggled(init)
|
||||||
|
{
|
||||||
|
_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);
|
||||||
|
_time_print.setPosition(60, 60);
|
||||||
|
_time_print.setFillColor(sf::Color(255, 255, 255));
|
||||||
|
_time_print.setCharacterSize(25);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugHelper::toggle()
|
||||||
|
{
|
||||||
|
_toggled = !_toggled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isVisible(const sf::Shape* shape)
|
||||||
|
{
|
||||||
|
return shape->getFillColor().a > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugHelper::update(const sf::Int64 µ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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
game_window.draw(_time_print);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugHelper::onUserTap()
|
||||||
|
{
|
||||||
|
const sf::Uint8 alpha = 255;
|
||||||
|
_tap_pulse.setFillColor(sf::Color(255, 0, 0, alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugHelper::onBeat()
|
||||||
|
{
|
||||||
|
const sf::Uint8 alpha = 255;
|
||||||
|
_bpm_pulse.setFillColor(sf::Color(0, 255, 0, alpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugHelper::onDeath()
|
||||||
|
{
|
||||||
|
const sf::Uint8 alpha = 255;
|
||||||
|
_death_pulse.setFillColor(sf::Color(0, 100, 255, alpha));
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#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>
|
||||||
|
|
||||||
|
class DebugHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebugHelper(bool init = true);
|
||||||
|
|
||||||
|
void toggle();
|
||||||
|
void update(const sf::Int64& microseconds);
|
||||||
|
void drawOn(sf::RenderWindow &game_window) const;
|
||||||
|
void onUserTap();
|
||||||
|
void onBeat();
|
||||||
|
void onDeath();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _toggled;
|
||||||
|
sf::RectangleShape _bpm_pulse;
|
||||||
|
sf::RectangleShape _tap_pulse;
|
||||||
|
sf::RectangleShape _death_pulse;
|
||||||
|
sf::Font _font;
|
||||||
|
sf::Text _time_print;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEBUGHELPER_H
|
9
note.cpp
9
note.cpp
|
@ -7,6 +7,11 @@ Note::Note(microsec offset, microsec death_offset, Note::Arrow type) :
|
||||||
_type(type)
|
_type(type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
microsec Note::offset() const noexcept
|
||||||
|
{
|
||||||
|
return _offset;
|
||||||
|
}
|
||||||
|
|
||||||
microsec Note::deathOffset() const noexcept
|
microsec Note::deathOffset() const noexcept
|
||||||
{
|
{
|
||||||
return _death_offset;
|
return _death_offset;
|
||||||
|
@ -24,10 +29,10 @@ 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;
|
||||||
if (odds < 500000)
|
if (odds < 412162)
|
||||||
{
|
{
|
||||||
ret.score = 50;
|
ret.score = 50;
|
||||||
ret.rating = NoteGrade::Rating::GREAT;
|
ret.rating = NoteGrade::Rating::GREAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
6
note.h
6
note.h
|
@ -25,15 +25,17 @@ public:
|
||||||
UP,
|
UP,
|
||||||
RIGHT,
|
RIGHT,
|
||||||
DOWN,
|
DOWN,
|
||||||
LEFT
|
LEFT,
|
||||||
|
|
||||||
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
Note(microsec offset, microsec death_offset, Note::Arrow type = Note::Arrow::UP);
|
Note(microsec offset, microsec death_offset, Note::Arrow type = Note::Arrow::UP);
|
||||||
|
|
||||||
NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const;
|
NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const;
|
||||||
|
microsec offset() const noexcept;
|
||||||
microsec deathOffset() const noexcept;
|
microsec deathOffset() const noexcept;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
microsec _offset;
|
microsec _offset;
|
||||||
microsec _death_offset;
|
microsec _death_offset;
|
||||||
|
|
Loading…
Reference in New Issue