forked from NaiJi/project-kyoku
Implement more precise active note detection
This commit is contained in:
parent
192e371d2f
commit
ad1b31c95c
|
@ -4,7 +4,6 @@
|
|||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/Window/Keyboard.hpp>
|
||||
|
||||
#include "debughelper.h"
|
||||
#include "timeline.h"
|
||||
#include "note.h"
|
||||
#include "game.h"
|
||||
|
@ -13,7 +12,6 @@ class Application
|
|||
{
|
||||
public:
|
||||
Application();
|
||||
~Application();
|
||||
void run();
|
||||
void input();
|
||||
void update();
|
||||
|
@ -21,13 +19,7 @@ public:
|
|||
|
||||
private:
|
||||
sf::RenderWindow _game_window;
|
||||
|
||||
sf::Font _font;
|
||||
sf::Text _grade;
|
||||
|
||||
std::unique_ptr<Timeline> _timeline;
|
||||
DebugHelper _debug;
|
||||
|
||||
std::unique_ptr<Game> _game;
|
||||
|
||||
void exec();
|
||||
|
|
|
@ -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
|
|
@ -7,18 +7,7 @@ const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f);
|
|||
|
||||
Application::Application() :
|
||||
_game_window({1280, 720}, "Test"),
|
||||
_debug(true),
|
||||
_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()
|
||||
|
|
|
@ -8,7 +8,6 @@ ClassicGame::ClassicGame() :
|
|||
_timeline(std::make_unique<ClassicTimeline>()),
|
||||
_view_manager(std::make_unique<ClassicViewManager>())
|
||||
{
|
||||
_font.loadFromFile("VeraMono.ttf");
|
||||
_keys_to_buttons =
|
||||
{
|
||||
{sf::Keyboard::Up, Button::UP}, // Load from settings
|
||||
|
@ -83,25 +82,9 @@ void ClassicGame::input(const sf::Event& event)
|
|||
|
||||
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));
|
||||
|
||||
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);
|
||||
(*note)->input(ClassicInputType(timestamp, new_action));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,24 +102,9 @@ void ClassicGame::update()
|
|||
{
|
||||
_timeline->update();
|
||||
_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
|
||||
{
|
||||
_timeline->drawVisibleNotes(window);
|
||||
|
||||
for (auto& grade : _grades)
|
||||
{
|
||||
window.draw(grade);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
#include "game.h"
|
||||
#include "classicactions.h"
|
||||
|
||||
|
@ -32,9 +31,6 @@ private:
|
|||
|
||||
std::unique_ptr<ClassicTimeline> _timeline;
|
||||
std::unique_ptr<ClassicViewManager> _view_manager;
|
||||
|
||||
sf::Font _font;
|
||||
std::list<sf::Text> _grades;
|
||||
};
|
||||
|
||||
#endif // CLASSICGAME_H
|
||||
|
|
|
@ -34,7 +34,11 @@ void ClassicNote::update(const microsec& music_offset)
|
|||
int xb = getPt( 1280./2. , _coordinates.x , 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
|
||||
|
@ -52,7 +56,8 @@ auto ClassicNote::input(ClassicInputType&& input_data) -> Grade
|
|||
}
|
||||
|
||||
std::cout << "User input: " << static_cast<int>(grade) << "\n";
|
||||
_state = State::DEAD;
|
||||
_state = State::DYING;
|
||||
_sprite->showGrade();
|
||||
return grade;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,53 @@
|
|||
#include "classicsprite.h"
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
|
||||
ClassicSprite::ClassicSprite(const sf::RectangleShape& shape) :
|
||||
ClassicSprite::ClassicSprite(const sf::RectangleShape& shape, const sf::Font& font) :
|
||||
_shape(shape),
|
||||
_trail(shape)
|
||||
{}
|
||||
_trail(shape),
|
||||
_font(font)
|
||||
{
|
||||
_grade_text.setFont(_font);
|
||||
}
|
||||
|
||||
void ClassicSprite::draw(sf::RenderTarget& target, sf::RenderStates states) const
|
||||
{
|
||||
target.draw(_shape, states);
|
||||
target.draw(_trail, states);
|
||||
target.draw(_grade_text, states);
|
||||
}
|
||||
|
||||
void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept
|
||||
{
|
||||
_shape.setPosition(x, 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);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -2,17 +2,23 @@
|
|||
|
||||
#include "sprite.h"
|
||||
#include "SFML/Graphics/RectangleShape.hpp"
|
||||
#include "SFML/Graphics/Text.hpp"
|
||||
|
||||
class ClassicSprite : public Sprite, public sf::Drawable
|
||||
{
|
||||
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;
|
||||
|
||||
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:
|
||||
sf::RectangleShape _shape;
|
||||
sf::RectangleShape _trail;
|
||||
sf::Text _grade_text;
|
||||
sf::Font _font;
|
||||
};
|
||||
|
|
|
@ -79,7 +79,8 @@ void ClassicTimeline::update()
|
|||
|
||||
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);
|
||||
++_top_note;
|
||||
|
@ -124,7 +125,9 @@ void ClassicTimeline::discardExpiredNotes(const std::unique_ptr<ClassicViewManag
|
|||
Iterator past_note = _top_note - 1;
|
||||
std::shared_ptr<ClassicSprite> sprite = (*past_note)->sprite();
|
||||
while (sprite)
|
||||
{ // CAREFULLY REWRITE
|
||||
{
|
||||
auto state = (*past_note)->state();
|
||||
if (state == ClassicNote::State::DEAD || state == ClassicNote::State::FLYING)
|
||||
view_manager->resetNoteSprite(*past_note);
|
||||
if (past_note == _timeline.begin())
|
||||
return;
|
||||
|
@ -154,12 +157,9 @@ void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr<ClassicViewManager
|
|||
}
|
||||
|
||||
if (note->state() == ClassicNote::State::DEAD)
|
||||
{
|
||||
view_manager->resetNoteSprite(note);
|
||||
}
|
||||
else
|
||||
note->update(music_offset);
|
||||
|
||||
note->update(music_offset);
|
||||
++note_iterator;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ ClassicViewManager::ClassicViewManager()
|
|||
{
|
||||
reallocatePoll(kind_of_action);
|
||||
}
|
||||
|
||||
_font.loadFromFile("VeraMono.ttf");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return std::make_shared<ClassicSprite>(sprite);
|
||||
return std::make_shared<ClassicSprite>(sprite, _font);
|
||||
}
|
||||
|
||||
void ClassicViewManager::initNoteSprite(ClassicNote* note)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <memory>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
|
||||
class ClassicSprite;
|
||||
class ClassicNote;
|
||||
|
@ -25,6 +26,7 @@ private:
|
|||
|
||||
using SpritePoll = std::stack<std::shared_ptr<ClassicSprite>>;
|
||||
std::map<Action, SpritePoll> _sprite_dispatcher;
|
||||
sf::Font _font;
|
||||
};
|
||||
|
||||
#endif // CLASSICDIVAVIEWMANAGER_H
|
||||
|
|
|
@ -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 µseconds)
|
||||
{
|
||||
_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);
|
||||
}
|
Loading…
Reference in New Issue