Add debug helper and clean init code

This commit is contained in:
NaiJi ✨ 2021-04-05 17:17:57 +03:00
parent bf8e6be88f
commit e37fb7b539
6 changed files with 292 additions and 97 deletions

View File

@ -1,81 +1,60 @@
#include "application.h"
#include <SFML/Graphics/Color.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f);
Application::Application() :
game_window({1280, 720}, "Test")
_game_window({1280, 720}, "Test"),
_debug(true)
{
float x = game_window.getSize().x;
float y = game_window.getSize().y;
pulse_mask.setSize({x, y});
pulse_mask.setOrigin(0.f, 0.f);
pulse_mask.setFillColor(sf::Color(255, 0, 0, 0));
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);
_font.loadFromFile("VeraMono.ttf");
_grade.setFont(_font);
_grade.setPosition(160, 160);
_grade.setFillColor(sf::Color(255, 255, 255, 0));
_grade.setCharacterSize(35);
}
void Application::run()
{
game_window.display();
sf::Int64 iter = 9000 + (1412162 * 25);
while (iter > 9000)
// 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;
while (iter > 0)
{
Note note(iter, iter + 412162);
timeline.push(note);
_timeline.push(note);
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::Time time_since_last_update = sf::Time::Zero;
music.openFromFile("/home/naiji/METEOR.flac");
music.play();
while (game_window.isOpen())
{
sf::Event event;
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())
while (_game_window.isOpen())
{
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;
}
}
}
input();
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;
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()
{
if (!timeline.empty() && timeline.top().deathOffset() <= music.getPlayingOffset().asMicroseconds())
const auto microseconds = _music.getPlayingOffset().asMicroseconds();
if (!_timeline.empty() && _timeline.top().offset() <= microseconds)
{
timeline.pop();
pulse_mask_green.setFillColor(sf::Color(0, 255, 0, 255));
_debug.onBeat();
}
text.setString(std::to_string(music.getPlayingOffset().asSeconds()));
if (pulse_mask.getFillColor().a > 0)
if (!_timeline.empty() && _timeline.top().deathOffset() <= microseconds)
{
const auto alpha = pulse_mask.getFillColor().a - 25;
pulse_mask.setFillColor(sf::Color(255, 0, 0, alpha < 0 ? 0 : alpha));
_timeline.pop();
_debug.onDeath();
}
if (pulse_mask_green.getFillColor().a > 0)
{
const auto alpha = pulse_mask_green.getFillColor().a - 25;
pulse_mask_green.setFillColor(sf::Color(0, 255, 0, alpha < 0 ? 0 : alpha));
}
_debug.update(microseconds);
if (grade.getFillColor().a > 0)
if (_grade.getFillColor().a > 0)
{
const auto alpha = grade.getFillColor().a - 20;
grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha));
const auto alpha = _grade.getFillColor().a - 20;
_grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha));
}
}
void Application::draw()
{
game_window.clear();
game_window.draw(pulse_mask);
game_window.draw(pulse_mask_green);
game_window.draw(text);
game_window.draw(grade);
game_window.display();
_game_window.clear();
_debug.drawOn(_game_window);
_game_window.draw(_grade);
_game_window.display();
}

View File

@ -1,15 +1,13 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Audio/Music.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <stack>
#include "debughelper.h"
#include "note.h"
class Application
@ -17,22 +15,24 @@ class Application
public:
Application();
void run();
void input();
void update();
void draw();
private:
sf::RenderWindow game_window;
sf::Music music;
sf::RectangleShape pulse_mask;
sf::RectangleShape pulse_mask_green;
sf::RenderWindow _game_window;
sf::Music _music;
std::stack<Note> timeline;
sf::Int64 time_since_last_tick;
sf::Int64 last_stamp;
sf::Font font;
sf::Font font2;
sf::Text text;
sf::Text grade;
std::stack<Note> _timeline;
sf::Int64 _time_since_last_tick;
sf::Int64 _last_stamp;
sf::Font _font;
sf::Text _grade;
DebugHelper _debug;
void startGameLoop();
void onKeyPressed(const sf::Keyboard::Key& key);
};
#endif // APPLICATION_H

84
debughelper.cpp Normal file
View File

@ -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 &microseconds)
{
_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));
}

30
debughelper.h Normal file
View File

@ -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

View File

@ -7,6 +7,11 @@ Note::Note(microsec offset, microsec death_offset, Note::Arrow type) :
_type(type)
{}
microsec Note::offset() const noexcept
{
return _offset;
}
microsec Note::deathOffset() const noexcept
{
return _death_offset;
@ -24,7 +29,7 @@ NoteGrade Note::onTap(Arrow arrow_type, microsec tap_time_stamp) const
NoteGrade Note::calculatePrecision(microsec odds) const
{
NoteGrade ret;
if (odds < 500000)
if (odds < 412162)
{
ret.score = 50;
ret.rating = NoteGrade::Rating::GREAT;

6
note.h
View File

@ -25,15 +25,17 @@ public:
UP,
RIGHT,
DOWN,
LEFT
LEFT,
NONE
};
Note(microsec offset, microsec death_offset, Note::Arrow type = Note::Arrow::UP);
NoteGrade onTap(Arrow arrow_type, microsec tap_time_stamp) const;
microsec offset() const noexcept;
microsec deathOffset() const noexcept;
private:
microsec _offset;
microsec _death_offset;