DragonBreathDirector
DragonBreathDirector sits on the entity that runs the dragon-breath Generator and keeps three things in step with that generator's clock: the `sync_time` property of a material, a set of flickering point lights that ride along the fire jet, and playback of the generator itself. T…
DragonBreathDirector
DragonBreathDirector sits on the entity that runs the dragon-breath Generator and keeps three things in
step with that generator's clock: the sync_time property of a material, a set of flickering point
lights that ride along the fire jet, and playback of the generator itself. The fire, the light it
throws and the scorch it leaves on the ground all read the same clock, so they agree.
The fx_breath scene uses it on the dragon_breath entity, next to that entity's Generator, with
material set to courtyard_flagstone (a material on the flagstone_scorch shader), mouth at
{ x = 170, y = 2.4, z = 141 } and frameCamera off. The jet sweeps as
yaw(t) = amplitude * sin(2 * pi * t / period), measured from world +Z toward +X; the source states
that these sweep constants must match proc/dragon_breath.procGraph and flagstone_scorch.shader.
It needs a Generator component on its own entity. It runs at executionOrder = 50.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
material | assetRef (material) | nil | Material whose sync_time follows the breath's clock. |
mouth | vec3 | { x = 0, y = 2.4, z = -9 } | World position of the dragon's mouth, metres. |
amplitude | number | 0.72 | Half-width of the sweep, radians. |
period | number | 14.0 | Seconds for one full left-right-left sweep. |
lightCount | number | 4 | Firelight point lights riding the jet. |
frameCamera | bool | true | Open the player's orbit camera on the wide hero shot. |
cameraDistance | number | 18 | Orbit distance of the opening shot, metres behind the avatar. |
cameraHeight | number | 6 | Height of the opening shot above the avatar's feet, metres. |
cameraAim | number | 2 | Height above the avatar's feet the opening shot looks at, metres. |
All fields are NoSync.
Lifecycle
awake(): binds the Generator on its entity and thematerialasset, then builds the lights. It despawns every entity matchingdragon_firelight_*and spawnslightCounttemporary entities nameddragon_firelight_1,dragon_firelight_2and so on, each with a pointLight(colour{ 1.0, 0.42, 0.1 }, intensity 0, range 14, shadows off).start(): callsplay()on the Generator.update(dt): runs the per-frame drive described below.editorUpdate(dt): runs the same drive whileengine.pausedis true.onDestroy(): despawns the lights it spawned.
Each drive step:
- When
frameCamerais on, every 0.5 seconds it looks for entities namedCameraRigthat carry acontroller.orbital_followcomponent and, once per rig, setsmaxRadiusScale = 6,ringCenter = { height = cameraHeight, radius = 4.5 },radiusScale = cameraDistance / 4.5andaimHeight = cameraAim. Each rig is framed once, so the player's own scroll and orbit stay in the player's hands afterwards. - It rebinds the Generator if it has none yet, and rebuilds the lights if the first one is gone.
- It reads the generator's time
twithgetTime()and sets the material'ssync_timetot % period, the phase of the periodic sweep. - It computes the sweep yaw and places light
iofnalong the jet, at1.5 + 13 * (i / n)from the mouth and1.5 * (i / n)below it (held at a height of at least 0.9). Each light's intensity is(60 - 34 * (i / n))scaled by its own sum-of-sines flicker, and its radius is12 + 10 * (i / n).
Scoped to this part · feeds back into the world's score.