-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsimulation_loop
128 lines (99 loc) · 4.73 KB
/
simulation_loop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
Copyright (C) 2018-2024 Geoffrey Daniels. https://gpdaniels.com/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef GTL_ALGORITHM_SIMULATION_LOOP_HPP
#define GTL_ALGORITHM_SIMULATION_LOOP_HPP
// Summary: Fixed time step helper class for creating game loops.
#if defined(_MSC_VER)
# pragma warning(push, 0)
#endif
#include <chrono>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
namespace gtl {
/// @brief A simulation loop template that operates at a given tick rate.
/// @tparam tick_rate The simulation loop uses a fixed tick rate per second.
template <unsigned long long int tick_rate = 100>
class simulation_loop final {
private:
static_assert(tick_rate > 0, "The simuation loop must tick at least once per second.");
private:
/// @brief The duration that must pass between each tick.
constexpr static const std::chrono::nanoseconds tick_step = std::chrono::nanoseconds(1000000000ull / tick_rate);
/// @brief The current system time.
std::chrono::steady_clock::time_point current_time;
/// @brief The last tick time.
std::chrono::steady_clock::time_point last_tick_time;
/// @brief The current tick.
unsigned long long int current_tick;
/// @brief The leftover or remainder time that has not been consumed by a tick yet.
std::chrono::nanoseconds lag_duration;
public:
/// @brief Default constructor initialises internal state.
simulation_loop()
: current_time(std::chrono::steady_clock::now())
, last_tick_time(current_time)
, current_tick{0}
, lag_duration{0} {
}
/// @brief Update returns true if the simulation should be updated.
/// @return True if the tick time step has passed and the current tick has been incremented, false otherwise.
bool update() {
// Get the current time.
this->current_time = std::chrono::steady_clock::now();
// Add the elapsed duration since the last update to the lag duration.
this->lag_duration = std::chrono::nanoseconds(this->current_time - this->last_tick_time);
// While the current state is lagging perform an update.
if (this->lag_duration >= simulation_loop::tick_step) {
// Advance the last tick time by the tick time step.
this->last_tick_time += simulation_loop::tick_step;
// Reduce the lag by the tick time step.
this->lag_duration -= simulation_loop::tick_step;
// Increment the current tick.
++this->current_tick;
// Return true if a the fixed tick time step has passed and the simulation update should occur.
return true;
}
// Return false if the simulation should not be updated.
return false;
}
/// @brief Get the tick rate of the class.
/// @return The tick rate.
constexpr static unsigned long long int get_tick_rate() {
return tick_rate;
}
/// @brief Get the duration of a tick.
/// @return The tick step.
constexpr static std::chrono::nanoseconds get_tick_step() {
return simulation_loop::tick_step;
}
/// @brief Get the current tick number.
/// @return An unsigned integer representing the current tick counting up from zero.
unsigned long long int get_current_tick() const {
return this->current_tick;
}
/// @brief Get the current amount of remainder time between ticks.
/// @return The number of nanoseconds not consumed by a tick yet.
std::chrono::nanoseconds get_lag_duration() const {
return this->lag_duration;
}
/// @brief Get a floating representation of the amount a tick has been filled.
/// @return A value between 0.0 (inclusive) and 1.0 (exclusive) representing the progress to the next tick.
template <typename type>
type get_alpha() const {
return type(this->lag_duration.count()) / type(simulation_loop::tick_step.count());
}
};
}
#endif // GTL_ALGORITHM_SIMULATION_LOOP_HPP