Add a GameClock autoload with pausable, speed-scaled ticks #65
Labels
No labels
assets
bug
duplicate
enhancement
help wanted
invalid
question
testing
ui
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
liamjd/UntitledColonyBuilder#65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of milestone #5. Nothing in the game ticks yet, so task work and idle-pawn polling have nothing to run on, and
BuildingType.build_timeis an int with no unit.Add a
GameClockautoload that emits aticksignal at a configurable simulation rate, independent of frame rate.AC:
tick(tick_number: int)signal emitted at a configurable ticks-per-second rate, accumulated from_processdelta so it is frame-rate independentpausedproperty stops ticks;speedmultiplier (1x, 2x, 3x) scales the ratenow(current tick count) readable; monotonic; starts at 0 on a new runGameState.main_menu_changed)build_timeas ticksNot in scope: a calendar/day cycle. The threat forecast timeline will want one later and can derive it from ticks.
Two things the spec deliberately doesn't decide
Re-entrancy. tick.emit() inside the loop hands control to arbitrary listeners mid-drain, and one of them may set paused = true (a task completes, triggering a game-over dialog). Your options are to let the loop finish the drain, or to make the condition while not paused and _accumulator >= 1.0. The second is more consistent with the accumulator rule you chose — the undelivered ticks stay banked and fire on resume. No test pins it yet; if you pick one, it wants a test.
Float drift. This is the one that may bite you. test_the_tick_count_does_not_depend_on_frame_rate advances 2.0 seconds in 300 steps, which lands exactly on a tick boundary after 300 roundings — the worst case for accumulated error. If it comes out 19 instead of 20, don't reach for an epsilon in the comparison; that hides genuine drift. Nudge the test off the boundary instead (2.05 seconds, asserting 20). I set that boundary up when writing the spec and it's the one number in the file I'd expect to move.
Two of this issue's AC items turned out to belong to the calendar rather than the clock, and have moved to #87:
build_timeas ticks" — #66 had already answered this without naming it.Task.work(ctx, ticks)decrementswork_remaining, so build effort is pawn-ticks (labour), not elapsed time. That makes it a data-model change acrossBuildingTypeand three.tresfiles, now #88.nowstarts at 0 on a new run" —GameClockis an autoload that outlives a run and nothing resets_now, so a second contract currently starts on day 400. Thereset()is tracked in #87 alongside the other run-start state.Also deferred to #87: making
ticks_per_secondaconst. It is a mutablevartoday, and a mid-run change silently invalidates every computed forecast and desyncs a replay.What #65 still owes: the re-entrancy decision (a listener that sets
pausedmid-drain should stop the drain —while not paused and _accumulator >= 1.0), which has a failing test against it intest/unit/test_game_clock.gd.