incanto 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/2d.d.ts +51 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +9 -3
- package/dist/3d.js +4 -4
- package/dist/{behavior-uPEuZrUB.d.ts → behavior-Do0Da56m.d.ts} +98 -0
- package/dist/{create-game-B_e9hJf7.js → create-game-9D87XaiX.js} +26 -11
- package/dist/{create-game-CGnoypjL.js → create-game-CDJ1lVqK.js} +21 -13
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-B-OtSRFL.js → duplicate-MNLMAcbz.js} +1 -1
- package/dist/editor.js +14 -0
- package/dist/{environment-presets-DSZwsKPs.js → environment-presets-SkGanr2s.js} +2 -2
- package/dist/{gameplay-B6jqvYeM.js → gameplay-CRYw_Q-T.js} +2 -2
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +177 -5
- package/dist/index.js +8 -8
- package/dist/{loader-B-Gft32x.js → loader-BTkHYrQn.js} +54 -18
- package/dist/{loader-B9iTqs27.d.ts → loader-Cu_7kJDy.d.ts} +1 -1
- package/dist/{log-report-lxrQY9cH.js → log-report-CPFm4OXf.js} +0 -0
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{pathfinding-CAR9DjQQ.d.ts → pathfinding-HNGFqGUZ.d.ts} +24 -1
- package/dist/{physics-2d-Dns-oZlE.js → physics-2d-BhZZ-HAp.js} +2 -2
- package/dist/{physics-3d-BhI0ehpe.js → physics-3d-DmyO2oaN.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-DVwlnZAZ.js → register-BTomIiYG.js} +304 -24
- package/dist/{register-Trx7WHnD.js → register-DROK2l7J.js} +2 -2
- package/dist/{replay-BU1CCM15.d.ts → replay-9Fy6C10F.d.ts} +1 -1
- package/dist/{replay-BicPOMX0.js → replay-DYNUL4BU.js} +2 -2
- package/dist/{split-screen-CZ9ccBBQ.js → split-screen-CaF9hO7g.js} +2 -2
- package/dist/{split-screen-paxkQs_q.d.ts → split-screen-DNmcX1Pz.d.ts} +1 -1
- package/dist/{src-5gbZO47I.js → src-C9xyZW7M.js} +1 -1
- package/dist/{teardown-ks3d5W9n.js → teardown-Bw2aeyGI.js} +30 -1
- package/dist/{test-DAojuFdb.js → test-CJRsciFk.js} +11 -11
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/{touch-BoNg_MnF.js → touch-BnMyy9tr.js} +4 -4
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-CCvckvbw.js → agent8-PlFHzJsh.js} +1 -1
- package/editor/assets/{debug-CLNCOnbc.js → debug-CebV7CDW.js} +1 -1
- package/editor/assets/{index-Cb5Brupb.js → index-CdbsY31G.js} +91 -91
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +213 -0
- package/skills/incanto-audio.md +97 -10
- package/skills/incanto-building-2d-games.md +20 -3
- package/skills/incanto-hud.md +7 -0
- package/skills/incanto-node-reference.md +34 -0
- package/skills/incanto-physics-and-input.md +38 -0
- package/skills/incanto-verifying-your-game.md +19 -1
- package/skills/incanto-web-integration.md +1 -0
- package/templates-app/beacon-isle-3d/index.html +3 -3
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/index.html +3 -3
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/index.html +3 -3
- package/templates-app/village-quest-3d/package.json +1 -1
package/dist/2d.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-Do0Da56m.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-Cu_7kJDy.js";
|
|
5
5
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
6
6
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
7
7
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
@@ -304,7 +304,21 @@ interface CreateGame2DOptions {
|
|
|
304
304
|
* false disables. They overlay `touchContainer` (default: the canvas's
|
|
305
305
|
* parent element — give it position: relative).
|
|
306
306
|
*/
|
|
307
|
+
/**
|
|
308
|
+
* Attach pointer input (mouse, finger or pen) to the canvas: positions for
|
|
309
|
+
* `input.pointerPosition()`, buttons for `input.mousePressed()`.
|
|
310
|
+
* `{ lockOnClick: true }` captures the cursor — rare in 2D, so it is off.
|
|
311
|
+
*/
|
|
312
|
+
pointer?: boolean | {
|
|
313
|
+
lockOnClick?: boolean;
|
|
314
|
+
};
|
|
307
315
|
touch?: "auto" | boolean;
|
|
316
|
+
/**
|
|
317
|
+
* Leave the browser's touch gestures (scroll/zoom/pull-to-refresh) on the
|
|
318
|
+
* canvas. Default false: the GAME owns them, or a drag on a phone scrolls
|
|
319
|
+
* the page instead of playing.
|
|
320
|
+
*/
|
|
321
|
+
pageGestures?: boolean;
|
|
308
322
|
touchContainer?: HTMLElement;
|
|
309
323
|
/** @internal Test seam — replaces `document` for the touch overlay. */
|
|
310
324
|
_touchDoc?: {
|
|
@@ -344,10 +358,32 @@ interface CreateGame2DOptions {
|
|
|
344
358
|
_scheduler?: Scheduler;
|
|
345
359
|
}
|
|
346
360
|
/** What createGame needs from a renderer (stats is optional for test stubs). */
|
|
361
|
+
/** What a renderer must do for the engine. The test seam supplies this much. */
|
|
347
362
|
interface GameRenderer {
|
|
348
363
|
dispose(): void;
|
|
349
364
|
stats?(): RendererStats;
|
|
350
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* What a GAME can ask its renderer for.
|
|
368
|
+
*
|
|
369
|
+
* The two coordinate conversions live here rather than only on `Renderer2D`,
|
|
370
|
+
* because `game.renderer` is what a consumer holds: a tap needs screen→world
|
|
371
|
+
* and a pinned DOM element needs world→screen, both are documented in the
|
|
372
|
+
* skills, and neither typechecked through the narrow interface. Found by
|
|
373
|
+
* following my own documentation in a fresh project.
|
|
374
|
+
*/
|
|
375
|
+
interface Game2DRenderer extends GameRenderer {
|
|
376
|
+
/** Canvas px → world px, through the design viewport and the camera. */
|
|
377
|
+
worldFromScreen(sx: number, sy: number): {
|
|
378
|
+
x: number;
|
|
379
|
+
y: number;
|
|
380
|
+
};
|
|
381
|
+
/** World px → canvas px (pin DOM to a node). */
|
|
382
|
+
screenFromWorld(wx: number, wy: number): {
|
|
383
|
+
x: number;
|
|
384
|
+
y: number;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
351
387
|
interface Game2D {
|
|
352
388
|
engine: Engine;
|
|
353
389
|
scene: Scene$1;
|
|
@@ -356,13 +392,25 @@ interface Game2D {
|
|
|
356
392
|
* A running tree has moved; the editor gets what was written down.
|
|
357
393
|
*/
|
|
358
394
|
sourceJson: SceneJson;
|
|
359
|
-
renderer:
|
|
395
|
+
renderer: Game2DRenderer;
|
|
360
396
|
physics: Physics2D | null;
|
|
361
397
|
/**
|
|
362
398
|
* The node under a screen pixel, or null. The raycast the renderer already
|
|
363
399
|
* does — reachable now without holding the renderer.
|
|
364
400
|
*/
|
|
365
401
|
pick(x: number, y: number): Node | null;
|
|
402
|
+
/**
|
|
403
|
+
* Assets that did not arrive — a texture that 404'd, a sound that cannot be
|
|
404
|
+
* played — with the ref and the reason.
|
|
405
|
+
*
|
|
406
|
+
* The verify loop names this as one of its four signals, and 2D never had it:
|
|
407
|
+
* a 2D game could not ask the question at all.
|
|
408
|
+
*/
|
|
409
|
+
assetErrors(): Array<{
|
|
410
|
+
ref: string;
|
|
411
|
+
url: string;
|
|
412
|
+
error: string;
|
|
413
|
+
}>;
|
|
366
414
|
/** Engine + renderer perf counters in one read (fps/nodes/triangles/…). */
|
|
367
415
|
stats(): GameStats;
|
|
368
416
|
/**
|
package/dist/2d.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
3
|
-
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-
|
|
4
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
2
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-9D87XaiX.js";
|
|
3
|
+
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-DROK2l7J.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BhZZ-HAp.js";
|
|
5
5
|
//#region src/2d/library-sprite.ts
|
|
6
6
|
/**
|
|
7
7
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { D as QualityCaps, Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { D as QualityCaps, Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-Do0Da56m.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson$1, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-Cu_7kJDy.js";
|
|
5
5
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
6
6
|
import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DZ70IY26.js";
|
|
7
|
-
import { n as PathGrid, s as SpatialPose } from "./pathfinding-
|
|
7
|
+
import { n as PathGrid, s as SpatialPose } from "./pathfinding-HNGFqGUZ.js";
|
|
8
8
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
9
9
|
import { VRM } from "@pixiv/three-vrm";
|
|
10
10
|
import { Sky } from "three/examples/jsm/objects/Sky.js";
|
|
@@ -563,6 +563,12 @@ interface CreateGame3DOptions {
|
|
|
563
563
|
* parent element — give it position: relative).
|
|
564
564
|
*/
|
|
565
565
|
touch?: "auto" | boolean;
|
|
566
|
+
/**
|
|
567
|
+
* Leave the browser's touch gestures (scroll/zoom/pull-to-refresh) on the
|
|
568
|
+
* canvas. Default false: the GAME owns them, or a drag on a phone scrolls
|
|
569
|
+
* the page instead of playing.
|
|
570
|
+
*/
|
|
571
|
+
pageGestures?: boolean;
|
|
566
572
|
touchContainer?: HTMLElement;
|
|
567
573
|
/** @internal Test seam — replaces `document` for the touch overlay. */
|
|
568
574
|
_touchDoc?: {
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-
|
|
2
|
-
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-
|
|
3
|
-
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-
|
|
1
|
+
import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-CRYw_Q-T.js";
|
|
2
|
+
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-SkGanr2s.js";
|
|
3
|
+
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-CDJ1lVqK.js";
|
|
4
4
|
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-njybhZon.js";
|
|
5
5
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
6
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
6
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DmyO2oaN.js";
|
|
7
7
|
//#region src/3d/model-verdict.ts
|
|
8
8
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
9
9
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -325,9 +325,42 @@ type BusName = "sfx" | "music";
|
|
|
325
325
|
* engine.audio.muted = true; // mute toggle
|
|
326
326
|
* ```
|
|
327
327
|
*/
|
|
328
|
+
/** One thing that sounded (or would have, headless). */
|
|
329
|
+
interface AudioEvent {
|
|
330
|
+
/** `preset` (procedural one-shot), `src` (a clip), `music`, or `voice`. */
|
|
331
|
+
kind: "preset" | "src" | "music" | "voice";
|
|
332
|
+
/** The preset name, the clip url, or the voice preset. */
|
|
333
|
+
name: string;
|
|
334
|
+
/** Node path for a node-driven sound; `engine.music` / `engine.sfx` otherwise. */
|
|
335
|
+
from: string;
|
|
336
|
+
bus: BusName;
|
|
337
|
+
/** `engine.time` when it fired, in seconds. */
|
|
338
|
+
at: number;
|
|
339
|
+
}
|
|
328
340
|
declare class AudioBuses {
|
|
329
341
|
/** Fires whenever any value changes (drives live re-gain of playing sounds). */
|
|
330
342
|
readonly changed: Signal<[]>;
|
|
343
|
+
/**
|
|
344
|
+
* What has sounded, most recent last.
|
|
345
|
+
*
|
|
346
|
+
* Audio is a no-op headless, which left "did the coin sound actually fire
|
|
347
|
+
* when the coin was collected?" unanswerable — the audio skill's own advice
|
|
348
|
+
* was to *"assert `play()` doesn't throw and check your gameplay logic
|
|
349
|
+
* instead"*, which checks something else. The CALL still happens with no
|
|
350
|
+
* backend, so recording it answers the wiring question everywhere: in the
|
|
351
|
+
* verify VM, in a playtest, in a test.
|
|
352
|
+
*
|
|
353
|
+
* Bounded (200) — a game running for an hour must not grow a log.
|
|
354
|
+
*/
|
|
355
|
+
private readonly events;
|
|
356
|
+
/** @internal Called by the players; games read `recent()`. */
|
|
357
|
+
record(event: AudioEvent): void;
|
|
358
|
+
/** The last `limit` sounds, oldest first. */
|
|
359
|
+
recent(limit?: number): AudioEvent[];
|
|
360
|
+
/** How many times a preset/clip/track sounded — the assertion you want. */
|
|
361
|
+
countOf(name: string): number;
|
|
362
|
+
/** Forget what has sounded so far (between scenes, or between assertions). */
|
|
363
|
+
clearLog(): void;
|
|
331
364
|
private _master;
|
|
332
365
|
private _sfx;
|
|
333
366
|
private _music;
|
|
@@ -377,6 +410,8 @@ interface MusicBackend {
|
|
|
377
410
|
createTrack(src: string): MusicTrack;
|
|
378
411
|
/** Resume a gesture-suspended context (wired to the first user gesture). */
|
|
379
412
|
unlock(): void;
|
|
413
|
+
/** Release the context it owns (optional — teardown). */
|
|
414
|
+
dispose?(): void;
|
|
380
415
|
}
|
|
381
416
|
interface PlayMusicOptions {
|
|
382
417
|
/** Loop the track (default true — music usually loops). */
|
|
@@ -420,6 +455,15 @@ declare class MusicManager {
|
|
|
420
455
|
get current(): string | null;
|
|
421
456
|
/** Per-manager volume (0..1), on top of the bus gain. */
|
|
422
457
|
get volume(): number;
|
|
458
|
+
/**
|
|
459
|
+
* The backend, or an INERT one that mints silent tracks.
|
|
460
|
+
*
|
|
461
|
+
* Never null, on purpose: the manager used to return before touching its
|
|
462
|
+
* state when there was no backend, so `current` stayed null forever in every
|
|
463
|
+
* headless run — including the verify VM, which is the only place a game is
|
|
464
|
+
* checked automatically. "Did the boss music start?" had no answer anywhere.
|
|
465
|
+
* With an inert backend the state machine runs identically and nothing plays.
|
|
466
|
+
*/
|
|
423
467
|
private ensure;
|
|
424
468
|
/** Resume a gesture-suspended context + (re)start any pending track. */
|
|
425
469
|
unlock(): void;
|
|
@@ -432,6 +476,13 @@ declare class MusicManager {
|
|
|
432
476
|
crossfadeTo(src: string, seconds?: number): void;
|
|
433
477
|
/** Stop the current track, optionally fading out over `fadeOut` seconds. */
|
|
434
478
|
stop(fadeOut?: number): void;
|
|
479
|
+
/**
|
|
480
|
+
* Stop instantly and release the backend — music must not outlive the game.
|
|
481
|
+
*
|
|
482
|
+
* `dispose()` is the one call that tears an SPA-mounted game down, and it used
|
|
483
|
+
* to leave the track playing with the engine that owned it gone.
|
|
484
|
+
*/
|
|
485
|
+
dispose(): void;
|
|
435
486
|
/** Set the per-manager volume (re-applied to live tracks on the next tick). */
|
|
436
487
|
setVolume(v: number): void;
|
|
437
488
|
/** Advance fades by `dt` seconds and (re)apply bus×fade gains. Frame-driven. */
|
|
@@ -588,6 +639,14 @@ interface Voice {
|
|
|
588
639
|
//#endregion
|
|
589
640
|
//#region src/core/audio/webaudio-sfx.d.ts
|
|
590
641
|
/** A spatial emitter: where the sound is + where the listener is. */
|
|
642
|
+
/** The shape `AudioBuses.record` takes (structural — no import cycle). */
|
|
643
|
+
interface AudioRecord {
|
|
644
|
+
kind: "preset" | "src" | "music" | "voice";
|
|
645
|
+
name: string;
|
|
646
|
+
from: string;
|
|
647
|
+
bus: "sfx" | "music";
|
|
648
|
+
at: number;
|
|
649
|
+
}
|
|
591
650
|
interface SpatialPlay {
|
|
592
651
|
/** Emitter world position. */
|
|
593
652
|
position: Vec3;
|
|
@@ -615,6 +674,19 @@ declare class SfxEngine {
|
|
|
615
674
|
private ctx;
|
|
616
675
|
private resolved;
|
|
617
676
|
private readonly pcmCache;
|
|
677
|
+
/**
|
|
678
|
+
* The engine's buses, when this SfxEngine belongs to one — so a continuous
|
|
679
|
+
* voice lands in the same audio record as everything else. A record that
|
|
680
|
+
* covered only SOME sounds would answer "did the engine hum start?" with a
|
|
681
|
+
* confident no.
|
|
682
|
+
*/
|
|
683
|
+
private buses;
|
|
684
|
+
/** Live continuous voices, so teardown can silence the ones nobody stopped. */
|
|
685
|
+
private readonly voices;
|
|
686
|
+
/** @internal Engine wiring. */
|
|
687
|
+
_setBuses(buses: {
|
|
688
|
+
record(event: AudioRecord): void;
|
|
689
|
+
}): void;
|
|
618
690
|
/** True once a backend is present (lazily created on first use). */
|
|
619
691
|
get available(): boolean;
|
|
620
692
|
private ensure;
|
|
@@ -624,6 +696,18 @@ declare class SfxEngine {
|
|
|
624
696
|
* done. Headless returns an inert handle (same call sites, no ifs).
|
|
625
697
|
*/
|
|
626
698
|
startVoice(preset: VoicePreset, gain?: number): Voice;
|
|
699
|
+
/** How many continuous voices are still running (teardown/leak checks). */
|
|
700
|
+
get liveVoiceCount(): number;
|
|
701
|
+
/** Silence every continuous voice — the hum must not outlive the game. */
|
|
702
|
+
stopAll(seconds?: number): void;
|
|
703
|
+
/**
|
|
704
|
+
* Silence everything and release the AudioContext.
|
|
705
|
+
*
|
|
706
|
+
* A browser allows only a handful of contexts per page, so an SPA that mounts
|
|
707
|
+
* the game a few times must hand this one back — `dispose()` is documented as
|
|
708
|
+
* the call that tears everything down.
|
|
709
|
+
*/
|
|
710
|
+
dispose(): void;
|
|
627
711
|
/** Resume a gesture-suspended context (wired to the first user gesture). */
|
|
628
712
|
unlock(): void;
|
|
629
713
|
/**
|
|
@@ -760,6 +844,20 @@ declare class InputMap {
|
|
|
760
844
|
connect(fn: () => void): () => void;
|
|
761
845
|
};
|
|
762
846
|
}): () => void;
|
|
847
|
+
/**
|
|
848
|
+
* Pointer input from a mouse, a FINGER or a pen — one code path.
|
|
849
|
+
*
|
|
850
|
+
* This used to bind `mousedown`/`mousemove`/`mouseup`, which on a phone only
|
|
851
|
+
* arrive as COMPATIBILITY events: delayed until the browser has decided the
|
|
852
|
+
* touch is not a scroll, never fired for drags or multi-touch, and suppressed
|
|
853
|
+
* outright once the surface claims its gestures with `touch-action: none`.
|
|
854
|
+
* So every genre the comment below lists — match-3, tower defense, card,
|
|
855
|
+
* point-and-click, RTS — was mouse-only on the device most of them are played
|
|
856
|
+
* on. Pointer events cover all three input kinds and fire immediately.
|
|
857
|
+
*
|
|
858
|
+
* Only the PRIMARY pointer drives it: a second finger (the one on the virtual
|
|
859
|
+
* stick) must not also swing the camera.
|
|
860
|
+
*/
|
|
763
861
|
attachPointer(target: HTMLElement, opts?: {
|
|
764
862
|
lockOnClick?: boolean;
|
|
765
863
|
}): () => void;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-BTkHYrQn.js";
|
|
3
|
+
import { b as AudioPlayer, x as Engine } from "./register-BTomIiYG.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import { i as resolveRendering, n as attachTouchControls } from "./touch-
|
|
6
|
-
import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
5
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-BnMyy9tr.js";
|
|
6
|
+
import { a as openBundledEditor, c as audioErrors, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, s as claimCanvasGestures, t as teardown } from "./teardown-Bw2aeyGI.js";
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-CRYw_Q-T.js";
|
|
8
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-DROK2l7J.js";
|
|
9
9
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
10
|
+
import { n as enablePhysics2D } from "./physics-2d-BhZZ-HAp.js";
|
|
11
11
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
12
12
|
//#region src/2d/assets.ts
|
|
13
13
|
/**
|
|
@@ -625,10 +625,15 @@ async function createGame2D(opts) {
|
|
|
625
625
|
const cleanups = [];
|
|
626
626
|
const keyboard = opts.keyboard ?? (typeof window !== "undefined" ? window : false);
|
|
627
627
|
if (keyboard) engine.input.attachKeyboard(keyboard);
|
|
628
|
+
if (opts.pointer) {
|
|
629
|
+
const lockOnClick = typeof opts.pointer === "object" ? opts.pointer.lockOnClick ?? false : false;
|
|
630
|
+
engine.input.attachPointer(opts.canvas, { lockOnClick });
|
|
631
|
+
}
|
|
628
632
|
cleanups.push(wireAudioUnlock(engine, scene.root, opts.canvas));
|
|
629
633
|
cleanups.push(engine.settings.bindAudio(engine.audio));
|
|
630
634
|
cleanups.push(pauseWhenHidden(engine));
|
|
631
635
|
cleanups.push(engine.settings.bindLocale(engine.locale));
|
|
636
|
+
if (!opts.pageGestures) claimCanvasGestures(opts.canvas);
|
|
632
637
|
const touchMode = opts.touch ?? "auto";
|
|
633
638
|
if (touchMode !== false) {
|
|
634
639
|
const host = opts.touchContainer ?? opts.canvas.parentElement ?? null;
|
|
@@ -718,6 +723,9 @@ async function createGame2D(opts) {
|
|
|
718
723
|
pick(x, y) {
|
|
719
724
|
return engine.picker?.(x, y) ?? null;
|
|
720
725
|
},
|
|
726
|
+
assetErrors() {
|
|
727
|
+
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
728
|
+
},
|
|
721
729
|
stats() {
|
|
722
730
|
return {
|
|
723
731
|
triangles: 0,
|
|
@@ -755,10 +763,17 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
755
763
|
target: canvasTarget,
|
|
756
764
|
type: "pointerdown"
|
|
757
765
|
});
|
|
758
|
-
if (typeof window !== "undefined")
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
766
|
+
if (typeof window !== "undefined") {
|
|
767
|
+
const win = window;
|
|
768
|
+
sources.push({
|
|
769
|
+
target: win,
|
|
770
|
+
type: "keydown"
|
|
771
|
+
});
|
|
772
|
+
sources.push({
|
|
773
|
+
target: win,
|
|
774
|
+
type: "pointerdown"
|
|
775
|
+
});
|
|
776
|
+
}
|
|
762
777
|
if (sources.length === 0) return () => {};
|
|
763
778
|
function detachAll() {
|
|
764
779
|
for (const s of sources) s.target.removeEventListener?.(s.type, unlock);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-BTkHYrQn.js";
|
|
3
|
+
import { C as qualityCaps, T as qualityRendering, b as AudioPlayer, x as Engine } from "./register-BTomIiYG.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import { r as parseDrive, t as logReport } from "./log-report-
|
|
6
|
-
import { i as resolveRendering, n as attachTouchControls } from "./touch-
|
|
7
|
-
import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-
|
|
8
|
-
import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-
|
|
5
|
+
import { r as parseDrive, t as logReport } from "./log-report-CPFm4OXf.js";
|
|
6
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-BnMyy9tr.js";
|
|
7
|
+
import { a as openBundledEditor, c as audioErrors, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as claimCanvasGestures, t as teardown } from "./teardown-Bw2aeyGI.js";
|
|
8
|
+
import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-CRYw_Q-T.js";
|
|
9
9
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
10
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-SkGanr2s.js";
|
|
11
11
|
import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-njybhZon.js";
|
|
12
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
12
|
+
import { n as enablePhysics3D } from "./physics-3d-DmyO2oaN.js";
|
|
13
13
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
14
14
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
15
15
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -2349,6 +2349,7 @@ async function createGame3D(opts) {
|
|
|
2349
2349
|
engine.input.attachPointer(opts.canvas, { lockOnClick });
|
|
2350
2350
|
}
|
|
2351
2351
|
cleanups.push(wireAudioUnlock(engine, scene.root, opts.canvas));
|
|
2352
|
+
if (!opts.pageGestures) claimCanvasGestures(opts.canvas);
|
|
2352
2353
|
const touchMode = opts.touch ?? "auto";
|
|
2353
2354
|
if (touchMode !== false) {
|
|
2354
2355
|
const host = opts.touchContainer ?? opts.canvas.parentElement ?? null;
|
|
@@ -2575,7 +2576,7 @@ async function createGame3D(opts) {
|
|
|
2575
2576
|
renderer,
|
|
2576
2577
|
physics,
|
|
2577
2578
|
assetErrors() {
|
|
2578
|
-
return renderer.assets?.errors() ?? [];
|
|
2579
|
+
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
2579
2580
|
},
|
|
2580
2581
|
async frame(frameOpts) {
|
|
2581
2582
|
const capture = renderer.captureFrame;
|
|
@@ -2623,10 +2624,17 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
2623
2624
|
target: canvasTarget,
|
|
2624
2625
|
type: "pointerdown"
|
|
2625
2626
|
});
|
|
2626
|
-
if (typeof window !== "undefined")
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2627
|
+
if (typeof window !== "undefined") {
|
|
2628
|
+
const win = window;
|
|
2629
|
+
sources.push({
|
|
2630
|
+
target: win,
|
|
2631
|
+
type: "keydown"
|
|
2632
|
+
});
|
|
2633
|
+
sources.push({
|
|
2634
|
+
target: win,
|
|
2635
|
+
type: "pointerdown"
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2630
2638
|
if (sources.length === 0) return () => {};
|
|
2631
2639
|
function detachAll() {
|
|
2632
2640
|
for (const s of sources) s.target.removeEventListener?.(s.type, unlock);
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-
|
|
1
|
+
import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-Do0Da56m.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
package/dist/editor.js
CHANGED
|
@@ -1181,6 +1181,20 @@ var kt = {
|
|
|
1181
1181
|
en: "Options are the locales the scene declares in \"strings\", each labeled with its own endonym. Picking one switches the game live and persists it. English is the base: any key a locale omits falls back to it, on purpose.",
|
|
1182
1182
|
ko: "옵션은 씬의 \"strings\"가 선언한 로케일이며, 각 언어의 자기 이름으로 표시됩니다. 선택하면 즉시 바뀌고 저장됩니다. 영어가 기준이라 로케일이 빠뜨린 키는 의도적으로 영어로 표시됩니다."
|
|
1183
1183
|
}),
|
|
1184
|
+
L("UiVolumeSlider", {
|
|
1185
|
+
en: "A volume slider, already wired to a bus.",
|
|
1186
|
+
ko: "볼륨 슬라이더 — 버스에 이미 연결되어 있습니다."
|
|
1187
|
+
}, {
|
|
1188
|
+
en: "bus picks which one it owns: master (everything), sfx or music. It writes engine.audio, which persists itself, so nothing needs saving. Left unlabelled it names its own bus. Two of them (music + sfx) is the audio menu most games ship.",
|
|
1189
|
+
ko: "bus로 어느 볼륨을 맡을지 고릅니다 — master(전체), sfx, music. engine.audio에 쓰면 자동 저장되므로 따로 저장할 게 없습니다. label을 비워두면 버스 이름이 표시됩니다. 대부분의 게임은 music + sfx 두 개면 충분합니다."
|
|
1190
|
+
}),
|
|
1191
|
+
L("UiMuteToggle", {
|
|
1192
|
+
en: "The mute switch — checked means silent.",
|
|
1193
|
+
ko: "음소거 스위치 — 체크하면 소리가 꺼집니다."
|
|
1194
|
+
}, {
|
|
1195
|
+
en: "Writes engine.audio.muted and persists with the volumes. Follows a mute made anywhere else, so two menus can never disagree.",
|
|
1196
|
+
ko: "engine.audio.muted에 쓰고 볼륨과 함께 저장됩니다. 다른 곳에서 음소거해도 따라가므로 두 메뉴가 어긋나지 않습니다."
|
|
1197
|
+
}),
|
|
1184
1198
|
L("UiQualitySelect", {
|
|
1185
1199
|
en: "Graphics quality — Low, Medium, High. Already wired.",
|
|
1186
1200
|
ko: "그래픽 품질 — Low, Medium, High. 이미 연결되어 있습니다."
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { t as registerCoreNodes } from "./register-
|
|
1
|
+
import { t as registerCoreNodes } from "./register-BTomIiYG.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
4
|
import { i as getNodeSchema, l as registerNode } from "./registry-C7u42TID.js";
|
|
5
5
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
6
6
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-D_p28jwU.js";
|
|
7
|
-
import { F as CharacterBody3D, I as PhysicsBody3D, L as RigidBody3D, N as WaterCutout3D, P as Area3D, R as StaticBody3D, U as colliderFootDrop, j as Water3D, z as Node3D } from "./gameplay-
|
|
7
|
+
import { F as CharacterBody3D, I as PhysicsBody3D, L as RigidBody3D, N as WaterCutout3D, P as Area3D, R as StaticBody3D, U as colliderFootDrop, j as Water3D, z as Node3D } from "./gameplay-CRYw_Q-T.js";
|
|
8
8
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
9
9
|
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
10
10
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as registerBehavior, T as Behavior, b as effectiveOrder, f as Node, n as loadScene, p as SaveSlots } from "./loader-
|
|
1
|
+
import { A as registerBehavior, T as Behavior, b as effectiveOrder, f as Node, n as loadScene, p as SaveSlots } from "./loader-BTkHYrQn.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
4
|
-
import { t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { t as duplicateNode } from "./duplicate-MNLMAcbz.js";
|
|
5
5
|
import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
6
6
|
//#region src/3d/frustum.ts
|
|
7
7
|
const scratchFrustum = new Frustum();
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dt as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { Dt as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-Do0Da56m.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as Chase, C as restartScene, D as DamageOnContact, E as phaseOf, O as Health, S as goToScene, T as DayNight, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, k as Collector, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, w as FollowCamera, x as GameFlow, y as screenFlash } from "./gameplay-
|
|
1
|
+
import { A as Chase, C as restartScene, D as DamageOnContact, E as phaseOf, O as Health, S as goToScene, T as DayNight, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, k as Collector, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, w as FollowCamera, x as GameFlow, y as screenFlash } from "./gameplay-CRYw_Q-T.js";
|
|
2
2
|
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|