I asked this question already in Unreal slackers, but I hope to get some more insights and maybe also provide a “cite” for people facing a similar problem.
I would implement it similar to this in simplified/plain c++:
void GameLoop() {
// Initialize
Date currentDate = Date(2025-01-01);
TimeKeeper timeKeeper;
bool isPaused = false;
while (!shouldQuit) {
auto tickStartTime = Clock::now();
// Get current speed setting
auto currentSpeed = timeKeeper.GetSpeedAsMs();
// Update simulation if not paused
// should prob be done as tasks, since we have also different "ticks",
// like tick, daily (4 default ticks), weekly,monthly etc
if (!isPaused) {
currentDate.AdvanceTimeByOneTick();
doWork(); // had async here before, but thats not entirly correct.
}
// Time management - regulate tick rate based on speed setting
if (currentSpeed > 0) { // Skip timing for max speed
auto processingTime = Clock::now() - tickStartTime;
// Sleep for remaining time to maintain consistent speed
if (processingTime < currentSpeed) {
std::this_thread::sleep_for(currentSpeed - processingTime);
}
}
}
}
I had in the initial question doAsyncWork, that’s not right, the tick should not proceed until all work for that tick is done.
The Background is a simulation heavy game. For example something like Crusader Kings, Victoria 3 etc, where Demographic groups, economy etc are simulated. Time processes not entirely in realtime.
You have ticks as a time unit — then for example 4 ticks are a day, 3×7 a Week etc.
Some things need to be recalculated every tick, other stuff only on a weekly, monthly … basis.
The Game has different Speeds, let’s call them 1, …, 5 where 5 is the fastest and runs as fast as it can process and for example 3 is default and takes 1sec per tick. If the simulation part takes longer as the defined value, then the next one starts immediately after, if its faster — then we wait until the time is up.
The recommendations were:
- Actor component as time manager on game state or world subsystem and letting tick update the state. With a delegate to handle ingame game time for others.
- A World Subsystem as the time manager, with the Tick function updating the in-game time state based on real time and a time factor. It also broadcasts events (via delegates) when the day changes so other systems can respond to in-game time changes.