ludic/docs/language/phases/phase-update.md

43 lines
1.8 KiB
Markdown

---
id: phase-update
name: Update
category: phases
kind: phase
tokens: Update
sig: phase Update
tip: The ordinary per-frame game-logic step, run after Input and FixedUpdate.
order: 3
---
`Update` is the everyday game-logic phase, run each frame after `Input` and `FixedUpdate` and before `LateUpdate` and `Render`. It is where most gameplay lives when you are not being strict about determinism: spawn waves on a timer, apply the intent that `Input` recorded, check win/lose conditions, advance animations. Reach for `Update` by default and reserve `FixedUpdate` for the simulation you specifically want reproducible. Because it runs after `Input`, the current frame's key press is already reflected in your program `var`s by the time `Update` reads them.
```ludic
program UpdateExample {
property Position { column: int = 0, row: int = 0 }
model Enemy { Position }
const GRID_WIDTH: int = 20
state UpdateExampleState {
elapsed_frames: int = 0
score: int = 0
}
handler SpawnWave(update_example_st: mut UpdateExampleState) phase Update {
update_example_st.elapsed_frames = update_example_st.elapsed_frames + 1
if update_example_st.elapsed_frames % 30 == 0 {
let spawn_column = Random.range(low: 0, high: GRID_WIDTH - 1)
spawn Enemy { Position { column: spawn_column, row: 0 } }
update_example_st.score = update_example_st.score + 1
}
}
handler DrawWorld(update_example_st: UpdateExampleState) phase Render {
Screen.clear(Color.MidnightBlue)
for (current_position) in query [Position, {Enemy}] {
Screen.fill_rectangle(x: current_position.column * 16, y: current_position.row * 16, width: 16, height: 16, color: Color.Crimson)
}
Screen.draw_number(x: 4, y: 4, value: update_example_st.score, color: Color.Gold, scale: 1)
Screen.show()
}
}
```