50 lines
3.2 KiB
Markdown
50 lines
3.2 KiB
Markdown
# Fixed-camera games and runtime presentation
|
||
|
||
Forma supports fixed orthographic scenes that combine 3D geometry and transparent GLB sprite planes. This is optional: projects without these settings retain the existing camera, controls, and player UI.
|
||
|
||
## Camera and rendering
|
||
|
||
An entity can have `camera: { mode: "fixed", lookAt: [0, 0, 0], projection: "orthographic", orthoWidth: 24, aspect: 16 / 9 }`. The camera uses the entity's world position, faces `lookAt`, and preserves the specified aspect ratio with letterboxing. Omit `aspect` to fill the current viewport. The inspector exposes fixed mode, projection, width and look-at position. Perspective and follow/first-person cameras remain supported.
|
||
|
||
`settings.rendering` accepts `toneMapping`, `exposure`, `contrast` and `defaultLights`. Set `defaultLights: false` to use only authored lights, for example in an imported Blender scene. Disabling tone mapping is useful for artwork that already contains lighting. Generated mesh materials accept `unlit`, `alpha` (0–1) and `doubleSided`; scripts can update them through `api.patch`. Imported GLB materials retain their authoring settings unless a material override is requested.
|
||
|
||
## Controls
|
||
|
||
`settings.controls` optionally maps `attack`, `jump`, `dash`, `sprint` and `reset` to arrays of browser `KeyboardEvent.code` values. Empty arrays disable a keyboard action. Mouse attack and pointer aiming retain the existing runtime input API. Movement remains WASD/arrows; a project's script may transform those axes into its camera basis. Dash/jump/reset also have one-frame pressed events.
|
||
|
||
## Presentation
|
||
|
||
Optional `settings.presentation` enables the same lightweight overlay in the editor and exported standalone player:
|
||
|
||
```json
|
||
{
|
||
"title": "Example game",
|
||
"accent": "#d74732",
|
||
"instructions": "WASD — move · J — attack · Space — dash",
|
||
"start": { "title": "Example game", "body": "Reach the exit." }
|
||
}
|
||
```
|
||
|
||
The start screen pauses simulation until the player continues. The overlay supplies pause/resume, fullscreen, sound, touch movement/attack/dash and keyboard restart. On restart it emits `resetPressed`; the project script owns resetting its gameplay state. Stop in the editor restores the original scene document.
|
||
|
||
Scripts can emit these presentation events:
|
||
|
||
```js
|
||
api.emit("hud", {
|
||
objective: "Wave 1 / 3",
|
||
counters: ["Enemies: 4", "Defeated: 0"],
|
||
meters: [
|
||
{ id: "life", label: "Health", value: 4, max: 5, style: "hearts" },
|
||
{ id: "dash", label: "Dash", value: 0.7, max: 1, style: "bar" }
|
||
]
|
||
});
|
||
api.emit("hud", { overlay: { title: "Victory", body: "You reached the exit.", button: "Play again" } });
|
||
api.emit("hud", { overlay: null }); // Clear an outcome overlay when resetting.
|
||
api.emit("feedback", {}); // Brief damage vignette.
|
||
api.emit("sound", { frequency: 520, endFrequency: 90, duration: 0.1, type: "triangle", gain: 0.025 });
|
||
```
|
||
|
||
Outcome overlays pause simulation. HUD text is assigned as text content, meter values and list lengths are bounded. Audio starts after a user gesture and can be muted. Runtime callbacks continue receiving these events, including during headless tests.
|
||
|
||
The concrete arena, artwork, combat, enemy AI and wave progression live in `projects/InfernalCourtyard`, not in the engine or default project templates.
|