forked from NaiJi/project-kyoku
Encapsulate music and timer interpolation, test with pause
This commit is contained in:
parent
c2677bdd2b
commit
cf1119c742
|
@ -2,7 +2,7 @@
|
||||||
#define INPUTTYPE_H
|
#define INPUTTYPE_H
|
||||||
|
|
||||||
#include <SFML/Window/Event.hpp>
|
#include <SFML/Window/Event.hpp>
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
|
|
||||||
struct PlayerInput
|
struct PlayerInput
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef PRECISIONEVALUATOR_H
|
#ifndef PRECISIONEVALUATOR_H
|
||||||
#define PRECISIONEVALUATOR_H
|
#define PRECISIONEVALUATOR_H
|
||||||
|
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef TIMELINE_H
|
#ifndef TIMELINE_H
|
||||||
#define TIMELINE_H
|
#define TIMELINE_H
|
||||||
|
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -13,10 +13,9 @@ class Timeline
|
||||||
public:
|
public:
|
||||||
virtual ~Timeline() = default;
|
virtual ~Timeline() = default;
|
||||||
|
|
||||||
virtual void update() = 0;
|
virtual void update(const microsec& offset) = 0;
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual microsec currentMusicOffset() const = 0;
|
|
||||||
virtual void drawVisibleNotes() const = 0;
|
virtual void drawVisibleNotes() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tools/mathutils.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Music
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Music() = default;
|
||||||
|
|
||||||
|
virtual bool openFromFile(const std::string& filepath) = 0;
|
||||||
|
|
||||||
|
virtual void play() = 0;
|
||||||
|
virtual void pause() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
virtual void setVolume(int volume) = 0;
|
||||||
|
|
||||||
|
virtual void setOffset(const microsec& offset) = 0;
|
||||||
|
virtual microsec fetchOffset() = 0;
|
||||||
|
};
|
|
@ -7,13 +7,15 @@
|
||||||
#include "gui/mainmenu.h"
|
#include "gui/mainmenu.h"
|
||||||
#include "gui/gamestate.h"
|
#include "gui/gamestate.h"
|
||||||
|
|
||||||
|
#include "tools/musicsfml.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
||||||
|
|
||||||
Application::Application() :
|
Application::Application() :
|
||||||
_game_window({1280, 720}, "Test", sf::Style::Default),
|
_game_window({1280, 720}, "Test", sf::Style::Default),
|
||||||
_game(std::make_unique<ClassicGame>(std::make_unique<ClassicGraphicsManager>(_game_window)))
|
_game(std::make_unique<ClassicGame>(std::make_unique<ClassicGraphicsManager>(_game_window), std::make_unique<MusicSFML>()))
|
||||||
{
|
{
|
||||||
_game_window.setFramerateLimit(60);
|
_game_window.setFramerateLimit(60);
|
||||||
_game_window.setKeyRepeatEnabled(false);
|
_game_window.setKeyRepeatEnabled(false);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class ClassicSprite;
|
class ClassicSprite;
|
||||||
|
|
|
@ -2,11 +2,14 @@
|
||||||
#include "classictimeline.h"
|
#include "classictimeline.h"
|
||||||
#include "classicnote.h"
|
#include "classicnote.h"
|
||||||
#include "classicmapcreator.h"
|
#include "classicmapcreator.h"
|
||||||
|
#include "tools/music.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
ClassicGame::ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager) :
|
ClassicGame::ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager, std::unique_ptr<Music>&& music) :
|
||||||
_timeline(std::make_unique<ClassicTimeline>()),
|
_timeline(std::make_unique<ClassicTimeline>()),
|
||||||
_graphics_manager(std::move(manager))
|
_graphics_manager(std::move(manager)),
|
||||||
|
_music(std::move(music)),
|
||||||
|
_is_paused(false)
|
||||||
{
|
{
|
||||||
_slap_buffer.loadFromFile("very-final-slap.wav");
|
_slap_buffer.loadFromFile("very-final-slap.wav");
|
||||||
_slap.setBuffer(_slap_buffer);
|
_slap.setBuffer(_slap_buffer);
|
||||||
|
@ -58,12 +61,15 @@ void ClassicGame::run()
|
||||||
{
|
{
|
||||||
ClassicMapCreator creator(_graphics_manager);
|
ClassicMapCreator creator(_graphics_manager);
|
||||||
auto beatmap = creator.createBeatmap("aa");
|
auto beatmap = creator.createBeatmap("aa");
|
||||||
|
_music->openFromFile("METEOR.flac");
|
||||||
|
_music->setVolume(10);
|
||||||
|
_music->play();
|
||||||
_timeline->run(std::move(beatmap.notes), beatmap.visibility_offset);
|
_timeline->run(std::move(beatmap.notes), beatmap.visibility_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGame::input(PlayerInput&& inputdata)
|
void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
{
|
{
|
||||||
inputdata.timestamp = _timeline->currentMusicOffset();
|
inputdata.timestamp = _music->fetchOffset();
|
||||||
|
|
||||||
switch (inputdata.event.type)
|
switch (inputdata.event.type)
|
||||||
{
|
{
|
||||||
|
@ -73,6 +79,22 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
|
|
||||||
case sf::Event::KeyPressed:
|
case sf::Event::KeyPressed:
|
||||||
{
|
{
|
||||||
|
if (inputdata.event.key.code == sf::Keyboard::Space)
|
||||||
|
{
|
||||||
|
if (!_is_paused)
|
||||||
|
{
|
||||||
|
_is_paused = true;
|
||||||
|
_music->pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_is_paused = false;
|
||||||
|
_music->play();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto note_it = _timeline->getActiveNote();
|
auto note_it = _timeline->getActiveNote();
|
||||||
|
|
||||||
if (!_timeline->isExpired(note_it))
|
if (!_timeline->isExpired(note_it))
|
||||||
|
@ -111,7 +133,7 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
|
|
||||||
void ClassicGame::update()
|
void ClassicGame::update()
|
||||||
{
|
{
|
||||||
_timeline->update();
|
_timeline->update(_music->fetchOffset());
|
||||||
_timeline->fetchVisibleNotes();
|
_timeline->fetchVisibleNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <SFML/Audio/SoundBuffer.hpp>
|
#include <SFML/Audio/SoundBuffer.hpp>
|
||||||
#include <SFML/Audio/Sound.hpp>
|
#include <SFML/Audio/Sound.hpp>
|
||||||
|
|
||||||
|
class Music;
|
||||||
class ClassicNote;
|
class ClassicNote;
|
||||||
class ClassicTimeline;
|
class ClassicTimeline;
|
||||||
class ClassicGraphicsManager;
|
class ClassicGraphicsManager;
|
||||||
|
@ -14,7 +15,7 @@ class ClassicGraphicsManager;
|
||||||
class ClassicGame final : public Game
|
class ClassicGame final : public Game
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager);
|
explicit ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager, std::unique_ptr<Music>&& music);
|
||||||
virtual ~ClassicGame() override;
|
virtual ~ClassicGame() override;
|
||||||
|
|
||||||
virtual void run() override;
|
virtual void run() override;
|
||||||
|
@ -34,6 +35,10 @@ private:
|
||||||
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||||
sf::SoundBuffer _slap_buffer;
|
sf::SoundBuffer _slap_buffer;
|
||||||
sf::Sound _slap;
|
sf::Sound _slap;
|
||||||
|
|
||||||
|
std::unique_ptr<Music> _music;
|
||||||
|
|
||||||
|
bool _is_paused;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLASSICGAME_H
|
#endif // CLASSICGAME_H
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
#include "classicgraphicsmanager.h"
|
#include "classicgraphicsmanager.h"
|
||||||
|
|
||||||
struct Beatmap
|
struct Beatmap
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "game/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
#include "game/sprite.h"
|
#include "game/sprite.h"
|
||||||
#include "SFML/Graphics/RectangleShape.hpp"
|
#include "SFML/Graphics/RectangleShape.hpp"
|
||||||
#include "SFML/Graphics/Text.hpp"
|
#include "SFML/Graphics/Text.hpp"
|
||||||
|
|
|
@ -3,19 +3,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
ClassicTimeline::ClassicTimeline() :
|
ClassicTimeline::ClassicTimeline() :
|
||||||
_sfml_music_offset(0),
|
_current_offset(0)
|
||||||
_previous_frame_offset(0),
|
{}
|
||||||
_absolute_offset(0)
|
|
||||||
{
|
|
||||||
// BPM of METEOR is 170.
|
|
||||||
// Length is 1:14
|
|
||||||
// I calculated that the time between beats is about 1412162 microseconds
|
|
||||||
|
|
||||||
std::string song_filename = "METEOR.flac";
|
|
||||||
|
|
||||||
_music.openFromFile(song_filename);
|
|
||||||
_music.setVolume(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassicTimeline::run(std::vector<ClassicNote*>&& notes, const microsec& visibility)
|
void ClassicTimeline::run(std::vector<ClassicNote*>&& notes, const microsec& visibility)
|
||||||
{
|
{
|
||||||
|
@ -28,9 +17,6 @@ void ClassicTimeline::run(std::vector<ClassicNote*>&& notes, const microsec& vis
|
||||||
expire(_active_note);
|
expire(_active_note);
|
||||||
|
|
||||||
fetchVisibleNotes();
|
fetchVisibleNotes();
|
||||||
_music.play();
|
|
||||||
|
|
||||||
_previous_frame_offset = _offset_interpolator.restart().asMicroseconds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassicTimeline::~ClassicTimeline()
|
ClassicTimeline::~ClassicTimeline()
|
||||||
|
@ -46,22 +32,13 @@ void ClassicTimeline::clear()
|
||||||
_timeline.clear();
|
_timeline.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicTimeline::update()
|
void ClassicTimeline::update(const microsec& offset)
|
||||||
{
|
{
|
||||||
const auto interpolator_timestamp = _offset_interpolator.getElapsedTime().asMicroseconds();
|
_current_offset = offset;
|
||||||
const auto sfml_new_offset = currentMusicOffset();
|
|
||||||
|
|
||||||
_absolute_offset += (interpolator_timestamp - _previous_frame_offset);
|
|
||||||
_previous_frame_offset = interpolator_timestamp;
|
|
||||||
if (sfml_new_offset != _sfml_music_offset)
|
|
||||||
{
|
|
||||||
_absolute_offset = ((_absolute_offset + sfml_new_offset) / 2);
|
|
||||||
_sfml_music_offset = sfml_new_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkCurrentActiveNote();
|
checkCurrentActiveNote();
|
||||||
checkForNextActiveNote();
|
checkForNextActiveNote();
|
||||||
updateVisibleSprites(_absolute_offset);
|
updateVisibleSprites(_current_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicTimeline::checkCurrentActiveNote()
|
void ClassicTimeline::checkCurrentActiveNote()
|
||||||
|
@ -115,11 +92,6 @@ void ClassicTimeline::expire(Iterator& iterator)
|
||||||
iterator = _timeline.end();
|
iterator = _timeline.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
microsec ClassicTimeline::currentMusicOffset() const
|
|
||||||
{
|
|
||||||
return _music.getPlayingOffset().asMicroseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const
|
bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const
|
||||||
{
|
{
|
||||||
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
|
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
|
||||||
|
@ -127,7 +99,7 @@ bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& m
|
||||||
|
|
||||||
void ClassicTimeline::fetchVisibleNotes()
|
void ClassicTimeline::fetchVisibleNotes()
|
||||||
{
|
{
|
||||||
findLastVisibleNote(_absolute_offset);
|
findLastVisibleNote(_current_offset);
|
||||||
findFirstVisibleNote();
|
findFirstVisibleNote();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
#include "game/timeline.h"
|
#include "game/timeline.h"
|
||||||
|
|
||||||
#include <SFML/Audio/Music.hpp>
|
|
||||||
#include <SFML/System/Clock.hpp>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -14,10 +12,9 @@ class ClassicTimeline : public Timeline
|
||||||
public:
|
public:
|
||||||
explicit ClassicTimeline();
|
explicit ClassicTimeline();
|
||||||
virtual ~ClassicTimeline();
|
virtual ~ClassicTimeline();
|
||||||
virtual void update() override;
|
virtual void update(const microsec& offset) override;
|
||||||
virtual void clear() override;
|
virtual void clear() override;
|
||||||
|
|
||||||
virtual microsec currentMusicOffset() const override;
|
|
||||||
virtual void drawVisibleNotes() const override;
|
virtual void drawVisibleNotes() const override;
|
||||||
|
|
||||||
void run(std::vector<ClassicNote*>&& notes, const microsec& visibility);
|
void run(std::vector<ClassicNote*>&& notes, const microsec& visibility);
|
||||||
|
@ -37,12 +34,7 @@ private:
|
||||||
std::vector<microsec> _input_intervals;
|
std::vector<microsec> _input_intervals;
|
||||||
std::vector<ClassicNote*> _timeline;
|
std::vector<ClassicNote*> _timeline;
|
||||||
microsec _visibility_offset;
|
microsec _visibility_offset;
|
||||||
|
microsec _current_offset;
|
||||||
sf::Music _music;
|
|
||||||
sf::Clock _offset_interpolator;
|
|
||||||
microsec _sfml_music_offset;
|
|
||||||
microsec _previous_frame_offset;
|
|
||||||
microsec _absolute_offset;
|
|
||||||
|
|
||||||
void updateVisibleSprites(const microsec& music_offset);
|
void updateVisibleSprites(const microsec& music_offset);
|
||||||
void checkCurrentActiveNote();
|
void checkCurrentActiveNote();
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#include "musicsfml.h"
|
||||||
|
|
||||||
|
MusicSFML::MusicSFML() :
|
||||||
|
_sfml_music_offset(0),
|
||||||
|
_previous_frame_offset(0),
|
||||||
|
_absolute_offset(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool MusicSFML::openFromFile(const std::string& filepath)
|
||||||
|
{
|
||||||
|
return _music.openFromFile(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSFML::play()
|
||||||
|
{
|
||||||
|
_music.play();
|
||||||
|
_sfml_music_offset = _offset_interpolator.restart().asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSFML::pause()
|
||||||
|
{
|
||||||
|
_music.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSFML::stop()
|
||||||
|
{
|
||||||
|
_music.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSFML::setVolume(int volume)
|
||||||
|
{
|
||||||
|
_music.setVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicSFML::setOffset(const microsec& offset)
|
||||||
|
{
|
||||||
|
_previous_frame_offset += (offset - _absolute_offset);
|
||||||
|
_music.setPlayingOffset(sf::microseconds(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
microsec MusicSFML::fetchOffset()
|
||||||
|
{
|
||||||
|
if (_music.getStatus() != sf::Music::Status::Playing)
|
||||||
|
return _absolute_offset;
|
||||||
|
|
||||||
|
const auto interpolator_timestamp = _offset_interpolator.getElapsedTime().asMicroseconds();
|
||||||
|
const auto sfml_new_offset = _music.getPlayingOffset().asMicroseconds();
|
||||||
|
|
||||||
|
_absolute_offset += (interpolator_timestamp - _previous_frame_offset);
|
||||||
|
_previous_frame_offset = interpolator_timestamp;
|
||||||
|
if (sfml_new_offset != _sfml_music_offset)
|
||||||
|
{
|
||||||
|
_absolute_offset = ((_absolute_offset + sfml_new_offset) / 2);
|
||||||
|
_sfml_music_offset = sfml_new_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _absolute_offset;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tools/music.h"
|
||||||
|
|
||||||
|
#include <SFML/Audio/Music.hpp>
|
||||||
|
|
||||||
|
class MusicSFML : public Music
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MusicSFML();
|
||||||
|
|
||||||
|
virtual bool openFromFile(const std::string& filepath) override;
|
||||||
|
|
||||||
|
virtual void play() override;
|
||||||
|
virtual void pause() override;
|
||||||
|
virtual void stop() override;
|
||||||
|
|
||||||
|
virtual void setVolume(int volume) override;
|
||||||
|
|
||||||
|
virtual void setOffset(const microsec& offset) override;
|
||||||
|
virtual microsec fetchOffset() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Music _music;
|
||||||
|
sf::Clock _offset_interpolator;
|
||||||
|
|
||||||
|
microsec _sfml_music_offset;
|
||||||
|
microsec _previous_frame_offset;
|
||||||
|
microsec _absolute_offset;
|
||||||
|
};
|
Loading…
Reference in New Issue