forked from NaiJi/project-kyoku
Improve work with timeline
This commit is contained in:
parent
f66951bcec
commit
e5969d1484
|
@ -1,7 +1,6 @@
|
||||||
#ifndef APPLICATION_H
|
#ifndef APPLICATION_H
|
||||||
#define APPLICATION_H
|
#define APPLICATION_H
|
||||||
|
|
||||||
#include <SFML/Audio/Music.hpp>
|
|
||||||
#include <SFML/System/Clock.hpp>
|
#include <SFML/System/Clock.hpp>
|
||||||
#include <SFML/Window/Keyboard.hpp>
|
#include <SFML/Window/Keyboard.hpp>
|
||||||
|
|
||||||
|
@ -21,7 +20,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::RenderWindow _game_window;
|
sf::RenderWindow _game_window;
|
||||||
sf::Music _music;
|
|
||||||
|
|
||||||
sf::Font _font;
|
sf::Font _font;
|
||||||
sf::Text _grade;
|
sf::Text _grade;
|
||||||
|
|
|
@ -12,6 +12,13 @@ public:
|
||||||
_perfect_offset(perfect_offset) {}
|
_perfect_offset(perfect_offset) {}
|
||||||
virtual ~Note() = 0;
|
virtual ~Note() = 0;
|
||||||
|
|
||||||
|
virtual bool isActive(microsec music_offset) const = 0;
|
||||||
|
|
||||||
|
virtual microsec offset() const
|
||||||
|
{
|
||||||
|
return _perfect_offset;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
microsec _perfect_offset;
|
microsec _perfect_offset;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,9 +11,11 @@ class Timeline
|
||||||
public:
|
public:
|
||||||
virtual ~Timeline() = default;
|
virtual ~Timeline() = default;
|
||||||
|
|
||||||
virtual void update(const microsec& music_offset) = 0;
|
virtual void update() = 0;
|
||||||
virtual void init() = 0;
|
virtual void init() = 0;
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
virtual microsec currentMusicOffset() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TIMELINE_H
|
#endif // TIMELINE_H
|
||||||
|
|
|
@ -20,12 +20,6 @@ Application::Application() :
|
||||||
|
|
||||||
void Application::run()
|
void Application::run()
|
||||||
{
|
{
|
||||||
std::string song_filename = "/home/naiji/METEOR.flac";
|
|
||||||
|
|
||||||
_music.openFromFile(song_filename);
|
|
||||||
_music.play();
|
|
||||||
_music.setVolume(30);
|
|
||||||
|
|
||||||
_game_window.display();
|
_game_window.display();
|
||||||
|
|
||||||
startGameLoop();
|
startGameLoop();
|
||||||
|
@ -63,10 +57,10 @@ void Application::input()
|
||||||
|
|
||||||
void Application::update()
|
void Application::update()
|
||||||
{
|
{
|
||||||
|
_game->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::draw()
|
void Application::draw()
|
||||||
{
|
{
|
||||||
|
// _game->draw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "classicgame.h"
|
#include "classicgame.h"
|
||||||
#include "classicinputtype.h"
|
#include "classicinputtype.h"
|
||||||
#include "classictimeline.h"
|
#include "classictimeline.h"
|
||||||
|
#include "classicnote.h"
|
||||||
|
|
||||||
ClassicGame::ClassicGame() :
|
ClassicGame::ClassicGame() :
|
||||||
_timeline(std::make_unique<ClassicTimeline>())
|
_timeline(std::make_unique<ClassicTimeline>())
|
||||||
|
@ -52,7 +53,7 @@ void ClassicGame::run()
|
||||||
void ClassicGame::input(const sf::Event& event)
|
void ClassicGame::input(const sf::Event& event)
|
||||||
{
|
{
|
||||||
Action new_action = Action::NONE;
|
Action new_action = Action::NONE;
|
||||||
microsec timestamp = 0; /* 0 is temp. get from timeline */
|
microsec timestamp = _timeline->currentMusicOffset();
|
||||||
|
|
||||||
switch (event.type)
|
switch (event.type)
|
||||||
{
|
{
|
||||||
|
@ -72,9 +73,10 @@ void ClassicGame::input(const sf::Event& event)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassicInputType input(timestamp, new_action);
|
auto note = _timeline->getActiveNote();
|
||||||
auto note = _timeline->getActiveNote(timestamp);
|
|
||||||
note->
|
if (!_timeline->isExpired(note))
|
||||||
|
(*note)->input(ClassicInputType(timestamp, new_action));
|
||||||
}
|
}
|
||||||
|
|
||||||
Action ClassicGame::getActionKeyPressed(Button button) const
|
Action ClassicGame::getActionKeyPressed(Button button) const
|
||||||
|
@ -89,7 +91,8 @@ Action ClassicGame::getActionKeyReleased(Button button) const
|
||||||
|
|
||||||
void ClassicGame::update()
|
void ClassicGame::update()
|
||||||
{
|
{
|
||||||
|
_timeline->update();
|
||||||
|
_timeline->fetchVisibleNotes(_view_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGame::draw(const sf::RenderWindow& window) const
|
void ClassicGame::draw(const sf::RenderWindow& window) const
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "classicactions.h"
|
#include "classicactions.h"
|
||||||
|
|
||||||
class ClassicTimeline;
|
class ClassicTimeline;
|
||||||
|
class ClassicViewManager;
|
||||||
|
|
||||||
class ClassicGame final : public Game
|
class ClassicGame final : public Game
|
||||||
{
|
{
|
||||||
|
@ -29,7 +30,7 @@ private:
|
||||||
Action getActionKeyReleased(Button button) const;
|
Action getActionKeyReleased(Button button) const;
|
||||||
|
|
||||||
std::unique_ptr<ClassicTimeline> _timeline;
|
std::unique_ptr<ClassicTimeline> _timeline;
|
||||||
|
std::unique_ptr<ClassicViewManager> _view_manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLASSICGAME_H
|
#endif // CLASSICGAME_H
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
#include "classicnote.h"
|
#include "classicnote.h"
|
||||||
|
|
||||||
ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset) :
|
ClassicNote::ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, Action action) :
|
||||||
Note(perfect_offset),
|
Note(perfect_offset),
|
||||||
_evaluator(intervals, _perfect_offset)
|
_evaluator(intervals, _perfect_offset),
|
||||||
{
|
_action(action)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool ClassicNote::isActive(microsec music_offset) const
|
||||||
|
{
|
||||||
|
return _evaluator.isActive(music_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassicNote::GRADE ClassicNote::input(ClassicInputType&& input_data)
|
||||||
|
{
|
||||||
|
if (input_data == _action)
|
||||||
|
{
|
||||||
|
return _evaluator.calculatePrecision(input_data.timestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClassicNote::GRADE::BAD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "note.h"
|
#include "note.h"
|
||||||
#include "precisionevaluator.h"
|
#include "precisionevaluator.h"
|
||||||
|
#include "classicinputtype.h"
|
||||||
|
|
||||||
class ClassicNote : public Note
|
class ClassicNote : public Note
|
||||||
{
|
{
|
||||||
|
@ -14,9 +15,13 @@ public:
|
||||||
BAD
|
BAD
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset);
|
explicit ClassicNote(const std::vector<microsec>& intervals, microsec perfect_offset, Action action);
|
||||||
virtual ~ClassicNote() = default;
|
virtual ~ClassicNote() = default;
|
||||||
|
virtual bool isActive(microsec music_offset) const override;
|
||||||
|
|
||||||
|
GRADE input(ClassicInputType&& input_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PrecisionEvaluator<GRADE> _evaluator;
|
PrecisionEvaluator<GRADE> _evaluator;
|
||||||
|
Action _action;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "classicactions.h"
|
#include "classicactions.h"
|
||||||
#include "classictimeline.h"
|
#include "classictimeline.h"
|
||||||
#include "note.h"
|
#include "classicnote.h"
|
||||||
|
|
||||||
ClassicTimeline::ClassicTimeline()
|
ClassicTimeline::ClassicTimeline()
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,12 @@ ClassicTimeline::ClassicTimeline()
|
||||||
// Length is 1:14
|
// Length is 1:14
|
||||||
// I calculated that the time between beats is about 1412162 microseconds
|
// I calculated that the time between beats is about 1412162 microseconds
|
||||||
|
|
||||||
|
std::string song_filename = "/home/naiji/METEOR.flac";
|
||||||
|
|
||||||
|
_music.openFromFile(song_filename);
|
||||||
|
_music.play();
|
||||||
|
_music.setVolume(30);
|
||||||
|
|
||||||
_timeline.reserve(1000);
|
_timeline.reserve(1000);
|
||||||
|
|
||||||
microsec starting_beat_offset = 372162;
|
microsec starting_beat_offset = 372162;
|
||||||
|
@ -19,91 +25,100 @@ ClassicTimeline::ClassicTimeline()
|
||||||
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 * 12;
|
_visibility_offset = note_input_offset * 12;
|
||||||
|
|
||||||
_timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::DOWN));
|
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_DOWN));
|
||||||
bpm_iterator += interval;
|
bpm_iterator += interval;
|
||||||
|
|
||||||
_timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT));
|
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT));
|
||||||
bpm_iterator += interval;
|
bpm_iterator += interval;
|
||||||
|
|
||||||
_timeline.emplace_back(new Note(bpm_iterator, note_input_offset, Button::LEFT));
|
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT));
|
||||||
bpm_iterator += interval;
|
bpm_iterator += interval;
|
||||||
|
|
||||||
while (bpm_iterator < bpm_end)
|
while (bpm_iterator < bpm_end)
|
||||||
{
|
{
|
||||||
_timeline.emplace_back(new Note(bpm_iterator, note_input_offset));
|
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP));
|
||||||
bpm_iterator += interval;
|
bpm_iterator += interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
_active_note = nullptr;
|
expire(_active_note);
|
||||||
_last_visible_note = _timeline.end();
|
|
||||||
_top_note = _timeline.begin();
|
_top_note = _timeline.begin();
|
||||||
|
|
||||||
_last_visible_note = _top_note;
|
_last_visible_note = _top_note;
|
||||||
_view_manager->initNoteGraphics(*_top_note);
|
|
||||||
prepareNotesToDraw(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::prepareNotesToDraw(const microsec &music_offset)
|
ClassicTimeline::~ClassicTimeline()
|
||||||
{
|
|
||||||
auto note_iterator = _top_note;
|
|
||||||
|
|
||||||
while (((*note_iterator)->offset() - _visibility_offset) <= music_offset)
|
|
||||||
{
|
|
||||||
++note_iterator;
|
|
||||||
if (note_iterator > _last_visible_note)
|
|
||||||
_view_manager->initNoteGraphics((*note_iterator));
|
|
||||||
}
|
|
||||||
|
|
||||||
_last_visible_note = note_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
Timeline::~Timeline()
|
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::clear()
|
void ClassicTimeline::clear()
|
||||||
{
|
{
|
||||||
for (auto note : _timeline)
|
for (auto note : _timeline)
|
||||||
delete note;
|
delete note;
|
||||||
|
|
||||||
_timeline.clear();
|
_timeline.clear();
|
||||||
_top_note = _timeline.end();
|
expire(_top_note);
|
||||||
_last_visible_note = _timeline.end();
|
expire(_last_visible_note);
|
||||||
_active_note = nullptr;
|
expire(_active_note);
|
||||||
|
|
||||||
Note::resetPrecisionQualifier();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::update(const microsec &music_offset)
|
void ClassicTimeline::update()
|
||||||
{
|
{
|
||||||
checkCurrentActiveNote(music_offset);
|
const auto& offset = currentMusicOffset();
|
||||||
checkForNextActiveNote(music_offset);
|
std::cout << "Upadting at: " << offset << '\n';
|
||||||
prepareNotesToDraw(music_offset);
|
checkCurrentActiveNote(offset);
|
||||||
|
checkForNextActiveNote(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::checkCurrentActiveNote(const microsec &music_offset)
|
void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset)
|
||||||
{
|
{
|
||||||
if (_active_note && !_active_note->isActive(music_offset))
|
if (!isExpired(_active_note) && !(*_active_note)->isActive(music_offset))
|
||||||
{
|
{
|
||||||
_active_note = nullptr;
|
expire(_active_note);
|
||||||
(*_top_note)->resetSprite();
|
|
||||||
++_top_note;
|
++_top_note;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::checkForNextActiveNote(const microsec &music_offset)
|
void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset)
|
||||||
{
|
{
|
||||||
if (!_active_note && (*_top_note)->isActive(music_offset))
|
if (isExpired(_active_note) && (*_top_note)->isActive(music_offset))
|
||||||
{
|
{
|
||||||
std::cout << "New active note: " << music_offset << '\n';
|
std::cout << "New active note: " << music_offset << '\n';
|
||||||
_active_note = *_top_note;
|
_active_note = _top_note;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Note* Timeline::fetchActiveNote(const microsec &music_offset) noexcept
|
ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept
|
||||||
{
|
{
|
||||||
std::cout << "Clicked at: " << music_offset << '\n';
|
update();
|
||||||
update(music_offset);
|
|
||||||
return _active_note;
|
return _active_note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClassicTimeline::isExpired(const Iterator &iterator)
|
||||||
|
{
|
||||||
|
return iterator == _timeline.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicTimeline::expire(Iterator &iterator)
|
||||||
|
{
|
||||||
|
iterator = _timeline.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
microsec ClassicTimeline::currentMusicOffset() const
|
||||||
|
{
|
||||||
|
return _music.getPlayingOffset().asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr<ClassicViewManager>& view_manager)
|
||||||
|
{
|
||||||
|
Iterator note_iterator = _top_note;
|
||||||
|
auto music_offset = currentMusicOffset();
|
||||||
|
|
||||||
|
while (((*note_iterator)->offset() - _visibility_offset) <= music_offset)
|
||||||
|
{
|
||||||
|
++note_iterator;
|
||||||
|
if (note_iterator > _last_visible_note)
|
||||||
|
(void) view_manager;//_view_manager->initNoteGraphics((*note_iterator));
|
||||||
|
}
|
||||||
|
|
||||||
|
_last_visible_note = note_iterator;
|
||||||
|
}
|
||||||
|
|
|
@ -1,31 +1,45 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
#include "timeline.h"
|
#include "timeline.h"
|
||||||
|
#include <SFML/Audio/Music.hpp>
|
||||||
|
|
||||||
class Note;
|
class ClassicNote;
|
||||||
|
class ClassicViewManager;
|
||||||
|
|
||||||
class ClassicTimeline : public Timeline
|
class ClassicTimeline : public Timeline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ClassicTimeline();
|
explicit ClassicTimeline();
|
||||||
virtual void update(const microsec& music_offset) override;
|
virtual ~ClassicTimeline();
|
||||||
|
virtual void update() override;
|
||||||
virtual void init() override;
|
virtual void init() override;
|
||||||
virtual void clear() override;
|
virtual void clear() override;
|
||||||
|
|
||||||
Note *getActiveNote(const microsec &music_offset) noexcept;
|
virtual microsec currentMusicOffset() const override;
|
||||||
|
|
||||||
|
void fetchVisibleNotes(const std::unique_ptr<ClassicViewManager>& view_manager);
|
||||||
|
|
||||||
|
using Iterator = std::vector<ClassicNote*>::const_iterator;
|
||||||
|
|
||||||
|
Iterator getActiveNote() noexcept;
|
||||||
|
|
||||||
|
bool isExpired(const Iterator& iterator);
|
||||||
|
void expire(Iterator& iterator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Note*> _timeline;
|
std::vector<ClassicNote*> _timeline;
|
||||||
std::vector<Note*>::const_iterator _top_note;
|
Iterator _top_note;
|
||||||
Note* _active_note;
|
Iterator _active_note;
|
||||||
|
Iterator _last_visible_note;
|
||||||
|
|
||||||
std::vector<Note*>::const_iterator _last_visible_note;
|
|
||||||
microsec _visibility_offset;
|
microsec _visibility_offset;
|
||||||
|
|
||||||
|
sf::Music _music;
|
||||||
|
|
||||||
void checkCurrentActiveNote(const microsec &music_offset);
|
void checkCurrentActiveNote(const microsec &music_offset);
|
||||||
void checkForNextActiveNote(const microsec &music_offset);
|
void checkForNextActiveNote(const microsec &music_offset);
|
||||||
void prepareNotesToDraw(const microsec &music_offset);
|
|
||||||
|
|
||||||
/* 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
|
||||||
|
|
Loading…
Reference in New Issue