Refactor music position, implement flow for Editor, link everything together

This commit is contained in:
NaiJi ✨ 2021-12-03 22:21:27 +03:00
parent 79543f6b93
commit 5e3ddccac0
19 changed files with 165 additions and 131 deletions

View File

@ -2,6 +2,7 @@
#include <set>
#include "core/inputtype.h"
#include "core/updatedata.h"
#include "core/bpmsection.h"
class Editor
@ -10,7 +11,7 @@ public:
virtual ~Editor() = default;
virtual void input(PlayerInput&& inputdata) = 0;
virtual void update(const sf::Time& dt) = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void draw() const = 0;
inline void setBPMSections(const std::set<BPMSection, BPMSectionCompt>& sections) noexcept

View File

@ -1,6 +1,7 @@
#pragma once
#include "core/inputtype.h"
#include "core/updatedata.h"
class Game
{
@ -10,6 +11,6 @@ public:
virtual void run() = 0;
virtual void input(PlayerInput&& inputdata) = 0;
virtual void update() = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void draw() const = 0;
};

View File

@ -28,6 +28,9 @@ public:
expire(_last_visible_note);
expire(_active_note);
if (isExpired(_top_note))
return;
fetchVisibleNotes();
}
@ -55,21 +58,20 @@ public:
{
_current_offset = offset;
if (isExpired(_top_note))
return;
checkCurrentActiveNote();
checkForNextActiveNote();
updateVisibleSprites(_current_offset);
}
void drawVisibleNotes() const
std::pair<Iterator, Iterator> getVisibleNotes() const
{
if (nothingToDraw())
return;
return std::pair<Iterator, Iterator>();
std::for_each(_first_visible_note, _last_visible_note,
[](const auto& note)
{
note->draw();
});
return std::make_pair(_first_visible_note, _last_visible_note);
}
void fetchVisibleNotes()
@ -80,6 +82,9 @@ public:
void findLastVisibleNote(const microsec& music_offset)
{
if (isExpired(_top_note))
return;
Iterator note_iterator = _top_note;
while (isVisiblyClose(note_iterator, music_offset))
{

View File

@ -0,0 +1,10 @@
#pragma once
#include <SFML/System/Time.hpp>
#include "tools/mathutils.h"
struct UpdateData
{
const microsec timestamp;
const sf::Time dt;
};

View File

@ -2,15 +2,17 @@
ClassicEditor::ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager) :
_graphics_manager(manager),
_selected_type(Type::UP)
_selected_type(Type::UP),
_current_time(0)
{
_context.graphics_manager = _graphics_manager;
_timeline.setNotes({}, 1648648);
}
void ClassicEditor::input(PlayerInput&& inputdata)
{
_current_time = inputdata.timestamp;
const auto& event = inputdata.event;
const auto offset = _music.fetchOffset();
switch (event.type)
{
@ -20,13 +22,13 @@ void ClassicEditor::input(PlayerInput&& inputdata)
case sf::Event::MouseButtonPressed:
{
const auto note = _timeline.getNoteBy(offset);
const auto note = _timeline.getNoteBy(_current_time);
if (_timeline.isExpired(note))
{
NoteInitializer init;
init.context = &_context;
init.intervals = {};
init.perfect_offset = offset;
init.perfect_offset = _current_time;
ElementInitializer elem_init;
elem_init.type = _selected_type;
@ -45,18 +47,22 @@ void ClassicEditor::input(PlayerInput&& inputdata)
}
}
void ClassicEditor::update(const sf::Time& dt)
void ClassicEditor::update(UpdateData&& updatedata)
{
(void)dt;
// TODO!!!
_timeline.update(_music.fetchOffset());
_timeline.update(updatedata.timestamp);
_timeline.fetchVisibleNotes();
}
void ClassicEditor::draw() const
{
_timeline.drawVisibleNotes();
const auto& graphics_manager = _graphics_manager;
auto notes = _timeline.getVisibleNotes();
std::for_each(notes.first, notes.second,
[graphics_manager](const auto& note)
{
note->draw();
});
}
void ClassicEditor::selectNoteType(Type type) noexcept

View File

@ -4,7 +4,6 @@
#include "core/editor.h"
#include "core/timeline.h"
#include "tools/music.h"
#include "mockclassicnote.h"
@ -16,17 +15,17 @@ public:
explicit ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager);
virtual void input(PlayerInput&& inputdata) override;
virtual void update(const sf::Time& dt) override;
virtual void update(UpdateData&& updatedata) override;
virtual void draw() const override;
void selectNoteType(Type type) noexcept;
private:
Music _music;
Context _context;
std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
Timeline<MockClassicNote> _timeline;
Type _selected_type;
microsec _current_time;
};

View File

@ -1,6 +1,7 @@
#include "classicgame.h"
#include "classicnote.h"
#include "classicmapcreator.h"
#include "graphics/classicgraphicsmanager.h"
#include "holdmanager.h"
ClassicGame::ClassicGame(std::shared_ptr<ClassicGraphicsManager>&& manager) :
@ -59,16 +60,11 @@ void ClassicGame::run()
_context.graphics_manager = _graphics_manager;
auto beatmap = classic::createBeatmap("aa", _context);
_music.openFromFile("METEOR.flac");
_music.setVolume(10);
_music.play();
_timeline.setNotes(beatmap.notes, beatmap.visibility_offset);
}
void ClassicGame::input(PlayerInput&& inputdata)
{
inputdata.timestamp = _music.fetchOffset();
switch (inputdata.event.type)
{
default:
@ -77,20 +73,6 @@ void ClassicGame::input(PlayerInput&& inputdata)
case sf::Event::KeyPressed:
{
if (inputdata.event.key.code == sf::Keyboard::Space)
{
if (_music.isPaused())
{
_music.play();
return;
}
else
{
_music.pause();
return;
}
}
auto note_it = _timeline.getActiveNote();
if (!_timeline.isExpired(note_it))
@ -111,13 +93,20 @@ void ClassicGame::input(PlayerInput&& inputdata)
}
}
void ClassicGame::update()
void ClassicGame::update(UpdateData&& updatedata)
{
_timeline.update(_music.fetchOffset());
_timeline.update(updatedata.timestamp);
_timeline.fetchVisibleNotes();
}
void ClassicGame::draw() const
{
_timeline.drawVisibleNotes();
const auto& graphics_manager = _graphics_manager;
auto notes = _timeline.getVisibleNotes();
std::for_each(notes.first, notes.second,
[graphics_manager](const auto& note)
{
note->draw();
});
}

View File

@ -8,9 +8,8 @@
#include "core/game.h"
#include "core/timeline.h"
#include "tools/music.h"
#include "classicmode/context.h"
#include "context.h"
#include "classicnote.h"
#include "classicmode/classicactions.h"
@ -27,7 +26,7 @@ public:
virtual void run() override;
virtual void input(PlayerInput&& inputdata) override;
virtual void update() override;
virtual void update(UpdateData&& updatedata) override;
virtual void draw() const override;
private:
@ -42,6 +41,5 @@ private:
sf::SoundBuffer _slap_buffer;
sf::Sound _slap;
Music _music;
Context _context;
};

View File

@ -1,6 +1,6 @@
#pragma once
#include "classicmode/context.h"
#include "context.h"
#include "core/note.h"
#include "core/precisionevaluator.h"
#include "classicmode/noteinitializer.h"

View File

@ -0,0 +1,12 @@
#pragma once
#include <memory>
class ClassicGraphicsManager;
class HoldManager;
struct Context
{
std::shared_ptr<ClassicGraphicsManager> graphics_manager;
std::shared_ptr<HoldManager> hold_manager;
};

View File

@ -23,6 +23,9 @@ EditorState::~EditorState()
void EditorState::input(const sf::Event& event)
{
if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
_music.isPaused() ? _music.play() : _music.pause();
_group->input(event);
}
@ -38,19 +41,57 @@ void EditorState::draw() const
void EditorState::enter()
{
_music.openFromFile("Uta-test.flac");
_music.setVolume(5);
auto& group = _group;
auto& music = _music;
auto& editor = _editor;
_music->openFromFile("Uta-test.flac");
_music->setVolume(5);
_bpm_calculator = std::make_shared<BPMCalculator>(_music);
_bpm_calculator = std::make_shared<BPMCalculator>();
auto& bpm_calculator = _bpm_calculator;
std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _font);
bpm_widget->init(_editor);
auto button_start = std::make_shared<PushButton>("Start", _font);
auto button_stop = std::make_shared<PushButton>("Stop", _font);
auto button_apply = std::make_shared<PushButton>("Apply", _font);
button_start->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.play();
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
});
button_stop->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.stop();
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
});
button_apply->setCallback([&editor, bpm_calculator]()
{
BPMSection section;
section.bpm = bpm_calculator->fetchApproximatedInfo().BPM;
section.fraction = 2;
section.offset_start = bpm_calculator->getStartingOffset();
editor->insertBPMSection(std::move(section));
});
BPMCalculatorWidget::Init bpm_widget_init;
bpm_widget_init.stop = button_stop;
bpm_widget_init.apply = button_apply;
bpm_widget_init.start = button_start;
bpm_widget_init.current_time = [&music]() -> microsec { return music.fetchOffset(); };
bpm_widget->init(std::move(bpm_widget_init));
const auto bpm_widget_callback = [&group, bpm_widget=bpm_widget, &music]()
{
music->stop();
music.stop();
bpm_widget->setVisibility(false);
group->unblock();
};
@ -113,14 +154,14 @@ void EditorState::enter()
editor->draw();
};
callbacks.onInput = [&editor](const sf::Event& event)
callbacks.onInput = [&editor, &music](const sf::Event& event)
{
editor->input(PlayerInput{0, event});
editor->input(PlayerInput{music.fetchOffset(), event});
};
callbacks.onUpdate = [&editor](const sf::Time& dt)
callbacks.onUpdate = [&editor, &music](const sf::Time& dt)
{
editor->update(dt);
editor->update(UpdateData{music.fetchOffset(), dt});
};
auto editor_widget = std::make_shared<EditorWidget>(std::move(callbacks));

View File

@ -33,7 +33,7 @@ private:
Callbacks _callbacks;
std::shared_ptr<Music> _music;
Music _music;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<Group> _group;

View File

@ -13,17 +13,15 @@ GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr<Game>&
void GameState::input(const sf::Event& event)
{
_game->input({0, event});
if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
_music.isPaused() ? _music.play() : _music.pause();
_game->input(PlayerInput{_music.fetchOffset(), event});
}
void GameState::update(const sf::Time& dt)
{
(void)dt;
// !!!!!!!!!!!!!!!!!!!!!!
// TODO.
//
// Oh dude... hang in there
_game->update();
_game->update(UpdateData{_music.fetchOffset(), dt});
}
void GameState::draw() const
@ -34,6 +32,10 @@ void GameState::draw() const
void GameState::enter()
{
_game->run();
_music.openFromFile("METEOR.flac");
_music.setVolume(10);
_music.play();
}
void GameState::leave()

View File

@ -1,6 +1,7 @@
#pragma once
#include "state.h"
#include "tools/music.h"
#include <SFML/Graphics/RenderWindow.hpp>
class Group;
@ -28,6 +29,7 @@ public:
virtual void leave() override;
private:
Music _music;
std::shared_ptr<Game> _game;
sf::RenderWindow& _game_window;

View File

@ -29,7 +29,7 @@ void BPMCalculatorWidget::input(const sf::Event& event)
case sf::Event::KeyPressed:
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space)
{
_bpm_calculator->click();
_bpm_calculator->click(_current_time());
}
break;
}
@ -46,7 +46,7 @@ void BPMCalculatorWidget::update(const sf::Time& dt)
{
_bpm_value.setString(std::to_string(static_cast<int>(beat_info.BPM)));
const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat();
const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(_current_time());
const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat);
const auto slider_path_left = _slider->rect().width / time_relation;
if (slider_path_left < 50)
@ -111,39 +111,13 @@ void BPMCalculatorWidget::setPosition(const sf::Vector2f &position)
Window::setPosition(position);
}
void BPMCalculatorWidget::init(const std::unique_ptr<Editor>& _editor)
void BPMCalculatorWidget::init(Init &&init)
{
auto& bpm_calculator = _bpm_calculator;
_button_start = init.start;
_button_stop = init.stop;
_button_apply = init.apply;
_button_start = std::make_shared<PushButton>("Start", _font);
_button_stop = std::make_shared<PushButton>("Stop", _font);
_button_apply = std::make_shared<PushButton>("Apply", _font);
_button_start->setCallback([bpm_calculator, button_start=_button_start, button_stop=_button_stop]()
{
bpm_calculator->music()->play(); // Remove when global play/stop available
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
});
_button_stop->setCallback([bpm_calculator, button_start=_button_start, button_stop=_button_stop]()
{
bpm_calculator->music()->stop(); // Remove when global play/stop available
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
});
_button_apply->setCallback([&_editor, bpm_calculator]()
{
BPMSection section;
section.bpm = bpm_calculator->fetchApproximatedInfo().BPM;
section.fraction = 2;
section.offset_start = bpm_calculator->getStartingOffset();
_editor->insertBPMSection(std::move(section));
});
_current_time = init.current_time;
addChild(_button_start);
addChild(_button_stop);

View File

@ -8,6 +8,7 @@
#include <SFML/Graphics/Text.hpp>
#include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp>
#include "tools/mathutils.h"
class BPMCalculator;
class Editor;
@ -15,6 +16,15 @@ class Editor;
class BPMCalculatorWidget : public Window
{
public:
struct Init
{
std::shared_ptr<PushButton> start;
std::shared_ptr<PushButton> stop;
std::shared_ptr<PushButton> apply;
std::function<microsec(void)> current_time;
};
explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<sf::Font> &font);
virtual void input(const sf::Event& event) override;
@ -26,7 +36,7 @@ public:
virtual void setVisibility(bool is_visible = true) override;
void init(const std::unique_ptr<Editor>& _editor);
void init(Init&& init);
private:
std::shared_ptr<PushButton> _button_start;
@ -41,5 +51,6 @@ private:
bool _ticked;
sf::Text _bpm_value;
std::function<microsec(void)> _current_time;
};

View File

@ -7,19 +7,16 @@
class BPMCalculator
{
public:
explicit BPMCalculator(const std::shared_ptr<Music>& music);
void setMusic(const std::shared_ptr<Music>& music);
std::shared_ptr<Music> music() const;
explicit BPMCalculator();
void start();
void stop();
void click();
void click(const microsec& offset);
bool calculating() const;
const beat_utils::BeatInfo& fetchApproximatedInfo();
microsec fetchTimeUntilNextBeat();
microsec fetchTimeUntilNextBeat(const microsec& offset);
microsec getStartingOffset() const;
void setStartingOffset(microsec offset);
@ -29,7 +26,6 @@ private:
bool _need_recalculate;
bool _calculating;
std::shared_ptr<Music> _music;
std::vector<microsec> _deltas;
microsec _previous_click_offset;
microsec _first_click_offset;

View File

@ -3,8 +3,7 @@
#include <numeric>
#include <iostream>
BPMCalculator::BPMCalculator(const std::shared_ptr<Music>& music) :
_music(music)
BPMCalculator::BPMCalculator()
{
reset();
}
@ -18,17 +17,6 @@ void BPMCalculator::reset()
_need_recalculate = true;
}
void BPMCalculator::setMusic(const std::shared_ptr<Music>& music)
{
_music = music;
reset();
}
std::shared_ptr<Music> BPMCalculator::music() const
{
return _music;
}
void BPMCalculator::start()
{
reset();
@ -46,25 +34,24 @@ bool BPMCalculator::calculating() const
return _calculating;
}
void BPMCalculator::click()
void BPMCalculator::click(const microsec &offset)
{
if (!_calculating)
return;
const microsec click_offset = _music->fetchOffset();
_need_recalculate = true;
if (_previous_click_offset == 0)
{
_previous_click_offset = click_offset;
_first_click_offset = click_offset;
_previous_click_offset = offset;
_first_click_offset = offset;
return;
}
const microsec delta = click_offset - _previous_click_offset;
const microsec delta = offset - _previous_click_offset;
_deltas.emplace_back(delta);
_previous_click_offset = click_offset;
_previous_click_offset = offset;
}
const beat_utils::BeatInfo& BPMCalculator::fetchApproximatedInfo()
@ -98,9 +85,9 @@ void BPMCalculator::moveStartingOffsetBy(microsec shift)
_first_click_offset += shift;
}
microsec BPMCalculator::fetchTimeUntilNextBeat()
microsec BPMCalculator::fetchTimeUntilNextBeat(const microsec& offset)
{
const microsec actual_offset = _music->fetchOffset() - getStartingOffset();
const microsec actual_offset = offset - getStartingOffset();
return actual_offset % fetchApproximatedInfo().interval;
}

View File

@ -29,7 +29,7 @@ void Music::stop()
bool Music::isPaused() const
{
return (_music.getStatus() == sf::Music::Paused);
return (_music.getStatus() != sf::Music::Playing);
}
void Music::setVolume(int volume)