@zylem/game-lib 0.5.1 → 0.6.2
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/behaviors.d.ts +834 -88
- package/dist/behaviors.js +1166 -355
- package/dist/behaviors.js.map +1 -1
- package/dist/blueprints-Cq3Ko6_G.d.ts +26 -0
- package/dist/{camera-Dk-fOVZE.d.ts → camera-CeJPAgGg.d.ts} +20 -46
- package/dist/camera.d.ts +2 -2
- package/dist/camera.js +340 -129
- package/dist/camera.js.map +1 -1
- package/dist/{core-C2mjetAd.d.ts → core-bO8TzV7u.d.ts} +113 -44
- package/dist/core.d.ts +8 -5
- package/dist/core.js +6180 -3678
- package/dist/core.js.map +1 -1
- package/dist/entities-DvByhMGU.d.ts +306 -0
- package/dist/entities.d.ts +5 -267
- package/dist/entities.js +3239 -1893
- package/dist/entities.js.map +1 -1
- package/dist/entity-Bq_eNEDI.d.ts +28 -0
- package/dist/entity-types-DAu8sGJH.d.ts +26 -0
- package/dist/main.d.ts +147 -31
- package/dist/main.js +9364 -5479
- package/dist/main.js.map +1 -1
- package/dist/{stage-CrmY7V0i.d.ts → stage-types-Bd-KtcYT.d.ts} +149 -61
- package/dist/stage.d.ts +42 -20
- package/dist/stage.js +4103 -2027
- package/dist/stage.js.map +1 -1
- package/dist/world-C8tQ7Plj.d.ts +774 -0
- package/package.json +2 -1
- package/dist/entity-bQElAdpo.d.ts +0 -347
- package/dist/entity-spawner-DNnLYnZq.d.ts +0 -11
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
import { Vector3, Vector2, Color, Material, BufferGeometry, Mesh, Group, ShaderMaterial } from 'three';
|
|
2
|
+
import RAPIER__default, { Vector3 as Vector3$1, RigidBodyDesc, ColliderDesc, RigidBody, Collider, World } from '@dimforge/rapier3d-compat';
|
|
3
|
+
import { E as Entity } from './entity-Bq_eNEDI.js';
|
|
4
|
+
import { IWorld, IComponent } from 'bitecs';
|
|
5
|
+
import * as mitt from 'mitt';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* BehaviorSystem Interface
|
|
9
|
+
*
|
|
10
|
+
* Base interface for ECS-based behavior systems that run at the stage level.
|
|
11
|
+
* Systems query entities with matching components and process them each frame.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A behavior system that processes entities with specific components.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* class ThrusterMovementSystem implements BehaviorSystem {
|
|
20
|
+
* update(ecs: IWorld, delta: number): void {
|
|
21
|
+
* // Query and process entities with thruster components
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
interface BehaviorSystem {
|
|
27
|
+
/** Called once per frame with ECS world and delta time */
|
|
28
|
+
update(ecs: IWorld, delta: number): void;
|
|
29
|
+
/** Optional cleanup when stage is destroyed */
|
|
30
|
+
destroy?(ecs: IWorld): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Factory function that creates a BehaviorSystem.
|
|
34
|
+
* Receives the stage for access to world, scene, etc.
|
|
35
|
+
*/
|
|
36
|
+
type BehaviorSystemFactory<T extends BehaviorSystem = BehaviorSystem> = (stage: {
|
|
37
|
+
world: any;
|
|
38
|
+
ecs: IWorld;
|
|
39
|
+
}) => T;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* BehaviorDescriptor
|
|
43
|
+
*
|
|
44
|
+
* Type-safe behavior descriptors that provide options inference.
|
|
45
|
+
* Used with entity.use() to declaratively attach behaviors to entities.
|
|
46
|
+
*
|
|
47
|
+
* Each behavior can define its own handle type via `createHandle`,
|
|
48
|
+
* providing behavior-specific methods with full type safety.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Base handle returned by entity.use() for lazy access to behavior runtime.
|
|
53
|
+
* FSM is null until entity is spawned and components are initialized.
|
|
54
|
+
*/
|
|
55
|
+
interface BaseBehaviorHandle<O extends Record<string, any> = Record<string, any>> {
|
|
56
|
+
/** Get the FSM instance (null until entity is spawned) */
|
|
57
|
+
getFSM(): any | null;
|
|
58
|
+
/** Get the current options */
|
|
59
|
+
getOptions(): O;
|
|
60
|
+
/** Access the underlying behavior ref */
|
|
61
|
+
readonly ref: BehaviorRef<O>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Reference to a behavior stored on an entity
|
|
65
|
+
*/
|
|
66
|
+
interface BehaviorRef<O extends Record<string, any> = Record<string, any>> {
|
|
67
|
+
/** The behavior descriptor */
|
|
68
|
+
descriptor: BehaviorDescriptor<O, any>;
|
|
69
|
+
/** Merged options (defaults + overrides) */
|
|
70
|
+
options: O;
|
|
71
|
+
/** Optional FSM instance - set lazily when entity is spawned */
|
|
72
|
+
fsm?: any;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A typed behavior descriptor that associates a symbol key with:
|
|
76
|
+
* - Default options (providing type inference)
|
|
77
|
+
* - A system factory to create the behavior system
|
|
78
|
+
* - An optional handle factory for behavior-specific methods
|
|
79
|
+
*/
|
|
80
|
+
interface BehaviorDescriptor<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
|
|
81
|
+
/** Unique symbol identifying this behavior */
|
|
82
|
+
readonly key: symbol;
|
|
83
|
+
/** Default options (used for type inference) */
|
|
84
|
+
readonly defaultOptions: O;
|
|
85
|
+
/** Factory to create the behavior system */
|
|
86
|
+
readonly systemFactory: BehaviorSystemFactory;
|
|
87
|
+
/**
|
|
88
|
+
* Optional factory to create behavior-specific handle methods.
|
|
89
|
+
* These methods are merged into the handle returned by entity.use().
|
|
90
|
+
*/
|
|
91
|
+
readonly createHandle?: (ref: BehaviorRef<O>) => H;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The full handle type returned by entity.use().
|
|
95
|
+
* Combines base handle with behavior-specific methods.
|
|
96
|
+
*/
|
|
97
|
+
type BehaviorHandle<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>> = BaseBehaviorHandle<O> & H;
|
|
98
|
+
/**
|
|
99
|
+
* Configuration for defining a new behavior
|
|
100
|
+
*/
|
|
101
|
+
interface DefineBehaviorConfig<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
|
|
102
|
+
/** Human-readable name for debugging */
|
|
103
|
+
name: string;
|
|
104
|
+
/** Default options - these define the type */
|
|
105
|
+
defaultOptions: O;
|
|
106
|
+
/** Factory function to create the system */
|
|
107
|
+
systemFactory: BehaviorSystemFactory;
|
|
108
|
+
/**
|
|
109
|
+
* Optional factory to create behavior-specific handle methods.
|
|
110
|
+
* The returned object is merged into the handle returned by entity.use().
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* createHandle: (ref) => ({
|
|
115
|
+
* getLastHits: () => ref.fsm?.getLastHits() ?? null,
|
|
116
|
+
* getMovement: (moveX, moveY) => ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
|
|
117
|
+
* }),
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
createHandle?: (ref: BehaviorRef<O>) => H;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Define a typed behavior descriptor.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* export const WorldBoundary2DBehavior = defineBehavior({
|
|
128
|
+
* name: 'world-boundary-2d',
|
|
129
|
+
* defaultOptions: { boundaries: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
130
|
+
* systemFactory: (ctx) => new WorldBoundary2DSystem(ctx.world),
|
|
131
|
+
* createHandle: (ref) => ({
|
|
132
|
+
* getLastHits: () => ref.fsm?.getLastHits() ?? null,
|
|
133
|
+
* getMovement: (moveX: number, moveY: number) =>
|
|
134
|
+
* ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
|
|
135
|
+
* }),
|
|
136
|
+
* });
|
|
137
|
+
*
|
|
138
|
+
* // Usage - handle has getLastHits and getMovement with full types
|
|
139
|
+
* const boundary = ship.use(WorldBoundary2DBehavior, { ... });
|
|
140
|
+
* const hits = boundary.getLastHits(); // Fully typed!
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function defineBehavior<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown>(config: DefineBehaviorConfig<O, H, I>): BehaviorDescriptor<O, H, I>;
|
|
144
|
+
|
|
145
|
+
type Vec3 = Vector3 | Vector3$1;
|
|
146
|
+
|
|
147
|
+
declare function shortHash(objString: string): string;
|
|
148
|
+
|
|
149
|
+
type ZylemShaderObject = {
|
|
150
|
+
fragment: string;
|
|
151
|
+
vertex: string;
|
|
152
|
+
};
|
|
153
|
+
interface MaterialOptions {
|
|
154
|
+
path?: string;
|
|
155
|
+
repeat?: Vector2;
|
|
156
|
+
shader?: ZylemShaderObject;
|
|
157
|
+
color?: Color;
|
|
158
|
+
}
|
|
159
|
+
type BatchGeometryMap = Map<symbol, number>;
|
|
160
|
+
interface BatchMaterialMapObject {
|
|
161
|
+
geometryMap: BatchGeometryMap;
|
|
162
|
+
material: Material;
|
|
163
|
+
}
|
|
164
|
+
type BatchKey = ReturnType<typeof shortHash>;
|
|
165
|
+
type TexturePath = string | null;
|
|
166
|
+
declare class MaterialBuilder {
|
|
167
|
+
static batchMaterialMap: Map<BatchKey, BatchMaterialMapObject>;
|
|
168
|
+
materials: Material[];
|
|
169
|
+
batchMaterial(options: Partial<MaterialOptions>, entityType: symbol): void;
|
|
170
|
+
build(options: Partial<MaterialOptions>, entityType: symbol): void;
|
|
171
|
+
withColor(color: Color): this;
|
|
172
|
+
withShader(shader: ZylemShaderObject): this;
|
|
173
|
+
/**
|
|
174
|
+
* Set texture - loads in background (deferred).
|
|
175
|
+
* Material is created immediately with null map, texture applies when loaded.
|
|
176
|
+
*/
|
|
177
|
+
setTexture(texturePath?: TexturePath, repeat?: Vector2): void;
|
|
178
|
+
setColor(color: Color): void;
|
|
179
|
+
setShader(customShader: ZylemShaderObject): void;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Options for configuring entity collision behavior.
|
|
184
|
+
*/
|
|
185
|
+
interface CollisionOptions {
|
|
186
|
+
static?: boolean;
|
|
187
|
+
sensor?: boolean;
|
|
188
|
+
size?: Vector3$1;
|
|
189
|
+
position?: Vector3$1;
|
|
190
|
+
collisionType?: string;
|
|
191
|
+
collisionFilter?: string[];
|
|
192
|
+
}
|
|
193
|
+
declare class CollisionBuilder {
|
|
194
|
+
static: boolean;
|
|
195
|
+
sensor: boolean;
|
|
196
|
+
gravity: Vec3;
|
|
197
|
+
build(options: Partial<CollisionOptions>): [RigidBodyDesc, ColliderDesc];
|
|
198
|
+
withCollision(collisionOptions: Partial<CollisionOptions>): this;
|
|
199
|
+
collider(options: CollisionOptions): ColliderDesc;
|
|
200
|
+
bodyDesc({ isDynamicBody }: {
|
|
201
|
+
isDynamicBody?: boolean | undefined;
|
|
202
|
+
}): RigidBodyDesc;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Input
|
|
206
|
+
*
|
|
207
|
+
* Maximum number of local players is 8.
|
|
208
|
+
* All input can be mapped to a gamepad or keyboard but shares the common
|
|
209
|
+
* interface represented as a gamepad.
|
|
210
|
+
*/
|
|
211
|
+
type InputPlayerNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
212
|
+
type InputPlayer = `p${InputPlayerNumber}`;
|
|
213
|
+
interface ButtonState {
|
|
214
|
+
pressed: boolean;
|
|
215
|
+
released: boolean;
|
|
216
|
+
held: number;
|
|
217
|
+
}
|
|
218
|
+
interface AnalogState {
|
|
219
|
+
value: number;
|
|
220
|
+
held: number;
|
|
221
|
+
}
|
|
222
|
+
interface InputGamepad {
|
|
223
|
+
playerNumber: InputPlayerNumber;
|
|
224
|
+
buttons: {
|
|
225
|
+
A: ButtonState;
|
|
226
|
+
B: ButtonState;
|
|
227
|
+
X: ButtonState;
|
|
228
|
+
Y: ButtonState;
|
|
229
|
+
Start: ButtonState;
|
|
230
|
+
Select: ButtonState;
|
|
231
|
+
L: ButtonState;
|
|
232
|
+
R: ButtonState;
|
|
233
|
+
};
|
|
234
|
+
directions: {
|
|
235
|
+
Up: ButtonState;
|
|
236
|
+
Down: ButtonState;
|
|
237
|
+
Left: ButtonState;
|
|
238
|
+
Right: ButtonState;
|
|
239
|
+
};
|
|
240
|
+
shoulders: {
|
|
241
|
+
LTrigger: ButtonState;
|
|
242
|
+
RTrigger: ButtonState;
|
|
243
|
+
};
|
|
244
|
+
axes: {
|
|
245
|
+
Horizontal: AnalogState;
|
|
246
|
+
Vertical: AnalogState;
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
type Inputs = Record<InputPlayer, InputGamepad>;
|
|
250
|
+
|
|
251
|
+
type LoadingEvent = {
|
|
252
|
+
type: 'start' | 'progress' | 'complete';
|
|
253
|
+
message?: string;
|
|
254
|
+
progress?: number;
|
|
255
|
+
total?: number;
|
|
256
|
+
current?: number;
|
|
257
|
+
};
|
|
258
|
+
interface IGame<TGlobals extends Record<string, unknown> = any> {
|
|
259
|
+
start: () => Promise<this>;
|
|
260
|
+
nextStage: () => void;
|
|
261
|
+
previousStage: () => void;
|
|
262
|
+
reset: () => Promise<void>;
|
|
263
|
+
pause: () => Promise<void>;
|
|
264
|
+
resume: () => Promise<void>;
|
|
265
|
+
onLoading: (callback: (event: LoadingEvent) => void) => void;
|
|
266
|
+
loadStageFromId: (stageId: string) => Promise<void>;
|
|
267
|
+
end: () => Promise<void>;
|
|
268
|
+
goToStage: () => void;
|
|
269
|
+
}
|
|
270
|
+
interface IStage {
|
|
271
|
+
onUpdate: (callback: UpdateFunction<IStage>) => void;
|
|
272
|
+
onSetup: (callback: SetupFunction<IStage>) => void;
|
|
273
|
+
onDestroy: (callback: DestroyFunction<IStage>) => void;
|
|
274
|
+
}
|
|
275
|
+
interface ICamera {
|
|
276
|
+
move: (position: Vector3) => void;
|
|
277
|
+
rotate: (pitch: number, yaw: number, roll: number) => void;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
type GlobalRecord = Record<string, unknown>;
|
|
281
|
+
/** Setup */
|
|
282
|
+
interface SetupContext<T, TGlobals extends GlobalRecord = any> {
|
|
283
|
+
me: T;
|
|
284
|
+
globals: TGlobals;
|
|
285
|
+
inputs?: Inputs;
|
|
286
|
+
camera?: ICamera;
|
|
287
|
+
stage?: IStage;
|
|
288
|
+
game?: IGame<TGlobals>;
|
|
289
|
+
}
|
|
290
|
+
interface SetupFunction<T, TGlobals extends GlobalRecord = any> {
|
|
291
|
+
(context: SetupContext<T, TGlobals>): void;
|
|
292
|
+
}
|
|
293
|
+
/** Loaded */
|
|
294
|
+
interface LoadedContext<T, TGlobals extends GlobalRecord = any> {
|
|
295
|
+
me: T;
|
|
296
|
+
globals: TGlobals;
|
|
297
|
+
}
|
|
298
|
+
interface LoadedFunction<T, TGlobals extends GlobalRecord = any> {
|
|
299
|
+
(context: LoadedContext<T, TGlobals>): void;
|
|
300
|
+
}
|
|
301
|
+
/** Update */
|
|
302
|
+
type UpdateContext<T, TGlobals extends GlobalRecord = any> = {
|
|
303
|
+
me: T;
|
|
304
|
+
delta: number;
|
|
305
|
+
inputs: Inputs;
|
|
306
|
+
globals: TGlobals;
|
|
307
|
+
camera: ICamera;
|
|
308
|
+
stage?: IStage;
|
|
309
|
+
game?: IGame<TGlobals>;
|
|
310
|
+
};
|
|
311
|
+
interface UpdateFunction<T, TGlobals extends GlobalRecord = any> {
|
|
312
|
+
(context: UpdateContext<T, TGlobals>): void;
|
|
313
|
+
}
|
|
314
|
+
/** Destroy */
|
|
315
|
+
interface DestroyContext<T, TGlobals extends GlobalRecord = any> {
|
|
316
|
+
me: T;
|
|
317
|
+
globals: TGlobals;
|
|
318
|
+
}
|
|
319
|
+
interface DestroyFunction<T, TGlobals extends GlobalRecord = any> {
|
|
320
|
+
(context: DestroyContext<T, TGlobals>): void;
|
|
321
|
+
}
|
|
322
|
+
/** Cleanup */
|
|
323
|
+
interface CleanupContext<T, TGlobals extends GlobalRecord = any> {
|
|
324
|
+
me: T;
|
|
325
|
+
globals: TGlobals;
|
|
326
|
+
}
|
|
327
|
+
interface CleanupFunction<T, TGlobals extends GlobalRecord = any> {
|
|
328
|
+
(context: CleanupContext<T, TGlobals>): void;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
interface NodeInterface {
|
|
332
|
+
uuid: string;
|
|
333
|
+
name: string;
|
|
334
|
+
markedForRemoval: boolean;
|
|
335
|
+
nodeSetup(params: SetupContext<any>): void;
|
|
336
|
+
nodeUpdate(params: UpdateContext<any>): void;
|
|
337
|
+
nodeDestroy(params: DestroyContext<any>): void;
|
|
338
|
+
setParent(parent: NodeInterface | null): void;
|
|
339
|
+
getParent(): NodeInterface | null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
type BaseNodeOptions<T = any> = BaseNode | Partial<T>;
|
|
343
|
+
/**
|
|
344
|
+
* Lifecycle callback arrays - each lifecycle event can have multiple callbacks
|
|
345
|
+
* that execute in order.
|
|
346
|
+
*/
|
|
347
|
+
interface LifecycleCallbacks<T> {
|
|
348
|
+
setup: Array<SetupFunction<T>>;
|
|
349
|
+
loaded: Array<LoadedFunction<T>>;
|
|
350
|
+
update: Array<UpdateFunction<T>>;
|
|
351
|
+
destroy: Array<DestroyFunction<T>>;
|
|
352
|
+
cleanup: Array<CleanupFunction<T>>;
|
|
353
|
+
}
|
|
354
|
+
declare abstract class BaseNode<Options = any, T = any> implements NodeInterface {
|
|
355
|
+
protected parent: NodeInterface | null;
|
|
356
|
+
protected children: NodeInterface[];
|
|
357
|
+
options: Options;
|
|
358
|
+
eid: number;
|
|
359
|
+
uuid: string;
|
|
360
|
+
name: string;
|
|
361
|
+
markedForRemoval: boolean;
|
|
362
|
+
/**
|
|
363
|
+
* Lifecycle callback arrays - use onSetup(), onUpdate(), etc. to add callbacks
|
|
364
|
+
*/
|
|
365
|
+
protected lifecycleCallbacks: LifecycleCallbacks<this>;
|
|
366
|
+
constructor(args?: BaseNodeOptions[]);
|
|
367
|
+
/**
|
|
368
|
+
* Add setup callbacks to be executed in order during nodeSetup
|
|
369
|
+
*/
|
|
370
|
+
onSetup(...callbacks: Array<SetupFunction<this>>): this;
|
|
371
|
+
/**
|
|
372
|
+
* Add loaded callbacks to be executed in order during nodeLoaded
|
|
373
|
+
*/
|
|
374
|
+
onLoaded(...callbacks: Array<LoadedFunction<this>>): this;
|
|
375
|
+
/**
|
|
376
|
+
* Add update callbacks to be executed in order during nodeUpdate
|
|
377
|
+
*/
|
|
378
|
+
onUpdate(...callbacks: Array<UpdateFunction<this>>): this;
|
|
379
|
+
/**
|
|
380
|
+
* Add destroy callbacks to be executed in order during nodeDestroy
|
|
381
|
+
*/
|
|
382
|
+
onDestroy(...callbacks: Array<DestroyFunction<this>>): this;
|
|
383
|
+
/**
|
|
384
|
+
* Add cleanup callbacks to be executed in order during nodeCleanup
|
|
385
|
+
*/
|
|
386
|
+
onCleanup(...callbacks: Array<CleanupFunction<this>>): this;
|
|
387
|
+
/**
|
|
388
|
+
* Prepend setup callbacks (run before existing ones)
|
|
389
|
+
*/
|
|
390
|
+
prependSetup(...callbacks: Array<SetupFunction<this>>): this;
|
|
391
|
+
/**
|
|
392
|
+
* Prepend update callbacks (run before existing ones)
|
|
393
|
+
*/
|
|
394
|
+
prependUpdate(...callbacks: Array<UpdateFunction<this>>): this;
|
|
395
|
+
setParent(parent: NodeInterface | null): void;
|
|
396
|
+
getParent(): NodeInterface | null;
|
|
397
|
+
add(baseNode: NodeInterface): void;
|
|
398
|
+
remove(baseNode: NodeInterface): void;
|
|
399
|
+
getChildren(): NodeInterface[];
|
|
400
|
+
isComposite(): boolean;
|
|
401
|
+
abstract create(): T;
|
|
402
|
+
protected abstract _setup(params: SetupContext<this>): void;
|
|
403
|
+
protected abstract _loaded(params: LoadedContext<this>): Promise<void>;
|
|
404
|
+
protected abstract _update(params: UpdateContext<this>): void;
|
|
405
|
+
protected abstract _destroy(params: DestroyContext<this>): void;
|
|
406
|
+
protected abstract _cleanup(params: CleanupContext<this>): Promise<void>;
|
|
407
|
+
nodeSetup(params: SetupContext<this>): void;
|
|
408
|
+
nodeUpdate(params: UpdateContext<this>): void;
|
|
409
|
+
nodeDestroy(params: DestroyContext<this>): void;
|
|
410
|
+
nodeLoaded(params: LoadedContext<this>): Promise<void>;
|
|
411
|
+
nodeCleanup(params: CleanupContext<this>): Promise<void>;
|
|
412
|
+
getOptions(): Options;
|
|
413
|
+
setOptions(options: Partial<Options>): void;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* TODO: allow for multiple materials requires geometry groups
|
|
418
|
+
* TODO: allow for instanced uniforms
|
|
419
|
+
* TODO: allow for geometry groups
|
|
420
|
+
* TODO: allow for batched meshes
|
|
421
|
+
* import { InstancedUniformsMesh } from 'three-instanced-uniforms-mesh';
|
|
422
|
+
* may not need geometry groups for shaders though
|
|
423
|
+
* setGeometry<T extends BufferGeometry>(geometry: T) {
|
|
424
|
+
* MeshBuilder.bachedMesh = new BatchedMesh(10, 5000, 10000, material);
|
|
425
|
+
* }
|
|
426
|
+
*/
|
|
427
|
+
type MeshBuilderOptions = Partial<Pick<GameEntityOptions, 'batched' | 'material'>>;
|
|
428
|
+
declare class MeshBuilder {
|
|
429
|
+
_build(meshOptions: MeshBuilderOptions, geometry: BufferGeometry, materials: Material[]): Mesh;
|
|
430
|
+
_postBuild(): void;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
declare abstract class EntityCollisionBuilder extends CollisionBuilder {
|
|
434
|
+
abstract collider(options: GameEntityOptions): ColliderDesc;
|
|
435
|
+
}
|
|
436
|
+
declare abstract class EntityMeshBuilder extends MeshBuilder {
|
|
437
|
+
build(options: GameEntityOptions): BufferGeometry;
|
|
438
|
+
postBuild(): void;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
interface Behavior {
|
|
442
|
+
component: IComponent;
|
|
443
|
+
values: any;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Reusable delegate for event emission and subscription.
|
|
448
|
+
* Use via composition in Game, Stage, and Entity classes.
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* class Game {
|
|
452
|
+
* private eventDelegate = new EventEmitterDelegate<GameEvents>();
|
|
453
|
+
*
|
|
454
|
+
* dispatch<K extends keyof GameEvents>(event: K, payload: GameEvents[K]) {
|
|
455
|
+
* this.eventDelegate.dispatch(event, payload);
|
|
456
|
+
* }
|
|
457
|
+
* }
|
|
458
|
+
*/
|
|
459
|
+
declare class EventEmitterDelegate<TEvents extends Record<string, unknown>> {
|
|
460
|
+
private emitter;
|
|
461
|
+
private unsubscribes;
|
|
462
|
+
constructor();
|
|
463
|
+
/**
|
|
464
|
+
* Dispatch an event to all listeners.
|
|
465
|
+
*/
|
|
466
|
+
dispatch<K extends keyof TEvents>(event: K, payload: TEvents[K]): void;
|
|
467
|
+
/**
|
|
468
|
+
* Subscribe to an event. Returns an unsubscribe function.
|
|
469
|
+
*/
|
|
470
|
+
listen<K extends keyof TEvents>(event: K, handler: (payload: TEvents[K]) => void): () => void;
|
|
471
|
+
/**
|
|
472
|
+
* Subscribe to all events.
|
|
473
|
+
*/
|
|
474
|
+
listenAll(handler: (type: keyof TEvents, payload: TEvents[keyof TEvents]) => void): () => void;
|
|
475
|
+
/**
|
|
476
|
+
* Clean up all subscriptions.
|
|
477
|
+
*/
|
|
478
|
+
dispose(): void;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Payload for game loading events with stage context.
|
|
483
|
+
*/
|
|
484
|
+
interface GameLoadingPayload extends LoadingEvent {
|
|
485
|
+
stageName?: string;
|
|
486
|
+
stageIndex?: number;
|
|
487
|
+
}
|
|
488
|
+
/** Payload for stage configuration sent to editor. */
|
|
489
|
+
interface StageConfigPayload {
|
|
490
|
+
id: string;
|
|
491
|
+
backgroundColor: string;
|
|
492
|
+
backgroundImage: string | null;
|
|
493
|
+
gravity: {
|
|
494
|
+
x: number;
|
|
495
|
+
y: number;
|
|
496
|
+
z: number;
|
|
497
|
+
};
|
|
498
|
+
inputs: Record<string, string[]>;
|
|
499
|
+
variables: Record<string, unknown>;
|
|
500
|
+
}
|
|
501
|
+
/** Payload for entity configuration sent to editor. */
|
|
502
|
+
interface EntityConfigPayload {
|
|
503
|
+
uuid: string;
|
|
504
|
+
name: string;
|
|
505
|
+
type: string;
|
|
506
|
+
position: {
|
|
507
|
+
x: number;
|
|
508
|
+
y: number;
|
|
509
|
+
z: number;
|
|
510
|
+
};
|
|
511
|
+
rotation: {
|
|
512
|
+
x: number;
|
|
513
|
+
y: number;
|
|
514
|
+
z: number;
|
|
515
|
+
};
|
|
516
|
+
scale: {
|
|
517
|
+
x: number;
|
|
518
|
+
y: number;
|
|
519
|
+
z: number;
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/** Payload for state dispatch events from game to editor. */
|
|
523
|
+
interface StateDispatchPayload {
|
|
524
|
+
scope: 'game' | 'stage' | 'entity';
|
|
525
|
+
path: string;
|
|
526
|
+
value: unknown;
|
|
527
|
+
previousValue?: unknown;
|
|
528
|
+
config?: {
|
|
529
|
+
id: string;
|
|
530
|
+
aspectRatio: number;
|
|
531
|
+
fullscreen: boolean;
|
|
532
|
+
bodyBackground: string | undefined;
|
|
533
|
+
internalResolution: {
|
|
534
|
+
width: number;
|
|
535
|
+
height: number;
|
|
536
|
+
} | undefined;
|
|
537
|
+
debug: boolean;
|
|
538
|
+
} | null;
|
|
539
|
+
stageConfig?: StageConfigPayload | null;
|
|
540
|
+
entities?: EntityConfigPayload[] | null;
|
|
541
|
+
}
|
|
542
|
+
type GameEvents = {
|
|
543
|
+
'loading:start': GameLoadingPayload;
|
|
544
|
+
'loading:progress': GameLoadingPayload;
|
|
545
|
+
'loading:complete': GameLoadingPayload;
|
|
546
|
+
'paused': {
|
|
547
|
+
paused: boolean;
|
|
548
|
+
};
|
|
549
|
+
'debug': {
|
|
550
|
+
enabled: boolean;
|
|
551
|
+
};
|
|
552
|
+
'state:dispatch': StateDispatchPayload;
|
|
553
|
+
};
|
|
554
|
+
type StageEvents = {
|
|
555
|
+
'stage:loaded': {
|
|
556
|
+
stageId: string;
|
|
557
|
+
};
|
|
558
|
+
'stage:unloaded': {
|
|
559
|
+
stageId: string;
|
|
560
|
+
};
|
|
561
|
+
'stage:variable:changed': {
|
|
562
|
+
key: string;
|
|
563
|
+
value: unknown;
|
|
564
|
+
};
|
|
565
|
+
};
|
|
566
|
+
type EntityEvents = {
|
|
567
|
+
'entity:spawned': {
|
|
568
|
+
entityId: string;
|
|
569
|
+
name: string;
|
|
570
|
+
};
|
|
571
|
+
'entity:destroyed': {
|
|
572
|
+
entityId: string;
|
|
573
|
+
};
|
|
574
|
+
'entity:collision': {
|
|
575
|
+
entityId: string;
|
|
576
|
+
otherId: string;
|
|
577
|
+
};
|
|
578
|
+
'entity:model:loading': {
|
|
579
|
+
entityId: string;
|
|
580
|
+
files: string[];
|
|
581
|
+
};
|
|
582
|
+
'entity:model:loaded': {
|
|
583
|
+
entityId: string;
|
|
584
|
+
success: boolean;
|
|
585
|
+
meshCount?: number;
|
|
586
|
+
};
|
|
587
|
+
'entity:animation:loaded': {
|
|
588
|
+
entityId: string;
|
|
589
|
+
animationCount: number;
|
|
590
|
+
};
|
|
591
|
+
};
|
|
592
|
+
type ZylemEvents = GameEvents & StageEvents & EntityEvents;
|
|
593
|
+
/**
|
|
594
|
+
* Global event bus for cross-package communication.
|
|
595
|
+
*
|
|
596
|
+
* Usage:
|
|
597
|
+
* ```ts
|
|
598
|
+
* import { zylemEventBus } from '@zylem/game-lib';
|
|
599
|
+
*
|
|
600
|
+
* // Subscribe
|
|
601
|
+
* const unsub = zylemEventBus.on('loading:progress', (e) => console.log(e));
|
|
602
|
+
*
|
|
603
|
+
* // Emit
|
|
604
|
+
* zylemEventBus.emit('loading:progress', { type: 'progress', progress: 0.5 });
|
|
605
|
+
*
|
|
606
|
+
* // Cleanup
|
|
607
|
+
* unsub();
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
declare const zylemEventBus: mitt.Emitter<ZylemEvents>;
|
|
611
|
+
|
|
612
|
+
interface CollisionContext<T, O extends GameEntityOptions, TGlobals extends Record<string, unknown> = any> {
|
|
613
|
+
entity: T;
|
|
614
|
+
other: GameEntity<O | any>;
|
|
615
|
+
globals: TGlobals;
|
|
616
|
+
}
|
|
617
|
+
type BehaviorContext<T, O extends GameEntityOptions> = SetupContext<T, O> | UpdateContext<T, O> | CollisionContext<T, O> | DestroyContext<T, O>;
|
|
618
|
+
type BehaviorCallback<T, O extends GameEntityOptions> = (params: BehaviorContext<T, O>) => void;
|
|
619
|
+
interface CollisionDelegate<T, O extends GameEntityOptions> {
|
|
620
|
+
collision?: ((params: CollisionContext<any, any>) => void)[];
|
|
621
|
+
}
|
|
622
|
+
type IBuilder<BuilderOptions = any> = {
|
|
623
|
+
preBuild: (options: BuilderOptions) => BuilderOptions;
|
|
624
|
+
build: (options: BuilderOptions) => BuilderOptions;
|
|
625
|
+
postBuild: (options: BuilderOptions) => BuilderOptions;
|
|
626
|
+
};
|
|
627
|
+
type GameEntityOptions = {
|
|
628
|
+
name?: string;
|
|
629
|
+
color?: Color;
|
|
630
|
+
size?: Vec3;
|
|
631
|
+
position?: Vec3;
|
|
632
|
+
batched?: boolean;
|
|
633
|
+
collision?: Partial<CollisionOptions>;
|
|
634
|
+
material?: Partial<MaterialOptions>;
|
|
635
|
+
custom?: {
|
|
636
|
+
[key: string]: any;
|
|
637
|
+
};
|
|
638
|
+
collisionType?: string;
|
|
639
|
+
collisionGroup?: string;
|
|
640
|
+
collisionFilter?: string[];
|
|
641
|
+
_builders?: {
|
|
642
|
+
meshBuilder?: IBuilder | EntityMeshBuilder | null;
|
|
643
|
+
collisionBuilder?: IBuilder | EntityCollisionBuilder | null;
|
|
644
|
+
materialBuilder?: MaterialBuilder | null;
|
|
645
|
+
};
|
|
646
|
+
};
|
|
647
|
+
declare abstract class GameEntityLifeCycle {
|
|
648
|
+
abstract _setup(params: SetupContext<this>): void;
|
|
649
|
+
abstract _update(params: UpdateContext<this>): void;
|
|
650
|
+
abstract _destroy(params: DestroyContext<this>): void;
|
|
651
|
+
}
|
|
652
|
+
interface EntityDebugInfo {
|
|
653
|
+
buildInfo: () => Record<string, string>;
|
|
654
|
+
}
|
|
655
|
+
type BehaviorCallbackType = 'setup' | 'update' | 'destroy' | 'collision';
|
|
656
|
+
declare class GameEntity<O extends GameEntityOptions> extends BaseNode<O> implements GameEntityLifeCycle, EntityDebugInfo {
|
|
657
|
+
behaviors: Behavior[];
|
|
658
|
+
group: Group | undefined;
|
|
659
|
+
mesh: Mesh | undefined;
|
|
660
|
+
materials: Material[] | undefined;
|
|
661
|
+
bodyDesc: RigidBodyDesc | null;
|
|
662
|
+
body: RigidBody | null;
|
|
663
|
+
colliderDesc: ColliderDesc | undefined;
|
|
664
|
+
collider: Collider | undefined;
|
|
665
|
+
custom: Record<string, any>;
|
|
666
|
+
debugInfo: Record<string, any>;
|
|
667
|
+
debugMaterial: ShaderMaterial | undefined;
|
|
668
|
+
collisionDelegate: CollisionDelegate<this, O>;
|
|
669
|
+
collisionType?: string;
|
|
670
|
+
/**
|
|
671
|
+
* @deprecated Use the new ECS-based behavior system instead.
|
|
672
|
+
* Use 'any' for callback types to avoid contravariance issues
|
|
673
|
+
* with function parameters. Type safety is enforced where callbacks are registered.
|
|
674
|
+
*/
|
|
675
|
+
behaviorCallbackMap: Record<BehaviorCallbackType, BehaviorCallback<any, any>[]>;
|
|
676
|
+
protected eventDelegate: EventEmitterDelegate<EntityEvents>;
|
|
677
|
+
private behaviorRefs;
|
|
678
|
+
constructor();
|
|
679
|
+
create(): this;
|
|
680
|
+
/**
|
|
681
|
+
* Add collision callbacks
|
|
682
|
+
*/
|
|
683
|
+
onCollision(...callbacks: ((params: CollisionContext<this, O>) => void)[]): this;
|
|
684
|
+
/**
|
|
685
|
+
* Use a behavior on this entity via typed descriptor.
|
|
686
|
+
* Behaviors will be auto-registered as systems when the entity is spawned.
|
|
687
|
+
* @param descriptor The behavior descriptor (import from behaviors module)
|
|
688
|
+
* @param options Optional overrides for the behavior's default options
|
|
689
|
+
* @returns BehaviorHandle with behavior-specific methods for lazy FSM access
|
|
690
|
+
*/
|
|
691
|
+
use<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>>(descriptor: BehaviorDescriptor<O, H>, options?: Partial<O>): BehaviorHandle<O, H>;
|
|
692
|
+
/**
|
|
693
|
+
* Get all behavior references attached to this entity.
|
|
694
|
+
* Used by the stage to auto-register required systems.
|
|
695
|
+
*/
|
|
696
|
+
getBehaviorRefs(): BehaviorRef[];
|
|
697
|
+
/**
|
|
698
|
+
* Entity-specific setup - runs behavior callbacks
|
|
699
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.setup)
|
|
700
|
+
*/
|
|
701
|
+
_setup(params: SetupContext<this>): void;
|
|
702
|
+
protected _loaded(_params: LoadedContext<this>): Promise<void>;
|
|
703
|
+
/**
|
|
704
|
+
* Entity-specific update - updates materials and runs behavior callbacks
|
|
705
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.update)
|
|
706
|
+
*/
|
|
707
|
+
_update(params: UpdateContext<this>): void;
|
|
708
|
+
/**
|
|
709
|
+
* Entity-specific destroy - runs behavior callbacks
|
|
710
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.destroy)
|
|
711
|
+
*/
|
|
712
|
+
_destroy(params: DestroyContext<this>): void;
|
|
713
|
+
protected _cleanup(_params: CleanupContext<this>): Promise<void>;
|
|
714
|
+
_collision(other: GameEntity<O>, globals?: any): void;
|
|
715
|
+
/**
|
|
716
|
+
* @deprecated Use the new ECS-based behavior system instead.
|
|
717
|
+
* See `lib/behaviors/thruster/thruster-movement.behavior.ts` for an example.
|
|
718
|
+
*/
|
|
719
|
+
addBehavior(behaviorCallback: {
|
|
720
|
+
type: BehaviorCallbackType;
|
|
721
|
+
handler: any;
|
|
722
|
+
}): this;
|
|
723
|
+
/**
|
|
724
|
+
* @deprecated Use the new ECS-based behavior system instead.
|
|
725
|
+
* See `lib/behaviors/thruster/thruster-movement.behavior.ts` for an example.
|
|
726
|
+
*/
|
|
727
|
+
addBehaviors(behaviorCallbacks: {
|
|
728
|
+
type: BehaviorCallbackType;
|
|
729
|
+
handler: any;
|
|
730
|
+
}[]): this;
|
|
731
|
+
protected updateMaterials(params: any): void;
|
|
732
|
+
buildInfo(): Record<string, string>;
|
|
733
|
+
/**
|
|
734
|
+
* Dispatch an event from this entity.
|
|
735
|
+
* Events are emitted both locally and to the global event bus.
|
|
736
|
+
*/
|
|
737
|
+
dispatch<K extends keyof EntityEvents>(event: K, payload: EntityEvents[K]): void;
|
|
738
|
+
/**
|
|
739
|
+
* Listen for events on this entity instance.
|
|
740
|
+
* @returns Unsubscribe function
|
|
741
|
+
*/
|
|
742
|
+
listen<K extends keyof EntityEvents>(event: K, handler: (payload: EntityEvents[K]) => void): () => void;
|
|
743
|
+
/**
|
|
744
|
+
* Clean up entity event subscriptions.
|
|
745
|
+
*/
|
|
746
|
+
disposeEvents(): void;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Interface for entities that handle collision events.
|
|
751
|
+
*/
|
|
752
|
+
interface CollisionHandlerDelegate {
|
|
753
|
+
handlePostCollision(params: any): boolean;
|
|
754
|
+
handleIntersectionEvent(params: any): void;
|
|
755
|
+
}
|
|
756
|
+
declare class ZylemWorld implements Entity<ZylemWorld> {
|
|
757
|
+
type: string;
|
|
758
|
+
world: World;
|
|
759
|
+
collisionMap: Map<string, GameEntity<any>>;
|
|
760
|
+
collisionBehaviorMap: Map<string, GameEntity<any>>;
|
|
761
|
+
_removalMap: Map<string, GameEntity<any>>;
|
|
762
|
+
static loadPhysics(gravity: Vector3): Promise<RAPIER__default.World>;
|
|
763
|
+
constructor(world: World);
|
|
764
|
+
addEntity(entity: any): void;
|
|
765
|
+
setForRemoval(entity: any): void;
|
|
766
|
+
destroyEntity(entity: GameEntity<any>): void;
|
|
767
|
+
setup(): void;
|
|
768
|
+
update(params: UpdateContext<any>): void;
|
|
769
|
+
updatePostCollisionBehaviors(delta: number): void;
|
|
770
|
+
updateColliders(delta: number): void;
|
|
771
|
+
destroy(): void;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export { type CollisionHandlerDelegate as A, BaseNode as B, type CleanupContext as C, type DestroyFunction as D, EventEmitterDelegate as E, GameEntity as G, type InputGamepad as I, type LoadingEvent as L, type MaterialOptions as M, type SetupFunction as S, type TexturePath as T, type UpdateFunction as U, type Vec3 as V, type ZylemShaderObject as Z, type SetupContext as a, type UpdateContext as b, type DestroyContext as c, ZylemWorld as d, type BehaviorSystem as e, type BehaviorSystemFactory as f, type GameEntityOptions as g, type StageEvents as h, type ZylemEvents as i, type GameEvents as j, type EntityEvents as k, type GameLoadingPayload as l, type StateDispatchPayload as m, type StageConfigPayload as n, type EntityConfigPayload as o, defineBehavior as p, type BehaviorDescriptor as q, type BehaviorRef as r, type BehaviorHandle as s, type DefineBehaviorConfig as t, type InputPlayerNumber as u, type Inputs as v, GameEntityLifeCycle as w, type IGame as x, type LoadedContext as y, zylemEventBus as z };
|