Calendar Time supports two distinct ageing mechanics. Pick the one that matches your game design.
Model 1: Clock-time ageing (continuous)
"This effect lasts N game-seconds."
AgeService tracks elapsed game time from GameClock.game_seconds_advanced.
Ageing scales with clock speed — if you speed up the clock, ageing speeds up
proportionally.
Use for:
- Potion expiry ("expires in 5 game-minutes")
- Buff/debuff durations
- Cooldown timers
- Real-time effects that should pause when the clock pauses
var age_service:= AgeService.new()
age_service.clock= clock
var component:= AgeComponent.new()
component.total_game_seconds= 300.0 # 5 game-minutes
age_service.register(component)
# Later: how much time has elapsed?
var elapsed:= component.elapsed_game_seconds
var remaining:= component.remaining_game_secondsAddAfterGameSeconds is a convenience node: it adds a child node after
N game-seconds have elapsed on the bound clock.
Model 2: Calendar-date ageing (discrete)
"This crop takes 3 game-days to mature."
Listen to clock.signal_bus.date_changed and advance growth stages
discretely. Each calendar day triggers exactly one growth tick, regardless
of clock speed. Speeding up the clock makes days pass faster, but each
day still advances one stage.
This is the farming-game model (Stardew Valley, Rune Factory, Harvest Moon).
Use for:
- Crop growth ("3 days to harvest")
- Building construction ("7 days to complete")
- Character aging ("1 year per game-year")
- Seasonal changes
func _ready()-> void:
clock.signal_bus.date_changed.connect(_on_date_changed)
var growth_stage:int = 0
const MAX_STAGE:int = 3
func _on_date_changed(current:DateTime, _previous:DateTime)-> void:
if growth_stage< MAX_STAGE:
growth_stage+= 1
_update_sprite(growth_stage)DateChangeEvent, DateChangeSpawner, DateChangeRandomizer, and
DateChangeRandomToggler are ready-made nodes for common date-triggered
behaviors.
Choosing between the models
| Question | Model |
|---|---|
| Should it pause when the clock pauses? | Both do |
| Should it scale smoothly with clock speed? | Model 1 (clock-time) |
| Should it advance in discrete day/month/year steps? | Model 2 (calendar-date) |
| Is it a duration ("lasts N seconds")? | Model 1 |
| Is it a progression ("takes N days")? | Model 2 |
| Farming, construction, seasons? | Model 2 |
| Cooldowns, expiry, buffs? | Model 1 |
Combining both models
Both models read from the same GameClock.
Pausing the clock pauses both.
Saving and loading preserves both.
both (Model 1 via AgeComponent serialization, Model 2 via the calendar
date in TimeSnapshot).
AgeService internals
AgeService is a per-clock Resource (not a singleton). Each clock can
have its own AgeService with independent components. The service
subscribes to game_seconds_advanced and updates all registered
AgeComponent instances.
AgeStateRegistry tracks visual states per clock. AgeState defines
what a component looks like at each threshold (sprite frame, material,
scale). AgePreset bundles named presets for quick authoring.
AgeSceneReplacement swaps a node's scene at an age threshold — useful
for "sapling → tree" or "ruins → rebuilt house" transitions.