#include "beat_system.hpp" #include "../messages.hpp" #include #include namespace phase_shifter::gameplay { namespace { auto smootherstep(float edge0, float edge1, float x) { x = std::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); return x * x * x * (x * (x * 6.f - 15.f) + 10.f); } } // namespace Beat_system::Beat_system(mirrage::util::Message_bus& bus, mirrage::asset::Asset_manager& assets) : _bus(bus), _mailbox(bus), _assets(assets) { auto input = _assets.open(mirrage::asset::AID("beat:pulse")).get_or_throw(); std::string line; int i = 0; while(std::getline(input, line)) { _time_stamps.push_back(static_cast(atof(line.substr(1, line.length() - 4).c_str()))); i++; } _state.beats_left = static_cast(_time_stamps.size()); _state.avg_beat_time = static_cast(_time_stamps[_time_stamps.size() - 1]) / _time_stamps.size(); _mailbox.subscribe_to([&](Beat_missed_msg& e) { decrease_beats_left(1); }); } void Beat_system::update(mirrage::util::Time dt) { _acc += dt.value(); int size = static_cast(_time_stamps.size()); auto beat = _beat_index + 1 < size && _acc >= _time_stamps[_beat_index + 1]; int beats_left = _state.beats_left; if(beat) { _beat_index++; LOG(plog::debug) << "beat"; _bus.send(0.03f, 0.05f); beats_left = size - 1 - _beat_index + _beat_offset; if(beats_left <= 0 || _beat_index + 1 >= size) { _bus.send(); } } _state = {beat, _beat_index >= 0 ? _acc - _time_stamps[_beat_index] : _acc, _beat_index + 1 < size ? _time_stamps[_beat_index + 1] - _acc : 999, _state.avg_beat_time, beats_left}; } auto Beat_system::graphic_time_scale() const -> float { if(_beat_index < 0) return 0.2f; constexpr auto t1_len = 0.05f; constexpr auto t2_len = 0.6f; constexpr auto factor = (1.f - (1.f - t1_len - t2_len) * 0.05f) / (t1_len + t2_len) * 2.f; auto to = _state.time_to_beat / _state.avg_beat_time; auto from = _state.time_to_beat / _state.avg_beat_time; return mirrage::util::max(0.05f, factor * (1.f - smootherstep(0.f, t1_len, to)), factor * (1.f - smootherstep(0.f, t2_len, from))); } void Beat_system::decrease_beats_left(int count) { _beat_offset -= count; if(_state.beats_left > 0) { _state.beats_left -= count; if(_state.beats_left <= 0) { _bus.send(); } } } void Beat_system::increase_beats_left(int count) { _beat_offset += count; _state.beats_left += count; } const std::vector& Beat_system::time_stamps() const { return _time_stamps; } int Beat_system::beat_index() const { return _beat_index; } } // namespace phase_shifter::gameplay