#include #include "classicactions.h" #include "classictimeline.h" #include "classicnote.h" #include "classicviewmanager.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(_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(); 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 &view_manager) { if (_top_note == _timeline.begin()) return; Iterator past_note = _top_note - 1; std::shared_ptr 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& view_manager) { const microsec music_offset = currentMusicOffset(); discardExpiredNotes(view_manager); Iterator note_iterator = _top_note; while (isVisiblyClose(note_iterator, music_offset)) { ClassicNote* note = *note_iterator; if (!note->sprite()) { note->saveAppearanceTime(music_offset); view_manager->initNoteSprite(note); } if (note->state() == ClassicNote::State::DEAD) { view_manager->resetNoteSprite(note); } else note->update(music_offset); ++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)) { if ((*note_to_draw)->sprite()) window.draw(*(*note_to_draw)); ++note_to_draw; } }