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
|
||||
|
||||
#include <SFML/Window/Event.hpp>
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
|
||||
struct PlayerInput
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PRECISIONEVALUATOR_H
|
||||
#define PRECISIONEVALUATOR_H
|
||||
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef TIMELINE_H
|
||||
#define TIMELINE_H
|
||||
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -13,10 +13,9 @@ class Timeline
|
|||
public:
|
||||
virtual ~Timeline() = default;
|
||||
|
||||
virtual void update() = 0;
|
||||
virtual void update(const microsec& offset) = 0;
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual microsec currentMusicOffset() 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/gamestate.h"
|
||||
|
||||
#include "tools/musicsfml.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
|
||||
|
||||
Application::Application() :
|
||||
_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.setKeyRepeatEnabled(false);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
#include <memory>
|
||||
|
||||
class ClassicSprite;
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
#include "classictimeline.h"
|
||||
#include "classicnote.h"
|
||||
#include "classicmapcreator.h"
|
||||
#include "tools/music.h"
|
||||
#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>()),
|
||||
_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.setBuffer(_slap_buffer);
|
||||
|
@ -58,12 +61,15 @@ void ClassicGame::run()
|
|||
{
|
||||
ClassicMapCreator creator(_graphics_manager);
|
||||
auto beatmap = creator.createBeatmap("aa");
|
||||
_music->openFromFile("METEOR.flac");
|
||||
_music->setVolume(10);
|
||||
_music->play();
|
||||
_timeline->run(std::move(beatmap.notes), beatmap.visibility_offset);
|
||||
}
|
||||
|
||||
void ClassicGame::input(PlayerInput&& inputdata)
|
||||
{
|
||||
inputdata.timestamp = _timeline->currentMusicOffset();
|
||||
inputdata.timestamp = _music->fetchOffset();
|
||||
|
||||
switch (inputdata.event.type)
|
||||
{
|
||||
|
@ -73,6 +79,22 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
|||
|
||||
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();
|
||||
|
||||
if (!_timeline->isExpired(note_it))
|
||||
|
@ -111,7 +133,7 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
|||
|
||||
void ClassicGame::update()
|
||||
{
|
||||
_timeline->update();
|
||||
_timeline->update(_music->fetchOffset());
|
||||
_timeline->fetchVisibleNotes();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <SFML/Audio/SoundBuffer.hpp>
|
||||
#include <SFML/Audio/Sound.hpp>
|
||||
|
||||
class Music;
|
||||
class ClassicNote;
|
||||
class ClassicTimeline;
|
||||
class ClassicGraphicsManager;
|
||||
|
@ -14,7 +15,7 @@ class ClassicGraphicsManager;
|
|||
class ClassicGame final : public Game
|
||||
{
|
||||
public:
|
||||
explicit ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager);
|
||||
explicit ClassicGame(std::unique_ptr<ClassicGraphicsManager>&& manager, std::unique_ptr<Music>&& music);
|
||||
virtual ~ClassicGame() override;
|
||||
|
||||
virtual void run() override;
|
||||
|
@ -34,6 +35,10 @@ private:
|
|||
std::unique_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||
sf::SoundBuffer _slap_buffer;
|
||||
sf::Sound _slap;
|
||||
|
||||
std::unique_ptr<Music> _music;
|
||||
|
||||
bool _is_paused;
|
||||
};
|
||||
|
||||
#endif // CLASSICGAME_H
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
#include "classicgraphicsmanager.h"
|
||||
|
||||
struct Beatmap
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/mathutils.h"
|
||||
#include "tools/mathutils.h"
|
||||
#include "game/sprite.h"
|
||||
#include "SFML/Graphics/RectangleShape.hpp"
|
||||
#include "SFML/Graphics/Text.hpp"
|
||||
|
|
|
@ -3,19 +3,8 @@
|
|||
#include <iostream>
|
||||
|
||||
ClassicTimeline::ClassicTimeline() :
|
||||
_sfml_music_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);
|
||||
}
|
||||
_current_offset(0)
|
||||
{}
|
||||
|
||||
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);
|
||||
|
||||
fetchVisibleNotes();
|
||||
_music.play();
|
||||
|
||||
_previous_frame_offset = _offset_interpolator.restart().asMicroseconds();
|
||||
}
|
||||
|
||||
ClassicTimeline::~ClassicTimeline()
|
||||
|
@ -46,22 +32,13 @@ void ClassicTimeline::clear()
|
|||
_timeline.clear();
|
||||
}
|
||||
|
||||
void ClassicTimeline::update()
|
||||
void ClassicTimeline::update(const microsec& offset)
|
||||
{
|
||||
const auto interpolator_timestamp = _offset_interpolator.getElapsedTime().asMicroseconds();
|
||||
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;
|
||||
}
|
||||
_current_offset = offset;
|
||||
|
||||
checkCurrentActiveNote();
|
||||
checkForNextActiveNote();
|
||||
updateVisibleSprites(_absolute_offset);
|
||||
updateVisibleSprites(_current_offset);
|
||||
}
|
||||
|
||||
void ClassicTimeline::checkCurrentActiveNote()
|
||||
|
@ -115,11 +92,6 @@ void ClassicTimeline::expire(Iterator& iterator)
|
|||
iterator = _timeline.end();
|
||||
}
|
||||
|
||||
microsec ClassicTimeline::currentMusicOffset() const
|
||||
{
|
||||
return _music.getPlayingOffset().asMicroseconds();
|
||||
}
|
||||
|
||||
bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const
|
||||
{
|
||||
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
|
||||
|
@ -127,7 +99,7 @@ bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& m
|
|||
|
||||
void ClassicTimeline::fetchVisibleNotes()
|
||||
{
|
||||
findLastVisibleNote(_absolute_offset);
|
||||
findLastVisibleNote(_current_offset);
|
||||
findFirstVisibleNote();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
#include "game/timeline.h"
|
||||
|
||||
#include <SFML/Audio/Music.hpp>
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
|
@ -14,10 +12,9 @@ class ClassicTimeline : public Timeline
|
|||
public:
|
||||
explicit ClassicTimeline();
|
||||
virtual ~ClassicTimeline();
|
||||
virtual void update() override;
|
||||
virtual void update(const microsec& offset) override;
|
||||
virtual void clear() override;
|
||||
|
||||
virtual microsec currentMusicOffset() const override;
|
||||
virtual void drawVisibleNotes() const override;
|
||||
|
||||
void run(std::vector<ClassicNote*>&& notes, const microsec& visibility);
|
||||
|
@ -37,12 +34,7 @@ private:
|
|||
std::vector<microsec> _input_intervals;
|
||||
std::vector<ClassicNote*> _timeline;
|
||||
microsec _visibility_offset;
|
||||
|
||||
sf::Music _music;
|
||||
sf::Clock _offset_interpolator;
|
||||
microsec _sfml_music_offset;
|
||||
microsec _previous_frame_offset;
|
||||
microsec _absolute_offset;
|
||||
microsec _current_offset;
|
||||
|
||||
void updateVisibleSprites(const microsec& music_offset);
|
||||
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