Phase 11 — Day/night cycle + Lighting (taken before Phase 9 per recommendation)
Three gdscript-refactor agents in parallel; Opus integrated and verified
the day-night transition + torch lighting via MCP runtime + screenshot.
Clock autoload (Agent A, autoload/clock.gd, ~138 lines):
- TICKS_PER_DAY = 4800 → 4 min/day at 1× / 48 s at Fast / 20 s at Ultra
- TICKS_PER_HOUR = 200 (so 60 min × ~3 ticks per minute)
- 4-phase day: night → dawn (5–7) → day (7–19) → dusk (19–22) → night
- darkness_factor() returns 0..1 with linear ramps across dawn/dusk
- phase_changed signal fires on phase transitions
- save_dict / apply_dict for save round-trip
- Boots at Day 1, 06:00 (mid-dawn for atmospheric start)
- Registered in project.godot autoload list (Opus)
Top-bar clock UI (Agent A):
- ClockLabel added to top_bar.tscn (center-anchored at ±80 px)
- _on_clock_refresh in top_bar.gd; early-out string compare to skip text
assignments when unchanged (cheap per-tick)
Torch entity + lights registry (Agent B, scenes/entities/torch.{gd,tscn} +
workbench.gd + world.gd, ~210 lines):
- class Torch: buildable furniture, BUILD_TICKS=30, LIGHT_RADIUS=6
- Procedural radial gradient texture (64×64) generated at runtime with
smoothstep falloff → no PNG dependency
- PointLight2D child with the gradient texture, warm fire tint, energy 1.2
- is_on / get_light_tile / get_light_radius duck-typed interface; same
shape exposed by Workbench when label_text='Hearth' (HEARTH_LIGHT_RADIUS=5)
- World.light_sources registry + register/unregister + is_tile_lit(tile)
(Manhattan distance, no occlusion — Phase 13 may add wall-occlusion)
CanvasModulate darkness + in_darkness thought (Agent C, ~30 lines mod +
new factory):
- DarkOverlay CanvasModulate node added to world.tscn (first child of
World root so it tints all sibling layers + entities)
- world.gd._update_dark_overlay lerps DAY_TINT (white) ↔ NIGHT_TINT
(0.20, 0.22, 0.40 deep cool blue) by Clock.darkness_factor() each tick
- ThoughtCatalog.in_darkness(): persistent, -3 mood, fires when
darkness > 0.3 AND World.is_tile_lit(pawn.tile) is false
- Pawn._process_thoughts syncs in_darkness alongside hungry/tired
Opus integration:
- project.godot: Clock autoload registered
- world.tscn: DarkOverlay CanvasModulate node, plus the agent additions
- Demo seed: 2 torches inside cabin at (46, 26) + (49, 26), pre-built
- MCP-driven runtime test verified day→night transition + lighting
effects:
- Noon: world bright green, torches barely visible (over-bright at noon
is minor polish — Phase 17 may scale torch energy by darkness)
- Midnight: world deep blue/green tinted, torches cast yellow halos,
Hearth ember glows orange, cabin interior warmly lit, exterior dark
- top_bar clock label updates each sim tick (early-out on no-change)
Phase 11 followups for later phases:
- Torch energy should scale with darkness — visible halos at noon are
silly. Phase 17 will likely tie PointLight2D.energy to clamp(darkness,
0.2, 1.0) so they're invisible at midday
- Wall-occlusion for light_map — Phase 13's room-detection BFS could
treat completed wall tiles as occluders so light doesn't bleed through
- 'In darkness' thought currently treats ALL unlit cells as darkness;
Phase 13's roof flag could differentiate 'indoors-dark' (different
thought) from 'outdoors-dark'
- Light source visibility through CanvasModulate works correctly thanks
to PointLight2D's additive blend mode
Acceptance — MCP-verified via play_scene + get_game_screenshot:
- ✅ Day → Dusk → Night cycle visible (Clock.current_phase emits events)
- ✅ CanvasModulate tints world deep blue at night
- ✅ Torches cast visible yellow halos via PointLight2D additive blend
- ✅ Hearth opts-in as a light source via label_text='Hearth' check
- ✅ Top-bar clock shows 'Day N, HH:MM' format and updates each tick
- ✅ in_darkness thought wires through _process_thoughts (would fire if
a pawn were standing in an unlit night tile — demo didn't capture this
specifically but the code path is verified)
Delegation report this phase:
- Agent A: Clock autoload + 4-phase day cycle + top-bar UI extension
- Agent B: Torch entity + PointLight2D + procedural radial texture +
Workbench Hearth opt-in + World.light_sources registry
- Agent C: CanvasModulate world.tscn node + day/night colour lerp +
in_darkness ThoughtCatalog entry + Pawn persistent thought sync
- Opus: Clock autoload registration in project.godot + 2 torches in
demo seed + MCP runtime verification at midnight vs noon
~75% of Phase 11 GDScript was subagent-authored.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
43e52ffe75
commit
a1e5b38dd6
16 changed files with 606 additions and 10 deletions
|
|
@ -29,6 +29,7 @@ const WORKBENCH_SCENE: PackedScene = preload("res://scenes/entities/workbench.ts
|
|||
const CROP_SCENE: PackedScene = preload("res://scenes/entities/crop.tscn")
|
||||
const ITEM_SCENE: PackedScene = preload("res://scenes/entities/item.tscn")
|
||||
const BED_SCENE: PackedScene = preload("res://scenes/entities/bed.tscn")
|
||||
const TORCH_SCENE: PackedScene = preload("res://scenes/entities/torch.tscn")
|
||||
|
||||
# 3 starting pawns — Phase 2 demo. Phase 7+ replaces this with map-gen + name table.
|
||||
const SAMPLE_PAWNS: Array[Dictionary] = [
|
||||
|
|
@ -51,6 +52,12 @@ const SAMPLE_ROCKS: Array[Vector2i] = [
|
|||
# HaulingProvider re-flow cadence — every 5 sim seconds at 1× (100 ticks).
|
||||
const HAUL_SWEEP_INTERVAL_TICKS: int = 100
|
||||
|
||||
# Phase 11 — global darkness tint. Day = white, night = deep cool blue.
|
||||
# Driven by Clock.darkness_factor() (0..1) each sim tick.
|
||||
const NIGHT_TINT: Color = Color(0.20, 0.22, 0.40, 1.0)
|
||||
const DAY_TINT: Color = Color(1.0, 1.0, 1.0, 1.0)
|
||||
|
||||
@onready var dark_overlay: CanvasModulate = $DarkOverlay
|
||||
@onready var terrain_layer: TileMapLayer = $Terrain
|
||||
@onready var floor_layer: TileMapLayer = $Floor
|
||||
@onready var wall_layer: TileMapLayer = $Wall
|
||||
|
|
@ -395,6 +402,19 @@ func _seed_phase5_demo_buildings() -> void:
|
|||
bed.on_build_tick()
|
||||
Audit.log("world", "phase 8 demo: %d beds pre-built inside cabin" % bed_tiles.size())
|
||||
|
||||
# Phase 11 demo — 2 torches inside cabin (north-east + south-west corners
|
||||
# of interior) so the indoor area stays lit at night. Combined with the
|
||||
# Hearth's light radius=5, the cabin interior should be mostly bright
|
||||
# while the outdoors goes deep-blue tinted.
|
||||
var torch_tiles: Array[Vector2i] = [Vector2i(46, 26), Vector2i(49, 26)]
|
||||
for tt in torch_tiles:
|
||||
var torch: Torch = TORCH_SCENE.instantiate()
|
||||
add_child(torch)
|
||||
torch.setup(tt)
|
||||
while torch.is_buildable():
|
||||
torch.on_build_tick()
|
||||
Audit.log("world", "phase 11 demo: %d torches pre-built inside cabin" % torch_tiles.size())
|
||||
|
||||
|
||||
func _spawn_sample_stockpiles() -> void:
|
||||
# Two zones for the Phase 4 acceptance demo:
|
||||
|
|
@ -463,11 +483,20 @@ func _on_designation_cleared(cell: Vector2i) -> void:
|
|||
# ── periodic re-flow (the "wood floats up" cascade) ─────────────────────────
|
||||
|
||||
func _on_sim_tick_world_sweep(tick_n: int) -> void:
|
||||
_update_dark_overlay()
|
||||
if tick_n % HAUL_SWEEP_INTERVAL_TICKS != 0:
|
||||
return
|
||||
hauling_provider.sweep_for_better_destinations()
|
||||
|
||||
|
||||
# Phase 11 — interpolate CanvasModulate between DAY_TINT and NIGHT_TINT based
|
||||
# on Clock.darkness_factor() (0 = full day, 1 = full night).
|
||||
# Called every sim tick; Color.lerp is a handful of float ops — negligible cost.
|
||||
func _update_dark_overlay() -> void:
|
||||
var f := Clock.darkness_factor()
|
||||
dark_overlay.color = DAY_TINT.lerp(NIGHT_TINT, f)
|
||||
|
||||
|
||||
# ── spike: AStarGrid2D query timing at 80² ──────────────────────────────────
|
||||
|
||||
func _run_pathfinder_spike() -> void:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue