beat_system.cpp 2.81 KB
Newer Older
Florian Oetke's avatar
Florian Oetke committed
1
2
#include "beat_system.hpp"

3
4
#include "../messages.hpp"

Florian Oetke's avatar
Florian Oetke committed
5
#include <mirrage/utils/log.hpp>
Florian Oetke's avatar
Florian Oetke committed
6
#include <mirrage/utils/min_max.hpp>
Florian Oetke's avatar
Florian Oetke committed
7
8
9
10

namespace phase_shifter::gameplay {

	namespace {
Florian Oetke's avatar
Florian Oetke committed
11
12
13
14
15
16
		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
Florian Oetke's avatar
Florian Oetke committed
17

Kevin Balz's avatar
Kevin Balz committed
18
	Beat_system::Beat_system(mirrage::util::Message_bus& bus, mirrage::asset::Asset_manager& assets)
Kevin Balz's avatar
Kevin Balz committed
19
	  : _bus(bus), _mailbox(bus), _assets(assets)
Kevin Balz's avatar
Kevin Balz committed
20
	{
Florian Oetke's avatar
Florian Oetke committed
21
		auto        input = _assets.open(mirrage::asset::AID("beat:pulse")).get_or_throw();
Kevin Balz's avatar
Kevin Balz committed
22
23
24
25
26
27
		std::string line;
		int         i = 0;
		while(std::getline(input, line)) {
			_time_stamps.push_back(static_cast<float>(atof(line.substr(1, line.length() - 4).c_str())));
			i++;
		}
Florian Oetke's avatar
Florian Oetke committed
28

Kevin Balz's avatar
Kevin Balz committed
29
		_state.beats_left = static_cast<int>(_time_stamps.size());
Florian Oetke's avatar
Florian Oetke committed
30
31
		_state.avg_beat_time =
		        static_cast<float>(_time_stamps[_time_stamps.size() - 1]) / _time_stamps.size();
Kevin Balz's avatar
Kevin Balz committed
32
33
		
		_mailbox.subscribe_to([&](Beat_missed_msg& e) { decrease_beats_left(1); });
Kevin Balz's avatar
Kevin Balz committed
34
	}
35

Florian Oetke's avatar
Florian Oetke committed
36
37
38
	void Beat_system::update(mirrage::util::Time dt)
	{
		_acc += dt.value();
39
40
		int  size       = static_cast<int>(_time_stamps.size());
		auto beat       = _beat_index + 1 < size && _acc >= _time_stamps[_beat_index + 1];
Kevin Balz's avatar
Kevin Balz committed
41
		int  beats_left = _state.beats_left;
Florian Oetke's avatar
Florian Oetke committed
42
		if(beat) {
Kevin Balz's avatar
Kevin Balz committed
43
			_beat_index++;
Florian Oetke's avatar
Florian Oetke committed
44
			LOG(plog::debug) << "beat";
Tim Scheiber's avatar
Tim Scheiber committed
45
			_bus.send<Screen_shake_msg>(0.03f, 0.05f);
46

47
			beats_left = size - 1 - _beat_index + _beat_offset;
Kevin Balz's avatar
Kevin Balz committed
48
			if(beats_left <= 0 || _beat_index + 1 >= size) {
49
50
				_bus.send<Lose_msg>();
			}
Florian Oetke's avatar
Florian Oetke committed
51
		}
Florian Oetke's avatar
Florian Oetke committed
52

Kevin Balz's avatar
Kevin Balz committed
53
54
		_state = {beat,
		          _beat_index >= 0 ? _acc - _time_stamps[_beat_index] : _acc,
Kevin Balz's avatar
merge    
Kevin Balz committed
55
		          _beat_index + 1 < size ? _time_stamps[_beat_index + 1] - _acc : 999,
Kevin Balz's avatar
Kevin Balz committed
56
		          _state.avg_beat_time,
Kevin Balz's avatar
Kevin Balz committed
57
		          beats_left};
Florian Oetke's avatar
Florian Oetke committed
58
59
	}

Florian Oetke's avatar
Florian Oetke committed
60
61
	auto Beat_system::graphic_time_scale() const -> float
	{
62
63
64
		if(_beat_index < 0)
			return 0.2f;

Florian Oetke's avatar
Florian Oetke committed
65
		constexpr auto t1_len = 0.05f;
Florian Oetke's avatar
Florian Oetke committed
66
		constexpr auto t2_len = 0.6f;
Florian Oetke's avatar
Florian Oetke committed
67
		constexpr auto factor = (1.f - (1.f - t1_len - t2_len) * 0.05f) / (t1_len + t2_len) * 2.f;
Florian Oetke's avatar
Florian Oetke committed
68
69
70
71

		auto to   = _state.time_to_beat / _state.avg_beat_time;
		auto from = _state.time_to_beat / _state.avg_beat_time;

Florian Oetke's avatar
Florian Oetke committed
72
		return mirrage::util::max(0.05f,
Florian Oetke's avatar
Florian Oetke committed
73
74
75
76
		                          factor * (1.f - smootherstep(0.f, t1_len, to)),
		                          factor * (1.f - smootherstep(0.f, t2_len, from)));
	}

Florian Oetke's avatar
Florian Oetke committed
77
78
	void Beat_system::decrease_beats_left(int count)
	{
Kevin Balz's avatar
Kevin Balz committed
79
		_beat_offset -= count;
Florian Oetke's avatar
Florian Oetke committed
80
81
82
83
84
85
86
87
		if(_state.beats_left > 0) {
			_state.beats_left -= count;

			if(_state.beats_left <= 0) {
				_bus.send<Lose_msg>();
			}
		}
	}
88

89
90
	void Beat_system::increase_beats_left(int count)
	{
Kevin Balz's avatar
Kevin Balz committed
91
92
93
94
		_beat_offset += count;
		_state.beats_left += count;
	}

Florian Oetke's avatar
Florian Oetke committed
95
	const std::vector<float>& Beat_system::time_stamps() const { return _time_stamps; }
96

Florian Oetke's avatar
Florian Oetke committed
97
	int Beat_system::beat_index() const { return _beat_index; }
98

Florian Oetke's avatar
Florian Oetke committed
99
} // namespace phase_shifter::gameplay