Implement smoother animation and fullscreen
This commit is contained in:
parent
cbe0fbb673
commit
89a80992cb
|
@ -20,7 +20,7 @@ public:
|
||||||
private:
|
private:
|
||||||
sf::RenderWindow _game_window;
|
sf::RenderWindow _game_window;
|
||||||
std::unique_ptr<Timeline> _timeline;
|
std::unique_ptr<Timeline> _timeline;
|
||||||
std::unique_ptr<Game> _game;
|
std::shared_ptr<Game> _game;
|
||||||
|
|
||||||
void exec();
|
void exec();
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <SFML/System/Clock.hpp>
|
#include <SFML/System/Clock.hpp>
|
||||||
|
|
||||||
|
@ -18,9 +19,8 @@ public:
|
||||||
_offset(offset),
|
_offset(offset),
|
||||||
_intervals(intervals)
|
_intervals(intervals)
|
||||||
{
|
{
|
||||||
microsec&& handling_offset = std::accumulate(intervals.begin(), intervals.end(), 0);
|
_start_handling_offset = _offset - intervals.back();
|
||||||
_start_handling_offset = _offset - handling_offset;
|
_end_handling_offset = _offset + intervals.back();
|
||||||
_end_handling_offset = _offset + handling_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline microsec offset() const noexcept
|
inline microsec offset() const noexcept
|
||||||
|
@ -38,6 +38,8 @@ public:
|
||||||
{
|
{
|
||||||
microsec shift_from_perfect = std::abs(odds - offset());
|
microsec shift_from_perfect = std::abs(odds - offset());
|
||||||
|
|
||||||
|
std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ") << shift_from_perfect << "\n";
|
||||||
|
|
||||||
std::size_t raw_grade;
|
std::size_t raw_grade;
|
||||||
for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade)
|
for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,13 +2,21 @@
|
||||||
#include "classicgame/classicgame.h"
|
#include "classicgame/classicgame.h"
|
||||||
#include <SFML/Graphics/Color.hpp>
|
#include <SFML/Graphics/Color.hpp>
|
||||||
#include <SFML/Window/Event.hpp>
|
#include <SFML/Window/Event.hpp>
|
||||||
|
#include <SFML/Window/ContextSettings.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f);
|
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
||||||
|
|
||||||
Application::Application() :
|
Application::Application() :
|
||||||
_game_window({1280, 720}, "Test"),
|
_game_window({1280, 720}, "Test", sf::Style::Fullscreen ),
|
||||||
_game(std::make_unique<ClassicGame>())
|
_game(std::make_unique<ClassicGame>())
|
||||||
{}
|
{
|
||||||
|
_game_window.setFramerateLimit(60);
|
||||||
|
_game_window.setKeyRepeatEnabled(false);
|
||||||
|
_game_window.setMouseCursorGrabbed(false);
|
||||||
|
_game_window.setVerticalSyncEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::run()
|
void Application::run()
|
||||||
{
|
{
|
||||||
|
@ -21,18 +29,21 @@ void Application::run()
|
||||||
void Application::exec()
|
void Application::exec()
|
||||||
{
|
{
|
||||||
sf::Clock timer;
|
sf::Clock timer;
|
||||||
|
sf::Clock game_timer;
|
||||||
sf::Time time_since_last_update = sf::Time::Zero;
|
sf::Time time_since_last_update = sf::Time::Zero;
|
||||||
|
|
||||||
while (_game_window.isOpen())
|
while (_game_window.isOpen())
|
||||||
{
|
{
|
||||||
input();
|
|
||||||
|
|
||||||
time_since_last_update += timer.restart();
|
time_since_last_update += timer.restart();
|
||||||
|
|
||||||
|
input();
|
||||||
|
|
||||||
bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME;
|
bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME;
|
||||||
if (isOneFramePassed)
|
if (isOneFramePassed)
|
||||||
{
|
{
|
||||||
time_since_last_update -= TIME_PER_FRAME;
|
time_since_last_update -= TIME_PER_FRAME;
|
||||||
|
game_timer.restart();
|
||||||
update();
|
update();
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
|
@ -50,9 +61,15 @@ void Application::input()
|
||||||
_game_window.close();
|
_game_window.close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case sf::Event::KeyPressed:
|
||||||
|
case sf::Event::KeyReleased:
|
||||||
|
if (event.key.code == sf::Keyboard::Escape)
|
||||||
|
_game_window.close();
|
||||||
_game->input(event);
|
_game->input(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,10 @@ ClassicGame::ClassicGame() :
|
||||||
_timeline(std::make_unique<ClassicTimeline>()),
|
_timeline(std::make_unique<ClassicTimeline>()),
|
||||||
_graphics_manager(std::make_unique<ClassicGraphicsManager>())
|
_graphics_manager(std::make_unique<ClassicGraphicsManager>())
|
||||||
{
|
{
|
||||||
|
_slap_buffer.loadFromFile("very-final-slap.wav");
|
||||||
|
_slap.setBuffer(_slap_buffer);
|
||||||
|
_slap.setVolume(50);
|
||||||
|
|
||||||
_keys_to_buttons =
|
_keys_to_buttons =
|
||||||
{
|
{
|
||||||
{sf::Keyboard::Up, Button::UP}, // Load from settings
|
{sf::Keyboard::Up, Button::UP}, // Load from settings
|
||||||
|
@ -86,6 +90,7 @@ void ClassicGame::input(const sf::Event& event)
|
||||||
if (!_timeline->isExpired(note))
|
if (!_timeline->isExpired(note))
|
||||||
{
|
{
|
||||||
(*note)->input(ClassicInputType(timestamp, new_action));
|
(*note)->input(ClassicInputType(timestamp, new_action));
|
||||||
|
_slap.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "classicactions.h"
|
#include "classicactions.h"
|
||||||
#include "spritecontainer.h"
|
#include "spritecontainer.h"
|
||||||
|
#include <SFML/Audio/SoundBuffer.hpp>
|
||||||
|
#include <SFML/Audio/Sound.hpp>
|
||||||
|
|
||||||
class ClassicTimeline;
|
class ClassicTimeline;
|
||||||
class ClassicSprite;
|
class ClassicSprite;
|
||||||
|
@ -33,6 +35,8 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<ClassicTimeline> _timeline;
|
std::unique_ptr<ClassicTimeline> _timeline;
|
||||||
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||||
|
sf::SoundBuffer _slap_buffer;
|
||||||
|
sf::Sound _slap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLASSICGAME_H
|
#endif // CLASSICGAME_H
|
||||||
|
|
|
@ -10,7 +10,8 @@ ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfec
|
||||||
_evaluator(intervals, _perfect_offset),
|
_evaluator(intervals, _perfect_offset),
|
||||||
_action(action),
|
_action(action),
|
||||||
_state(State::NONE),
|
_state(State::NONE),
|
||||||
_appearance_time(0)
|
_appearance_time(0),
|
||||||
|
_last_offset(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool ClassicNote::isActive(const microsec& music_offset) const
|
bool ClassicNote::isActive(const microsec& music_offset) const
|
||||||
|
@ -18,9 +19,9 @@ bool ClassicNote::isActive(const microsec& music_offset) const
|
||||||
return _evaluator.isActive(music_offset);
|
return _evaluator.isActive(music_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getPt( int n1 , int n2 , float perc )
|
static int getPt( float n1 , float n2 , float perc )
|
||||||
{
|
{
|
||||||
int diff = n2 - n1;
|
float diff = n2 - n1;
|
||||||
|
|
||||||
return n1 + ( diff * perc );
|
return n1 + ( diff * perc );
|
||||||
}
|
}
|
||||||
|
@ -36,16 +37,29 @@ void ClassicNote::update(const microsec& music_offset)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::FLYING:
|
case State::FLYING:
|
||||||
|
{
|
||||||
|
float i;
|
||||||
|
if (music_offset != _last_offset)
|
||||||
{
|
{
|
||||||
auto update_time = music_offset - _appearance_time; // This all will be inside ::update
|
auto update_time = music_offset - _appearance_time; // This all will be inside ::update
|
||||||
auto i = update_time / _trail_path_percent / 100; // of an animation object
|
i = update_time / _trail_path_percent * 0.01; // of an animation object
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto update_time = music_offset + 10000 - _appearance_time;
|
||||||
|
i = update_time / _trail_path_percent * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
int xa = getPt( 720./2. , 1280./2. , i );
|
_last_offset = music_offset;
|
||||||
int ya = getPt( 0 , 720./2. , i );
|
|
||||||
int xb = getPt( 1280./2. , _coordinates.x , i );
|
float xa = getPt( _coordinates.x + 20. , _coordinates.x + 90. , i );
|
||||||
int yb = getPt( 720./2. , _coordinates.y , i );
|
float ya = getPt( _coordinates.y - 600. , _coordinates.y - 150. , i );
|
||||||
|
float xb = getPt( _coordinates.x + 90. , _coordinates.x , i );
|
||||||
|
float yb = getPt( _coordinates.y - 150. , _coordinates.y , i );
|
||||||
|
|
||||||
_sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i ));
|
_sprite->update(getPt( xa , xb , i ), getPt( ya , yb , i ));
|
||||||
|
if (i >= 1)
|
||||||
|
_sprite->trailFade();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +106,7 @@ void ClassicNote::setState(State next_state)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::FLYING:
|
case State::FLYING:
|
||||||
_sprite->setCoordinates(_coordinates.x, _coordinates.y, 720/2, 50);
|
_sprite->setCoordinates(_coordinates.x, _coordinates.y, _coordinates.x + 20, _coordinates.y - 600);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::NONE:
|
case State::NONE:
|
||||||
|
|
|
@ -66,5 +66,6 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<ClassicSprite> _sprite;
|
std::shared_ptr<ClassicSprite> _sprite;
|
||||||
microsec _appearance_time;
|
microsec _appearance_time;
|
||||||
|
microsec _last_offset;
|
||||||
float _trail_path_percent; //100% for sprite falling trajectory
|
float _trail_path_percent; //100% for sprite falling trajectory
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,7 @@ void ClassicSprite::reset()
|
||||||
|
|
||||||
_shape = _prototype;
|
_shape = _prototype;
|
||||||
_trail = _prototype;
|
_trail = _prototype;
|
||||||
|
_trail_fade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept
|
void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_y) noexcept
|
||||||
|
@ -38,6 +39,19 @@ void ClassicSprite::setCoordinates(float x, float y, float trail_x, float trail_
|
||||||
void ClassicSprite::update(float trail_x, float trail_y) noexcept
|
void ClassicSprite::update(float trail_x, float trail_y) noexcept
|
||||||
{
|
{
|
||||||
_trail.setPosition(trail_x, trail_y);
|
_trail.setPosition(trail_x, trail_y);
|
||||||
|
|
||||||
|
if (_trail_fade)
|
||||||
|
{
|
||||||
|
auto fill_color = _trail.getFillColor();
|
||||||
|
|
||||||
|
if (fill_color.a == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto new_alpha = fill_color.a - 35;
|
||||||
|
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
|
||||||
|
|
||||||
|
_trail.setFillColor(fill_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicSprite::update() noexcept
|
void ClassicSprite::update() noexcept
|
||||||
|
@ -76,6 +90,11 @@ void ClassicSprite::fade()
|
||||||
_shape.setFillColor(fill_color);
|
_shape.setFillColor(fill_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassicSprite::trailFade()
|
||||||
|
{
|
||||||
|
_trail_fade = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClassicSprite::isDead() const
|
bool ClassicSprite::isDead() const
|
||||||
{
|
{
|
||||||
return _grade_text.getFillColor().a == 0
|
return _grade_text.getFillColor().a == 0
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
|
|
||||||
void pulse();
|
void pulse();
|
||||||
void fade();
|
void fade();
|
||||||
|
void trailFade();
|
||||||
bool isDead() const;
|
bool isDead() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -26,4 +27,6 @@ private:
|
||||||
sf::RectangleShape _trail;
|
sf::RectangleShape _trail;
|
||||||
sf::Text _grade_text;
|
sf::Text _grade_text;
|
||||||
sf::Font _font;
|
sf::Font _font;
|
||||||
|
|
||||||
|
bool _trail_fade = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,27 +23,26 @@ ClassicTimeline::ClassicTimeline()
|
||||||
microsec starting_beat_offset = 352162;
|
microsec starting_beat_offset = 352162;
|
||||||
int amount_of_beats = 209;
|
int amount_of_beats = 209;
|
||||||
microsec interval = 1412162;
|
microsec interval = 1412162;
|
||||||
microsec note_input_offset = 412162;
|
microsec tempo_interval = interval / 4;
|
||||||
|
microsec note_input_offset = 412162 / 3;
|
||||||
microsec bpm_iterator = starting_beat_offset;
|
microsec bpm_iterator = starting_beat_offset;
|
||||||
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
|
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
|
||||||
_visibility_offset = note_input_offset * 8;
|
_visibility_offset = note_input_offset * 12;
|
||||||
|
|
||||||
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_DOWN, {90, 90}));
|
_input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset};
|
||||||
bpm_iterator += interval;
|
|
||||||
|
|
||||||
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {190, 90}));
|
bpm_iterator += tempo_interval;
|
||||||
bpm_iterator += interval;
|
|
||||||
|
|
||||||
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {290, 90}));
|
|
||||||
bpm_iterator += interval;
|
|
||||||
|
|
||||||
float x = 90.;
|
float x = 90.;
|
||||||
|
|
||||||
while (bpm_iterator < bpm_end)
|
while (bpm_iterator < bpm_end)
|
||||||
{
|
{
|
||||||
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP, {x, 390.}));
|
_timeline.emplace_back(new ClassicNote(_input_intervals, bpm_iterator, Action::PRESS_UP, {x, 390.}));
|
||||||
bpm_iterator += interval;
|
bpm_iterator += tempo_interval;
|
||||||
x += 70;
|
x += 70;
|
||||||
|
|
||||||
|
if (x >= 1200)
|
||||||
|
x = 90.;
|
||||||
}
|
}
|
||||||
|
|
||||||
expire(_first_visible_note);
|
expire(_first_visible_note);
|
||||||
|
|
|
@ -28,16 +28,12 @@ public:
|
||||||
|
|
||||||
Iterator getActiveNote() noexcept;
|
Iterator getActiveNote() noexcept;
|
||||||
|
|
||||||
bool isExpired(const Iterator& iterator) const;
|
inline bool isExpired(const Iterator& iterator) const;
|
||||||
void expire(Iterator& iterator);
|
inline void expire(Iterator& iterator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<microsec> _input_intervals;
|
||||||
std::vector<ClassicNote*> _timeline;
|
std::vector<ClassicNote*> _timeline;
|
||||||
Iterator _top_note;
|
|
||||||
Iterator _active_note;
|
|
||||||
Iterator _last_visible_note;
|
|
||||||
Iterator _first_visible_note;
|
|
||||||
|
|
||||||
microsec _visibility_offset;
|
microsec _visibility_offset;
|
||||||
|
|
||||||
sf::Music _music;
|
sf::Music _music;
|
||||||
|
@ -46,7 +42,7 @@ private:
|
||||||
void checkCurrentActiveNote(const microsec& music_offset);
|
void checkCurrentActiveNote(const microsec& music_offset);
|
||||||
void checkForNextActiveNote(const microsec& music_offset);
|
void checkForNextActiveNote(const microsec& music_offset);
|
||||||
bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const;
|
bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const;
|
||||||
bool nothingToDraw() const noexcept;
|
inline bool nothingToDraw() const noexcept;
|
||||||
|
|
||||||
/* Difference between top and active note is that
|
/* Difference between top and active note is that
|
||||||
* top note is the note handling input right now
|
* top note is the note handling input right now
|
||||||
|
@ -61,4 +57,9 @@ private:
|
||||||
* An active note is always top note but a top note
|
* An active note is always top note but a top note
|
||||||
* is not always active note.
|
* is not always active note.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
Iterator _top_note;
|
||||||
|
Iterator _active_note;
|
||||||
|
Iterator _last_visible_note;
|
||||||
|
Iterator _first_visible_note;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue