You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
project-kyoku/src/classicgame/classictimeline.cpp

170 lines
4.5 KiB
C++

#include <iostream>
#include "classicactions.h"
#include "classictimeline.h"
#include "classicnote.h"
#include "classicviewmanager.h"
#include <SFML/Graphics/RenderTarget.hpp>
ClassicTimeline::ClassicTimeline()
{
// BPM of METEOR is 170.
// Length is 1:14
// I calculated that the time between beats is about 1412162 microseconds
std::string song_filename = "/home/naiji/METEOR.flac";
_music.openFromFile(song_filename);
_music.setVolume(10);
_timeline.reserve(1000);
microsec starting_beat_offset = 372162;
int amount_of_beats = 209;
microsec interval = 1412162;
microsec note_input_offset = 412162;
microsec bpm_iterator = starting_beat_offset;
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
_visibility_offset = note_input_offset * 6;
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_DOWN, {90, 90}));
bpm_iterator += interval;
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {190, 90}));
bpm_iterator += interval;
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_LEFT, {290, 90}));
bpm_iterator += interval;
while (bpm_iterator < bpm_end)
{
_timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP, {390, 390}));
bpm_iterator += interval;
}
expire(_last_visible_note);
expire(_active_note);
_top_note = _timeline.begin();
}
void ClassicTimeline::init()
{
_music.play();
}
ClassicTimeline::~ClassicTimeline()
{
clear();
}
void ClassicTimeline::clear()
{
for (auto note : _timeline)
delete note;
_timeline.clear();
expire(_top_note);
expire(_last_visible_note);
expire(_active_note);
}
void ClassicTimeline::update()
{
const microsec& offset = currentMusicOffset();
checkCurrentActiveNote(offset);
checkForNextActiveNote(offset);
}
void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset)
{
if (!isExpired(_active_note) && !(*_active_note)->isActive(music_offset))
{
expire(_active_note);
++_top_note;
}
}
void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset)
{
if (isExpired(_active_note) && (*_top_note)->isActive(music_offset))
{
std::cout << "New active note: " << music_offset << '\n';
_active_note = _top_note;
}
}
ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept
{
update();
return _active_note;
}
bool ClassicTimeline::isExpired(const Iterator &iterator) const
{
return iterator == _timeline.end();
}
void ClassicTimeline::expire(Iterator &iterator)
{
iterator = _timeline.end();
}
microsec ClassicTimeline::currentMusicOffset() const
{
return _music.getPlayingOffset().asMicroseconds();
}
void ClassicTimeline::discardExpiredNotes(const std::unique_ptr<ClassicViewManager> &view_manager, const microsec &music_offset)
{
if (_top_note == _timeline.begin())
return;
Iterator past_note = _top_note - 1;
std::shared_ptr<ClassicSprite> sprite = (*past_note)->sprite();
while (sprite)
{ // CAREFULLY REWRITE
view_manager->resetNoteSprite(*past_note);
if (past_note == _timeline.begin())
return;
--past_note;
sprite = (*past_note)->sprite();
}
}
bool ClassicTimeline::isVisiblyClose(const Iterator &iterator, const microsec &music_offset) const
{
return ((*iterator)->offset() - _visibility_offset) <= music_offset;
}
void ClassicTimeline::fetchVisibleNotes(const std::unique_ptr<ClassicViewManager>& view_manager)
{
microsec music_offset = currentMusicOffset();
discardExpiredNotes(view_manager, music_offset);
Iterator note_iterator = _top_note;
while (isVisiblyClose(note_iterator, music_offset))
{
ClassicNote* note = *note_iterator;
if (!note->sprite())
view_manager->initNoteSprite(note);
++note_iterator;
}
_last_visible_note = note_iterator;
}
void ClassicTimeline::drawVisibleNotes(sf::RenderWindow &window) const
{
bool no_visible_notes = isExpired(_last_visible_note)
|| _top_note > _last_visible_note;
if (no_visible_notes)
return;
Iterator note_to_draw = _top_note;
while (note_to_draw != (_last_visible_note))
{
window.draw(*(*note_to_draw));
++note_to_draw;
}
}