111 lines
3.2 KiB
Markdown
111 lines
3.2 KiB
Markdown
# Scene System
|
|
|
|
Source: `src/dusk/scene/`
|
|
|
|
## Overview
|
|
|
|
The scene system is the top-level coordinator for a running game state.
|
|
It manages one active scene at a time. Scenes are JS scripts -- each
|
|
scene is a `.js` asset file that exports an object with lifecycle hooks.
|
|
The scene system loads, ticks, and tears down these scripts, while the
|
|
C side runs the ECS and render pipeline on each tick.
|
|
|
|
## Scene lifecycle (C side)
|
|
|
|
```c
|
|
extern scene_t SCENE;
|
|
|
|
errorret_t sceneInit(void); // initialise the scene manager
|
|
errorret_t sceneUpdate(void); // process pending transition, tick active scene
|
|
errorret_t sceneRender(void); // render entities + render pipeline + UI
|
|
errorret_t sceneDispose(void); // dispose the active scene immediately
|
|
```
|
|
|
|
`sceneUpdate` each tick:
|
|
1. Checks for a pending scene transition and performs it (dispose old,
|
|
load and init new).
|
|
2. Calls the JS scene's `update()` hook.
|
|
3. Calls `entityManagerUpdate()` to fire all entity update callbacks.
|
|
|
|
`sceneRender` each tick:
|
|
1. Binds the screen.
|
|
2. Calls `sceneRenderPipeline()` -- renders all entities with a
|
|
`COMPONENT_TYPE_RENDERABLE` in priority order.
|
|
3. Renders UI.
|
|
4. Calls the JS scene's `render()` hook (for any custom drawing).
|
|
5. Unbinds the screen.
|
|
|
|
## Scene lifecycle (JS side)
|
|
|
|
A scene file exports a plain object with these optional hooks:
|
|
|
|
```js
|
|
var scene = {};
|
|
|
|
scene.init = async function() {
|
|
// Load assets, create entities, set up state.
|
|
// May be async -- await asset loads here.
|
|
};
|
|
|
|
scene.update = function() {
|
|
// Called each fixed-timestep tick.
|
|
};
|
|
|
|
scene.render = function() {
|
|
// Called each render tick, after ECS renderables.
|
|
};
|
|
|
|
scene.dispose = function() {
|
|
// Clean up entities and state.
|
|
};
|
|
|
|
module.exports = scene;
|
|
```
|
|
|
|
See `CLAUDE.md` -- "JavaScript (asset scripts)" for JS style rules.
|
|
|
|
## Render pipeline (`scenerenderpipeline.h`)
|
|
|
|
`sceneRenderPipeline(cameraEntityId)` gathers all active
|
|
`COMPONENT_TYPE_RENDERABLE` components, sorts them by effective
|
|
priority, and draws each one using its shader.
|
|
|
|
**Priority rules:**
|
|
- `renderable.priority != 0` -- use that value directly.
|
|
- `renderable.priority == 0` -- auto-derive: opaque geometry sorts
|
|
before transparent geometry; sprite batches sort before shader
|
|
materials; etc.
|
|
- Lower priority number = drawn first (behind); higher = drawn last
|
|
(on top).
|
|
|
|
The shader used for each renderable:
|
|
- `ENTITY_RENDERABLE_TYPE_SPRITEBATCH` and `CUSTOM` default to
|
|
`SHADER_LIST_SHADER_UNLIT`.
|
|
- `ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL` uses the shader indexed by
|
|
`renderable.data.material.shaderType` in `SHADER_LIST_DEFS`.
|
|
|
|
## Transitioning between scenes
|
|
|
|
To move to a new scene from JS, call the scene module's transition
|
|
function (exact API in the `scene` JS module). The C side defers the
|
|
actual switch to the start of the next `sceneUpdate` call so the
|
|
current tick completes cleanly before any dispose runs.
|
|
|
|
## Relationship to the engine loop
|
|
|
|
```
|
|
engineUpdate()
|
|
timeUpdate()
|
|
inputUpdate()
|
|
physicsManagerUpdate()
|
|
scriptUpdate() <- runs JS microjobs
|
|
sceneUpdate() <- JS update + ECS entity updates
|
|
|
|
engineUpdate() -> sceneRender()
|
|
screenBind()
|
|
sceneRenderPipeline() <- ECS renderables sorted by priority
|
|
uiRender()
|
|
sceneRender (JS hook)
|
|
screenUnbind / screenRender
|
|
```
|