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

204 lines
4.7 KiB
C++

#include <iostream>
#include "classicactions.h"
#include "classictimeline.h"
#include "classicnote.h"
#include "spritecontainer.h"
#include "classicgraphicsmanager.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 = "METEOR.flac";
_music.openFromFile(song_filename);
_music.setVolume(10);
microsec starting_beat_offset = 352162;
int amount_of_beats = 209;
microsec interval = 1412162;
microsec tempo_interval = interval / 2;
microsec note_input_offset = 412162 / 3;
microsec bpm_iterator = starting_beat_offset;
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
_visibility_offset = note_input_offset * 12;
_input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset};
bpm_iterator += tempo_interval;
float x = 90.;
while (bpm_iterator < bpm_end)
{
_timeline.emplace_back(new ClassicNote(_input_intervals, bpm_iterator, Action::PRESS_UP, {x, 390.}));
bpm_iterator += tempo_interval;
x += 70;
if (x >= 1200)
x = 90.;
}
expire(_first_visible_note);
expire(_last_visible_note);
expire(_active_note);
_top_note = _timeline.begin();
}
void ClassicTimeline::run()
{
_music.play();
}
ClassicTimeline::~ClassicTimeline()
{
clear();
}
void ClassicTimeline::clear()
{
for (auto& note : _timeline)
delete note;
_timeline.clear();
}
void ClassicTimeline::update()
{
checkCurrentActiveNote();
checkForNextActiveNote();
updateVisibleSprites(currentMusicOffset());
}
void ClassicTimeline::checkCurrentActiveNote()
{
if (isExpired(_active_note))
return;
auto note = *_active_note;
if (!note->isActive())
{
expire(_active_note);
++_top_note;
}
}
void ClassicTimeline::checkForNextActiveNote()
{
if (!isExpired(_active_note))
return;
auto top_note = *_top_note;
if (top_note->isActive())
_active_note = _top_note;
}
void ClassicTimeline::updateVisibleSprites(const microsec& music_offset)
{
if (nothingToDraw())
return;
std::for_each(_first_visible_note, _last_visible_note,
[&music_offset](const auto& note)
{
note->update(music_offset);
});
}
ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept
{
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();
}
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<ClassicGraphicsManager>& graphics_manager)
{
const microsec music_offset = currentMusicOffset();
initGraphicsForNewNotes(graphics_manager, music_offset);
discardGraphicsForDeadNotes(graphics_manager);
}
void ClassicTimeline::initGraphicsForNewNotes(const std::unique_ptr<ClassicGraphicsManager>& graphics_manager, const microsec &music_offset)
{
Iterator note_iterator = _top_note;
while (isVisiblyClose(note_iterator, music_offset))
{
if (nothingToDraw())
_first_visible_note = note_iterator;
auto note = *note_iterator;
if (!note->sprite())
{
graphics_manager->initSprite(note);
note->putToGame(music_offset);
}
++note_iterator;
}
_last_visible_note = note_iterator;
}
void ClassicTimeline::discardGraphicsForDeadNotes(const std::unique_ptr<ClassicGraphicsManager>& graphics_manager)
{
if (nothingToDraw())
return;
auto note_iterator = _first_visible_note;
while (note_iterator != _last_visible_note)
{
auto note = *note_iterator;
if (note->isExpired())
{
graphics_manager->resetSprite(note);
++_first_visible_note;
}
++note_iterator;
}
}
bool ClassicTimeline::nothingToDraw() const noexcept
{
return isExpired(_first_visible_note);
}
void ClassicTimeline::drawVisibleNotes(sf::RenderWindow &window) const
{
if (nothingToDraw())
return;
std::for_each(_first_visible_note, _last_visible_note,
[&window](const auto& note)
{
window.draw(*note);
});
}