#include #include "classicactions.h" #include "classictimeline.h" #include "classicnote.h" #include "spritecontainer.h" #include 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); _timeline.reserve(1000); microsec starting_beat_offset = 352162; 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 * 8; _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; float x = 90.; while (bpm_iterator < bpm_end) { _timeline.emplace_back(new ClassicNote({note_input_offset}, bpm_iterator, Action::PRESS_UP, {x, 390.})); bpm_iterator += interval; x += 70; } 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() { const microsec& offset = currentMusicOffset(); checkCurrentActiveNote(offset); checkForNextActiveNote(offset); } void ClassicTimeline::checkCurrentActiveNote(const microsec &music_offset) { if (isExpired(_active_note)) return; auto note = *_active_note; if (!note->isActive(music_offset)) { expire(_active_note); ++_top_note; } } void ClassicTimeline::checkForNextActiveNote(const microsec &music_offset) { if (!isExpired(_active_note)) return; auto top_note = *_top_note; if (top_note->isActive(music_offset)) _active_note = _top_note; } 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(SpriteContainer& sprite_container) { const microsec music_offset = currentMusicOffset(); initGraphicsForNewNotes(sprite_container, music_offset); discardGraphicsForDeadNotes(sprite_container); } void ClassicTimeline::initGraphicsForNewNotes(SpriteContainer& sprite_container, 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()) continue; note->saveAppearanceTime(music_offset); const auto action_type = note->action(); const auto sprite = sprite_container.getSprite(action_type); note->setSprite(sprite); } _last_visible_note = note_iterator; } void ClassicTimeline::discardGraphicsForDeadNotes(SpriteContainer &sprite_container) { if (nothingToDraw()) return; auto note_iterator = _first_visible_note; while (note_iterator != _last_visible_note) { auto note = *note_iterator; if (note->state() == ClassicNote::State::DEAD) { note->setState(ClassicNote::State::NONE); const auto action_type = note->action(); sprite_container.resetSprite(note->sprite(), action_type); note->setSprite(nullptr); ++_first_visible_note; } } } 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); }); }