Skip to content

Calendar Time v2.1.0

Ageing — Two Time Models

Calendar Time supports two distinct ageing mechanics. Pick the one that matches your game design.

Status
Current
Version
v2.1.0
Source updated
2026-08-09
Generated on
2026-09-06

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_seconds

AddAfterGameSeconds 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.