@zylem/behaviors 0.4.1 → 0.5.1
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/README.md +13 -1
- package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CeJXzNvr.d.ts} +305 -17
- package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
- package/dist/chunk-2PAHQZZD.js.map +1 -0
- package/dist/chunk-52FJIDGL.js +30 -0
- package/dist/chunk-52FJIDGL.js.map +1 -0
- package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
- package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
- package/dist/{chunk-A4CA35DQ.js → chunk-5EBIIYZD.js} +25 -45
- package/dist/chunk-5EBIIYZD.js.map +1 -0
- package/dist/{chunk-4L36OPY2.js → chunk-5NJGASUJ.js} +81 -135
- package/dist/chunk-5NJGASUJ.js.map +1 -0
- package/dist/{chunk-27UPCP5B.js → chunk-5UMCWV5A.js} +22 -13
- package/dist/chunk-5UMCWV5A.js.map +1 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
- package/dist/{chunk-Z72F2ENM.js → chunk-AEBDZWCP.js} +17 -26
- package/dist/chunk-AEBDZWCP.js.map +1 -0
- package/dist/chunk-AS3HR7AS.js +188 -0
- package/dist/chunk-AS3HR7AS.js.map +1 -0
- package/dist/chunk-E4X4YJZB.js +841 -0
- package/dist/chunk-E4X4YJZB.js.map +1 -0
- package/dist/{chunk-VMQHNJJI.js → chunk-F6ESSHQK.js} +17 -23
- package/dist/chunk-F6ESSHQK.js.map +1 -0
- package/dist/chunk-GQAPBNGT.js +210 -0
- package/dist/chunk-GQAPBNGT.js.map +1 -0
- package/dist/chunk-JGXRQUTC.js +191 -0
- package/dist/chunk-JGXRQUTC.js.map +1 -0
- package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
- package/dist/chunk-JVADRLWX.js.map +1 -0
- package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
- package/dist/{chunk-QDCJLJUV.js → chunk-KOWGILCN.js} +22 -13
- package/dist/chunk-KOWGILCN.js.map +1 -0
- package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
- package/dist/chunk-M3QDKKDF.js.map +1 -0
- package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
- package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
- package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
- package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
- package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
- package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
- package/dist/chunk-PLIXVF7B.js.map +1 -0
- package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
- package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
- package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
- package/dist/chunk-TBUKJKY6.js.map +1 -0
- package/dist/chunk-VFDUKGRZ.js +155 -0
- package/dist/chunk-VFDUKGRZ.js.map +1 -0
- package/dist/chunk-VT3H43QA.js +288 -0
- package/dist/chunk-VT3H43QA.js.map +1 -0
- package/dist/chunk-W26PHBME.js +309 -0
- package/dist/chunk-W26PHBME.js.map +1 -0
- package/dist/components-BANNjAZP.d.ts +30 -0
- package/dist/cooldown.d.ts +2 -2
- package/dist/cooldown.js +1 -0
- package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet-3d.js +1 -0
- package/dist/coordinators/boundary-ricochet.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet.js +3 -2
- package/dist/coordinators/first-person-shooter.js +1 -0
- package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
- package/dist/coordinators/multidirectional-space-shooter.js +5 -3
- package/dist/coordinators/top-down-shooter.d.ts +3 -3
- package/dist/coordinators/top-down-shooter.js +5 -3
- package/dist/core.d.ts +288 -8
- package/dist/core.js +480 -13
- package/dist/core.js.map +1 -1
- package/dist/destructible-3d.d.ts +32 -4
- package/dist/destructible-3d.js +2 -1
- package/dist/destructible-prebake.js +1 -0
- package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
- package/dist/first-person.d.ts +27 -38
- package/dist/first-person.js +8 -8
- package/dist/index.d.ts +14 -15
- package/dist/index.js +37 -52
- package/dist/jumper-2d.d.ts +3 -17
- package/dist/jumper-2d.js +4 -9
- package/dist/jumper-3d.d.ts +5 -39
- package/dist/jumper-3d.js +5 -10
- package/dist/{moveable-Cl9h-_w7.d.ts → moveable-XhzWPAw5.d.ts} +21 -4
- package/dist/particle-emitter/presets.js +1 -0
- package/dist/particle-emitter.d.ts +3 -3
- package/dist/particle-emitter.js +3 -2
- package/dist/platformer-2d.d.ts +13 -82
- package/dist/platformer-2d.js +4 -5
- package/dist/platformer-3d.d.ts +13 -78
- package/dist/platformer-3d.js +4 -5
- package/dist/ricochet-2d.d.ts +3 -3
- package/dist/ricochet-2d.js +4 -3
- package/dist/ricochet-3d.d.ts +3 -3
- package/dist/ricochet-3d.js +4 -3
- package/dist/runtime-2d.d.ts +2 -2
- package/dist/runtime-2d.js +1 -0
- package/dist/runtime-2d.js.map +1 -1
- package/dist/screen-visibility.d.ts +2 -2
- package/dist/screen-visibility.js +1 -0
- package/dist/screen-wrap.d.ts +2 -2
- package/dist/screen-wrap.js +4 -3
- package/dist/shooter-2d.d.ts +3 -3
- package/dist/shooter-2d.js +4 -3
- package/dist/thruster.d.ts +5 -34
- package/dist/thruster.js +4 -6
- package/dist/top-down-movement.d.ts +9 -27
- package/dist/top-down-movement.js +6 -6
- package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
- package/dist/world-boundary-2d.d.ts +2 -2
- package/dist/world-boundary-2d.js +5 -4
- package/dist/world-boundary-3d.d.ts +2 -2
- package/dist/world-boundary-3d.js +4 -3
- package/package.json +2 -3
- package/dist/chunk-27UPCP5B.js.map +0 -1
- package/dist/chunk-4L36OPY2.js.map +0 -1
- package/dist/chunk-4URF65BR.js +0 -44
- package/dist/chunk-4URF65BR.js.map +0 -1
- package/dist/chunk-5XZWTFGF.js.map +0 -1
- package/dist/chunk-67XLJ26X.js +0 -536
- package/dist/chunk-67XLJ26X.js.map +0 -1
- package/dist/chunk-75FJIUIG.js +0 -240
- package/dist/chunk-75FJIUIG.js.map +0 -1
- package/dist/chunk-A4CA35DQ.js.map +0 -1
- package/dist/chunk-BXP4K7RF.js.map +0 -1
- package/dist/chunk-F72WX4MH.js +0 -422
- package/dist/chunk-F72WX4MH.js.map +0 -1
- package/dist/chunk-GFARAJV2.js.map +0 -1
- package/dist/chunk-JXMF4NUI.js +0 -309
- package/dist/chunk-JXMF4NUI.js.map +0 -1
- package/dist/chunk-OTLSUYQQ.js +0 -29
- package/dist/chunk-OTLSUYQQ.js.map +0 -1
- package/dist/chunk-Q75LKHDF.js +0 -56
- package/dist/chunk-Q75LKHDF.js.map +0 -1
- package/dist/chunk-QDCJLJUV.js.map +0 -1
- package/dist/chunk-RDHSHEZM.js +0 -479
- package/dist/chunk-RDHSHEZM.js.map +0 -1
- package/dist/chunk-UIG7MWS2.js +0 -518
- package/dist/chunk-UIG7MWS2.js.map +0 -1
- package/dist/chunk-UL6Q5HDP.js.map +0 -1
- package/dist/chunk-VMQHNJJI.js.map +0 -1
- package/dist/chunk-WWVD5DR5.js.map +0 -1
- package/dist/chunk-Z72F2ENM.js.map +0 -1
- package/dist/components-BWG1GkZA.d.ts +0 -20
- package/dist/use-behavior-B85d5u7-.d.ts +0 -13
- /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
- /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
- /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# Zylem Behaviors
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The simulation layer of the Zylem framework: tree-shakable behavior descriptors, FSMs, coordinators, and the `Simulation` API that owns the `@zylem/runtime` WASM module (ECS + Rapier physics).
|
|
4
|
+
|
|
5
|
+
`@zylem/behaviors` sits between the game framework and the runtime:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@zylem/game-lib → @zylem/behaviors → @zylem/runtime (WASM)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- **`createSimulation()` / `Simulation`** — loads and owns the WASM stage, exposes `spawn`/`despawn` with opaque `EntityHandle`s, a fixed-timestep `update(delta)` loop, snapshot/pose accessors, raycasts, debug rendering, and translated `SimulationEvent`s (collision start/stop with handles instead of raw slots).
|
|
12
|
+
- **Behavior descriptors** (`Platformer3DBehavior`, `TopDownMovementBehavior`, …) — attach WASM-side controllers to entities and forward per-frame input through batched buffers; FSM state is read back from snapshots.
|
|
13
|
+
- **`MockBehaviorRuntime`** — in-memory `BehaviorRuntime` implementation for unit-testing behaviors without loading WASM.
|
|
14
|
+
|
|
15
|
+
Physics simulation is WASM-only; there is no TypeScript physics fallback. Disposal chains downward: `Simulation.dispose()` destroys the WASM stage.
|
|
4
16
|
|
|
5
17
|
Use per-behavior entrypoints when you want bundlers to pull only the behavior family you import:
|
|
6
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StageWasmExports } from '@zylem/runtime';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* BehaviorDescriptor
|
|
@@ -199,8 +199,9 @@ declare class GameEntity<TOptions = unknown> {
|
|
|
199
199
|
group: any;
|
|
200
200
|
mesh?: any;
|
|
201
201
|
materials?: any[];
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
/** Opaque host-owned physics references (never inspected by behaviors). */
|
|
203
|
+
body: unknown | null;
|
|
204
|
+
collider: unknown | null;
|
|
204
205
|
colliderDesc?: any;
|
|
205
206
|
colliderDescs: any[];
|
|
206
207
|
bodyDesc?: any;
|
|
@@ -233,12 +234,24 @@ declare class GameEntity<TOptions = unknown> {
|
|
|
233
234
|
*/
|
|
234
235
|
type CreateEntityFn = (options?: Partial<GameEntityOptions>) => GameEntity<GameEntityOptions>;
|
|
235
236
|
|
|
237
|
+
/**
|
|
238
|
+
* `WasmStageRuntime` — owns one wasm `WebAssembly.Instance` of
|
|
239
|
+
* `@zylem/runtime` and exposes the unified-Stage FFI as typed TypeScript
|
|
240
|
+
* methods. This is the single simulation adapter for the whole framework:
|
|
241
|
+
* behavior systems talk to it through the {@link BehaviorRuntime} contract,
|
|
242
|
+
* and hosts (e.g. `@zylem/game-lib`) drive it through
|
|
243
|
+
* {@link createSimulation} in `./simulation`.
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
/** Sentinel handle for "no entity / failed allocation". Mirrors `INVALID_SLOT` in Rust. */
|
|
247
|
+
declare const STAGE_INVALID_SLOT = 4294967295;
|
|
236
248
|
declare const StageBodyKind: {
|
|
237
249
|
readonly Dynamic: 0;
|
|
238
250
|
readonly Static: 1;
|
|
239
251
|
readonly KinematicPosition: 2;
|
|
240
252
|
readonly KinematicVelocity: 3;
|
|
241
253
|
};
|
|
254
|
+
type StageBodyKindValue = (typeof StageBodyKind)[keyof typeof StageBodyKind];
|
|
242
255
|
declare const StageBoundaryDim: {
|
|
243
256
|
readonly Two: 2;
|
|
244
257
|
readonly Three: 3;
|
|
@@ -426,7 +439,7 @@ interface StageBehaviorSnapshot {
|
|
|
426
439
|
* a duplicate TS FSM (or hardcoded defaults).
|
|
427
440
|
*/
|
|
428
441
|
interface WasmSnapshotBackref {
|
|
429
|
-
__wasmStage?:
|
|
442
|
+
__wasmStage?: BehaviorRuntime | null;
|
|
430
443
|
__entity?: {
|
|
431
444
|
runtimeHandle?: number;
|
|
432
445
|
} | null;
|
|
@@ -439,21 +452,24 @@ interface WasmSnapshotBackref {
|
|
|
439
452
|
*/
|
|
440
453
|
declare function readBehaviorSnapshot(ref: object): StageBehaviorSnapshot | null;
|
|
441
454
|
/**
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* that behavior systems call so descriptors stay runtime-agnostic.
|
|
455
|
+
* Runtime surface behavior systems rely on. `WasmStageRuntime` is the real
|
|
456
|
+
* wasm-backed implementation; `MockBehaviorRuntime` (see
|
|
457
|
+
* `./mock-behavior-runtime`) implements the same contract for unit tests, so
|
|
458
|
+
* descriptors stay runtime-agnostic.
|
|
447
459
|
*/
|
|
448
|
-
interface
|
|
460
|
+
interface BehaviorRuntime {
|
|
449
461
|
getPose(handle: number, out?: StagePose): StagePose | null;
|
|
462
|
+
setPosition(handle: number, x: number, y: number, z: number): boolean;
|
|
463
|
+
setRotation(handle: number, x: number, y: number, z: number, w: number): boolean;
|
|
450
464
|
writeInputAxes(handle: number, axisA: number, axisB: number): boolean;
|
|
451
465
|
writeInputLook(handle: number, yawDelta: number, pitchDelta: number): boolean;
|
|
466
|
+
/** Write reserved input slots (thruster world-space vector X/Y). */
|
|
467
|
+
writeInputReserved(handle: number, reservedA: number, reservedB: number): boolean;
|
|
452
468
|
writeInputButton(handle: number, buttonMask: number, pressed: boolean): boolean;
|
|
453
469
|
/** Read the per-slot behavior snapshot written at the end of the previous step. */
|
|
454
470
|
readSnapshot(handle: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;
|
|
455
471
|
attachThruster(handle: number, opts: StageThrusterOptions): boolean;
|
|
456
|
-
setThrusterInput(handle: number, thrust: number, rotate: number): void;
|
|
472
|
+
setThrusterInput(handle: number, thrust: number, rotate: number, vectorX?: number, vectorY?: number): void;
|
|
457
473
|
attachTopDown(handle: number, opts: StageTopDownOptions): boolean;
|
|
458
474
|
setTopDownInput(handle: number, moveX: number, moveY: number): void;
|
|
459
475
|
attachShooter2D(handle: number, opts: StageShooter2DOptions): boolean;
|
|
@@ -486,20 +502,292 @@ interface WasmStageRuntimeOptions {
|
|
|
486
502
|
initialCapacity?: number;
|
|
487
503
|
gravity?: readonly [number, number, number];
|
|
488
504
|
imports?: WebAssembly.Imports;
|
|
505
|
+
/**
|
|
506
|
+
* Custom wasm source. Defaults to the `zylem_runtime.wasm` bundled with
|
|
507
|
+
* `@zylem/runtime`.
|
|
508
|
+
*/
|
|
509
|
+
source?: RequestInfo | URL | ArrayBuffer | Uint8Array;
|
|
510
|
+
}
|
|
511
|
+
type StageEventTypeValue = (typeof StageEventType)[keyof typeof StageEventType];
|
|
512
|
+
/** One decoded event drained from the runtime's per-step event buffer. */
|
|
513
|
+
interface StageEvent {
|
|
514
|
+
type: StageEventTypeValue;
|
|
515
|
+
primarySlot: number | null;
|
|
516
|
+
secondarySlot: number | null;
|
|
517
|
+
payload: [number, number, number];
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Decoded view of one entity's slot in the unified render buffer.
|
|
521
|
+
*
|
|
522
|
+
* Mirrors the `STAGE_RENDER_STRIDE` (12-float) packing documented in
|
|
523
|
+
* `runtime/stage/render.rs`:
|
|
524
|
+
* `[0..3]` position, `[3..7]` rotation xyzw, `[7]` uniform scale,
|
|
525
|
+
* `[8..12]` custom0..custom3 (per-behavior shading hints).
|
|
526
|
+
*/
|
|
527
|
+
interface StageRenderSlot {
|
|
528
|
+
position: [number, number, number];
|
|
529
|
+
rotation: [number, number, number, number];
|
|
530
|
+
scale: number;
|
|
531
|
+
custom: [number, number, number, number];
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Read a single entity slot out of a unified-Stage render buffer view.
|
|
535
|
+
*
|
|
536
|
+
* @param view The `Float32Array` over wasm memory (e.g. `WasmStageRuntime.render`).
|
|
537
|
+
* @param slot The entity's wasm slot id (its `runtimeHandle`).
|
|
538
|
+
* @param out Optional target object to write into (avoids per-call allocation).
|
|
539
|
+
* @returns The decoded slot, or `null` when the slot is out of range.
|
|
540
|
+
*/
|
|
541
|
+
declare function readStageRenderSlot(view: Float32Array, slot: number, out?: StageRenderSlot): StageRenderSlot | null;
|
|
542
|
+
interface StageBodyConfig {
|
|
543
|
+
kind: StageBodyKindValue;
|
|
544
|
+
position: readonly [number, number, number];
|
|
545
|
+
rotation: readonly [number, number, number, number];
|
|
546
|
+
linearDamping: number;
|
|
547
|
+
angularDamping: number;
|
|
548
|
+
gravityScale: number;
|
|
549
|
+
canSleep: boolean;
|
|
550
|
+
ccdEnabled: boolean;
|
|
551
|
+
lockRotation: readonly [boolean, boolean, boolean];
|
|
552
|
+
lockTranslation: readonly [boolean, boolean, boolean];
|
|
553
|
+
}
|
|
554
|
+
type StageColliderShape = {
|
|
555
|
+
type: 'box';
|
|
556
|
+
halfExtents: readonly [number, number, number];
|
|
557
|
+
} | {
|
|
558
|
+
type: 'sphere';
|
|
559
|
+
radius: number;
|
|
560
|
+
} | {
|
|
561
|
+
type: 'capsule';
|
|
562
|
+
halfHeight: number;
|
|
563
|
+
radius: number;
|
|
564
|
+
} | {
|
|
565
|
+
type: 'cylinder';
|
|
566
|
+
halfHeight: number;
|
|
567
|
+
radius: number;
|
|
568
|
+
} | {
|
|
569
|
+
type: 'cone';
|
|
570
|
+
halfHeight: number;
|
|
571
|
+
radius: number;
|
|
572
|
+
} | {
|
|
573
|
+
type: 'convexHull';
|
|
574
|
+
vertices: Float32Array;
|
|
575
|
+
} | {
|
|
576
|
+
type: 'trimesh';
|
|
577
|
+
vertices: Float32Array;
|
|
578
|
+
indices: Uint32Array;
|
|
579
|
+
} | {
|
|
580
|
+
type: 'heightfield';
|
|
581
|
+
rows: number;
|
|
582
|
+
cols: number;
|
|
583
|
+
scale: readonly [number, number, number];
|
|
584
|
+
heights: Float32Array;
|
|
585
|
+
};
|
|
586
|
+
interface StageColliderConfig {
|
|
587
|
+
shape: StageColliderShape;
|
|
588
|
+
offset: readonly [number, number, number];
|
|
589
|
+
friction: number;
|
|
590
|
+
restitution: number;
|
|
591
|
+
sensor: boolean;
|
|
592
|
+
/** Packed interaction-groups: high 16 bits = membership, low 16 bits = filter. */
|
|
593
|
+
collisionGroups: number;
|
|
594
|
+
}
|
|
595
|
+
/** Result of a physics raycast against the stage. */
|
|
596
|
+
interface StageRaycastHit {
|
|
597
|
+
slot: number;
|
|
598
|
+
distance: number;
|
|
599
|
+
normal: [number, number, number];
|
|
600
|
+
}
|
|
601
|
+
/** Body introspection payload for debug tooling. */
|
|
602
|
+
interface StageBodyInfo {
|
|
603
|
+
bodyType: number;
|
|
604
|
+
mass: number;
|
|
605
|
+
isSleeping: boolean;
|
|
606
|
+
isEnabled: boolean;
|
|
607
|
+
linearVelocity: [number, number, number];
|
|
489
608
|
}
|
|
609
|
+
/** Line-list wireframe for physics debug rendering. */
|
|
610
|
+
interface StageDebugRender {
|
|
611
|
+
/** `[x, y, z]` per vertex, two vertices per line. */
|
|
612
|
+
vertices: Float32Array;
|
|
613
|
+
/** RGBA per vertex. */
|
|
614
|
+
colors: Float32Array;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Owns the wasm instance plus the live float-views over its render / event /
|
|
618
|
+
* pose / scratch buffers. One instance per logical stage; each stage gets
|
|
619
|
+
* its own `WebAssembly.Instance` so the singleton inside `stage_ffi.rs`
|
|
620
|
+
* stays single-stage scoped (today's `thread_local!` contract).
|
|
621
|
+
*/
|
|
622
|
+
declare class WasmStageRuntime implements BehaviorRuntime {
|
|
623
|
+
readonly exports: StageWasmExports;
|
|
624
|
+
private readonly memory;
|
|
625
|
+
private renderView;
|
|
626
|
+
private inputView;
|
|
627
|
+
private snapshotView;
|
|
628
|
+
private eventView;
|
|
629
|
+
private poseView;
|
|
630
|
+
private vec3View;
|
|
631
|
+
private queryView;
|
|
632
|
+
private scratchView;
|
|
633
|
+
constructor(exports: StageWasmExports, options?: WasmStageRuntimeOptions);
|
|
634
|
+
/** Recreate typed views over wasm memory. Call after step() or whenever memory may have grown. */
|
|
635
|
+
refreshViews(): void;
|
|
636
|
+
/** Step the simulation by `dt` seconds. Refreshes views afterwards. */
|
|
637
|
+
step(dt: number): number;
|
|
638
|
+
dispose(): void;
|
|
639
|
+
get tickCount(): number;
|
|
640
|
+
get activeCount(): number;
|
|
641
|
+
setGravity(x: number, y: number, z: number): void;
|
|
642
|
+
createEntity(): number;
|
|
643
|
+
destroyEntity(slot: number): boolean;
|
|
644
|
+
attachBody(slot: number, config: StageBodyConfig): boolean;
|
|
645
|
+
addCollider(slot: number, config: StageColliderConfig): boolean;
|
|
646
|
+
private stageScratch;
|
|
647
|
+
private stageScratchIndices;
|
|
648
|
+
getPose(slot: number, out?: StagePose): StagePose | null;
|
|
649
|
+
setPosition(slot: number, x: number, y: number, z: number): boolean;
|
|
650
|
+
setRotation(slot: number, x: number, y: number, z: number, w: number): boolean;
|
|
651
|
+
setLinearVelocity(slot: number, x: number, y: number, z: number): boolean;
|
|
652
|
+
getLinearVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null;
|
|
653
|
+
setAngularVelocity(slot: number, x: number, y: number, z: number): boolean;
|
|
654
|
+
getAngularVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null;
|
|
655
|
+
applyImpulse(slot: number, x: number, y: number, z: number): boolean;
|
|
656
|
+
/** Cast a ray against the physics world. Returns the closest hit or `null`. */
|
|
657
|
+
castRay(origin: readonly [number, number, number], dir: readonly [number, number, number], maxDistance: number, solidOnly?: boolean): StageRaycastHit | null;
|
|
658
|
+
/** Body introspection for debug tooling. */
|
|
659
|
+
getBodyInfo(slot: number): StageBodyInfo | null;
|
|
660
|
+
/** Wireframe debug render of every collider (all shapes). */
|
|
661
|
+
getDebugRender(): StageDebugRender | null;
|
|
662
|
+
/** Read-only view over the render buffer; one slot occupies {@link STAGE_RENDER_STRIDE} floats. */
|
|
663
|
+
get render(): Float32Array;
|
|
664
|
+
get renderStride(): number;
|
|
665
|
+
/**
|
|
666
|
+
* Decode a single entity slot from the live render buffer. Convenience
|
|
667
|
+
* wrapper over {@link readStageRenderSlot} bound to this runtime's view.
|
|
668
|
+
*/
|
|
669
|
+
readRenderSlot(slot: number, out?: StageRenderSlot): StageRenderSlot | null;
|
|
670
|
+
/** Drain the wasm event buffer into a fresh array of typed events. */
|
|
671
|
+
drainEvents(): StageEvent[];
|
|
672
|
+
/** Writable view over the slot-indexed input buffer ({@link STAGE_INPUT_STRIDE} floats/slot). */
|
|
673
|
+
get input(): Float32Array;
|
|
674
|
+
get inputStride(): number;
|
|
675
|
+
/** Read-only view over the per-slot behavior snapshot buffer ({@link STAGE_SNAPSHOT_STRIDE} floats/slot). */
|
|
676
|
+
get snapshot(): Float32Array;
|
|
677
|
+
get snapshotStride(): number;
|
|
678
|
+
/**
|
|
679
|
+
* Write the primary movement axes for a slot into the batched input
|
|
680
|
+
* buffer and mark the slot dirty. Field-scoped (doesn't touch look
|
|
681
|
+
* deltas or buttons) so multiple behaviors composed on one entity can
|
|
682
|
+
* each write their part.
|
|
683
|
+
*/
|
|
684
|
+
writeInputAxes(slot: number, axisA: number, axisB: number): boolean;
|
|
685
|
+
/** Write the look deltas (first-person yaw/pitch) for a slot. */
|
|
686
|
+
writeInputLook(slot: number, yawDelta: number, pitchDelta: number): boolean;
|
|
687
|
+
/** Write reserved input slots (thruster world-space vector X/Y). */
|
|
688
|
+
writeInputReserved(slot: number, reservedA: number, reservedB: number): boolean;
|
|
689
|
+
/**
|
|
690
|
+
* Set or clear one button bit ({@link STAGE_INPUT_BUTTON_JUMP} /
|
|
691
|
+
* {@link STAGE_INPUT_BUTTON_RUN}) in a slot's input bitmask.
|
|
692
|
+
*/
|
|
693
|
+
writeInputButton(slot: number, buttonMask: number, pressed: boolean): boolean;
|
|
694
|
+
/**
|
|
695
|
+
* Decode a slot's behavior snapshot from the buffer written at the end of
|
|
696
|
+
* the previous step. Returns `null` when the slot has no behavior data.
|
|
697
|
+
*/
|
|
698
|
+
readSnapshot(slot: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;
|
|
699
|
+
get queryScratch(): Float32Array;
|
|
700
|
+
attachCooldown(slot: number): boolean;
|
|
701
|
+
registerCooldown(slot: number, id: number, durationSeconds: number, immediate?: boolean): boolean;
|
|
702
|
+
fireCooldown(slot: number, id: number): boolean;
|
|
703
|
+
resetCooldown(slot: number, id: number): boolean;
|
|
704
|
+
cooldownRemaining(slot: number, id: number): number;
|
|
705
|
+
attachWorldBoundary(slot: number, dim: StageBoundaryDimValue, bounds: StageWorldBoundaryOptions): boolean;
|
|
706
|
+
queryWorldBoundary(slot: number): {
|
|
707
|
+
hits: number;
|
|
708
|
+
clamped: [number, number, number];
|
|
709
|
+
} | null;
|
|
710
|
+
attachScreenWrap(slot: number, opts: StageScreenWrapOptions): boolean;
|
|
711
|
+
queryScreenWrap(slot: number): {
|
|
712
|
+
fsm: number;
|
|
713
|
+
lastWrappedAxes: number;
|
|
714
|
+
} | null;
|
|
715
|
+
attachRicochet(slot: number, dim: StageRicochetDimValue, opts: StageRicochetOptions): boolean;
|
|
716
|
+
queryRicochet(slot: number): {
|
|
717
|
+
bounces: number;
|
|
718
|
+
lastKind: number;
|
|
719
|
+
} | null;
|
|
720
|
+
attachThruster(slot: number, opts: StageThrusterOptions): boolean;
|
|
721
|
+
setThrusterInput(slot: number, thrust: number, turn: number, vectorX?: number, vectorY?: number): void;
|
|
722
|
+
queryThruster(slot: number): {
|
|
723
|
+
headingRad: number;
|
|
724
|
+
speed: number;
|
|
725
|
+
} | null;
|
|
726
|
+
attachTopDown(slot: number, opts: StageTopDownOptions): boolean;
|
|
727
|
+
setTopDownInput(slot: number, axisA: number, axisB: number): void;
|
|
728
|
+
attachJumper2D(slot: number, opts: StageJumper2DOptions): boolean;
|
|
729
|
+
setJumper2DInput(slot: number, jumpPressed: boolean): void;
|
|
730
|
+
queryJumper2D(slot: number): {
|
|
731
|
+
grounded: boolean;
|
|
732
|
+
jumpCount: number;
|
|
733
|
+
coyote: number;
|
|
734
|
+
jumpBuffer: number;
|
|
735
|
+
} | null;
|
|
736
|
+
attachJumper3D(slot: number, opts: StageJumper3DOptions): boolean;
|
|
737
|
+
setJumper3DInput(slot: number, jump: boolean): void;
|
|
738
|
+
queryJumper3D(slot: number): {
|
|
739
|
+
grounded: boolean;
|
|
740
|
+
jumpCount: number;
|
|
741
|
+
verticalVelocity: number;
|
|
742
|
+
} | null;
|
|
743
|
+
attachShooter2D(slot: number, opts: StageShooter2DOptions): boolean;
|
|
744
|
+
fireShooter2D(slot: number, x: number, y: number, z: number, yaw: number): boolean;
|
|
745
|
+
queryShooter2D(slot: number): {
|
|
746
|
+
cooldown: number;
|
|
747
|
+
firedCount: number;
|
|
748
|
+
} | null;
|
|
749
|
+
attachPlatformer3D(slot: number, opts: StagePlatformer3DOptions): boolean;
|
|
750
|
+
setPlatformer3DInputAxes(slot: number, moveX: number, moveZ: number): void;
|
|
751
|
+
setPlatformer3DInputButtons(slot: number, jump: boolean, run: boolean): void;
|
|
752
|
+
queryPlatformer3D(slot: number): {
|
|
753
|
+
grounded: boolean;
|
|
754
|
+
jumpCount: number;
|
|
755
|
+
fsmState: number;
|
|
756
|
+
speed: number;
|
|
757
|
+
} | null;
|
|
758
|
+
attachPlatformer2D(slot: number, opts: StagePlatformer2DOptions): boolean;
|
|
759
|
+
setPlatformer2DInputAxes(slot: number, moveX: number): void;
|
|
760
|
+
setPlatformer2DInputButtons(slot: number, jump: boolean, run: boolean): void;
|
|
761
|
+
queryPlatformer2D(slot: number): {
|
|
762
|
+
grounded: boolean;
|
|
763
|
+
jumpCount: number;
|
|
764
|
+
fsmState: number;
|
|
765
|
+
verticalVelocity: number;
|
|
766
|
+
} | null;
|
|
767
|
+
attachFirstPerson(slot: number, opts: StageFirstPersonOptions): boolean;
|
|
768
|
+
setFirstPersonInput(slot: number, input: StageFirstPersonInput): void;
|
|
769
|
+
queryFirstPerson(slot: number): {
|
|
770
|
+
yaw: number;
|
|
771
|
+
pitch: number;
|
|
772
|
+
speed: number;
|
|
773
|
+
eyeHeight: number;
|
|
774
|
+
} | null;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Load the bundled `@zylem/runtime` wasm (or a custom `source`), instantiate
|
|
778
|
+
* it, and construct a `WasmStageRuntime` around the exports.
|
|
779
|
+
*/
|
|
780
|
+
declare function createWasmStageRuntime(options?: WasmStageRuntimeOptions): Promise<WasmStageRuntime>;
|
|
490
781
|
|
|
491
782
|
/**
|
|
492
783
|
* Structural stand-in for the engine world wrapper. The engine's world
|
|
493
|
-
* delegate exposes
|
|
494
|
-
* only rely on this slice.
|
|
784
|
+
* delegate exposes an entity lookup map; behaviors only rely on this slice.
|
|
495
785
|
*
|
|
496
786
|
* The map value is intentionally `unknown` (not the `GameEntity` stub class):
|
|
497
787
|
* the engine's concrete entity class is a different nominal type, and systems
|
|
498
788
|
* that iterate the map narrow entities themselves.
|
|
499
789
|
*/
|
|
500
790
|
interface ZylemWorld {
|
|
501
|
-
/** Raw Rapier physics world (present when the Rapier path is active). */
|
|
502
|
-
world?: World;
|
|
503
791
|
collisionMap?: Map<string, unknown>;
|
|
504
792
|
}
|
|
505
793
|
|
|
@@ -553,7 +841,7 @@ interface BehaviorSystemContext {
|
|
|
553
841
|
/** Host scene wrapper (engine-specific); behaviors only call `add`/`remove`-style methods on it. */
|
|
554
842
|
scene: any;
|
|
555
843
|
/** Wasm-driven Stage runtime; omitted when the stage has no wasm module. */
|
|
556
|
-
wasmStage?:
|
|
844
|
+
wasmStage?: BehaviorRuntime | null;
|
|
557
845
|
/**
|
|
558
846
|
* Returns live behavior links for a descriptor key.
|
|
559
847
|
* O(1) lookup into a pre-built stage index.
|
|
@@ -577,4 +865,4 @@ interface BehaviorSystemContext {
|
|
|
577
865
|
*/
|
|
578
866
|
type BehaviorSystemFactory<T extends BehaviorSystem = BehaviorSystem> = (stage: BehaviorSystemContext) => T;
|
|
579
867
|
|
|
580
|
-
export { type
|
|
868
|
+
export { type WasmSnapshotBackref as $, type StageJumper2DOptions as A, type BaseBehaviorHandle as B, type CreateEntityFn as C, type DefineBehaviorConfig as D, type StageJumper3DOptions as E, type StagePlatformer2DOptions as F, GameEntity as G, type StagePlatformer3DOptions as H, type StagePose as I, type StageRaycastHit as J, type StageRenderSlot as K, StageRicochetDim as L, type StageRicochetDimValue as M, type StageRicochetOptions as N, StageRicochetReflection as O, type StageRicochetReflectionValue as P, type StageScreenWrapOptions as Q, type StageShooter2DOptions as R, STAGE_INPUT_BUTTON_JUMP as S, type StageThrusterOptions as T, type StageTopDownOptions as U, StageTopDownPlane as V, type StageTopDownPlaneValue as W, type StageWorldBoundaryOptions as X, type TransformState as Y, type VelocityIntent as Z, type VelocityIntentMode as _, type BehaviorDescriptor as a, WasmStageRuntime as a0, type WasmStageRuntimeOptions as a1, createTransformStore as a2, createWasmStageRuntime as a3, defineBehavior as a4, readBehaviorSnapshot as a5, readStageRenderSlot as a6, type BehaviorEntityLink as b, type BehaviorHandle as c, type BehaviorRef as d, type BehaviorRuntime as e, type BehaviorSystem as f, type BehaviorSystemContext as g, type BehaviorSystemFactory as h, type GameEntityOptions as i, STAGE_INPUT_BUTTON_RUN as j, STAGE_INVALID_SLOT as k, type StageBehaviorSnapshot as l, type StageBodyConfig as m, type StageBodyInfo as n, StageBodyKind as o, type StageBodyKindValue as p, StageBoundaryDim as q, type StageBoundaryDimValue as r, type StageColliderConfig as s, type StageColliderShape as t, type StageDebugRender as u, type StageEvent as v, StageEventType as w, type StageEventTypeValue as x, type StageFirstPersonInput as y, type StageFirstPersonOptions as z };
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createBounds2DRect
|
|
3
|
-
|
|
4
|
-
} from "./chunk-KDY5N6J4.js";
|
|
2
|
+
createBounds2DRect
|
|
3
|
+
} from "./chunk-OPZ2LVS2.js";
|
|
5
4
|
import {
|
|
6
5
|
SyncStateMachine,
|
|
7
|
-
|
|
8
|
-
} from "./chunk-
|
|
6
|
+
import_typescript_fsm
|
|
7
|
+
} from "./chunk-AS3HR7AS.js";
|
|
9
8
|
import {
|
|
10
9
|
defineBehavior
|
|
11
10
|
} from "./chunk-EZNCCO4L.js";
|
|
@@ -36,33 +35,33 @@ var ScreenWrapFSM = class {
|
|
|
36
35
|
"center" /* Center */,
|
|
37
36
|
[
|
|
38
37
|
// From Center
|
|
39
|
-
t("center" /* Center */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
40
|
-
t("center" /* Center */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
41
|
-
t("center" /* Center */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
42
|
-
t("center" /* Center */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */),
|
|
38
|
+
(0, import_typescript_fsm.t)("center" /* Center */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
39
|
+
(0, import_typescript_fsm.t)("center" /* Center */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
40
|
+
(0, import_typescript_fsm.t)("center" /* Center */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
41
|
+
(0, import_typescript_fsm.t)("center" /* Center */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */),
|
|
43
42
|
// From NearEdge to Wrapped
|
|
44
|
-
t("near-edge-left" /* NearEdgeLeft */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
45
|
-
t("near-edge-right" /* NearEdgeRight */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
46
|
-
t("near-edge-top" /* NearEdgeTop */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
47
|
-
t("near-edge-bottom" /* NearEdgeBottom */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
43
|
+
(0, import_typescript_fsm.t)("near-edge-left" /* NearEdgeLeft */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
44
|
+
(0, import_typescript_fsm.t)("near-edge-right" /* NearEdgeRight */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
45
|
+
(0, import_typescript_fsm.t)("near-edge-top" /* NearEdgeTop */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
46
|
+
(0, import_typescript_fsm.t)("near-edge-bottom" /* NearEdgeBottom */, "wrap" /* Wrap */, "wrapped" /* Wrapped */),
|
|
48
47
|
// From NearEdge back to Center
|
|
49
|
-
t("near-edge-left" /* NearEdgeLeft */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
50
|
-
t("near-edge-right" /* NearEdgeRight */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
51
|
-
t("near-edge-top" /* NearEdgeTop */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
52
|
-
t("near-edge-bottom" /* NearEdgeBottom */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
48
|
+
(0, import_typescript_fsm.t)("near-edge-left" /* NearEdgeLeft */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
49
|
+
(0, import_typescript_fsm.t)("near-edge-right" /* NearEdgeRight */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
50
|
+
(0, import_typescript_fsm.t)("near-edge-top" /* NearEdgeTop */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
51
|
+
(0, import_typescript_fsm.t)("near-edge-bottom" /* NearEdgeBottom */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
53
52
|
// From Wrapped back to Center
|
|
54
|
-
t("wrapped" /* Wrapped */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
53
|
+
(0, import_typescript_fsm.t)("wrapped" /* Wrapped */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
55
54
|
// From Wrapped to NearEdge (landed near opposite edge)
|
|
56
|
-
t("wrapped" /* Wrapped */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
57
|
-
t("wrapped" /* Wrapped */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
58
|
-
t("wrapped" /* Wrapped */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
59
|
-
t("wrapped" /* Wrapped */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */),
|
|
55
|
+
(0, import_typescript_fsm.t)("wrapped" /* Wrapped */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
56
|
+
(0, import_typescript_fsm.t)("wrapped" /* Wrapped */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
57
|
+
(0, import_typescript_fsm.t)("wrapped" /* Wrapped */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
58
|
+
(0, import_typescript_fsm.t)("wrapped" /* Wrapped */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */),
|
|
60
59
|
// Self-transitions (no-ops for redundant events)
|
|
61
|
-
t("center" /* Center */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
62
|
-
t("near-edge-left" /* NearEdgeLeft */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
63
|
-
t("near-edge-right" /* NearEdgeRight */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
64
|
-
t("near-edge-top" /* NearEdgeTop */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
65
|
-
t("near-edge-bottom" /* NearEdgeBottom */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */)
|
|
60
|
+
(0, import_typescript_fsm.t)("center" /* Center */, "enter-center" /* EnterCenter */, "center" /* Center */),
|
|
61
|
+
(0, import_typescript_fsm.t)("near-edge-left" /* NearEdgeLeft */, "approach-left" /* ApproachLeft */, "near-edge-left" /* NearEdgeLeft */),
|
|
62
|
+
(0, import_typescript_fsm.t)("near-edge-right" /* NearEdgeRight */, "approach-right" /* ApproachRight */, "near-edge-right" /* NearEdgeRight */),
|
|
63
|
+
(0, import_typescript_fsm.t)("near-edge-top" /* NearEdgeTop */, "approach-top" /* ApproachTop */, "near-edge-top" /* NearEdgeTop */),
|
|
64
|
+
(0, import_typescript_fsm.t)("near-edge-bottom" /* NearEdgeBottom */, "approach-bottom" /* ApproachBottom */, "near-edge-bottom" /* NearEdgeBottom */)
|
|
66
65
|
]
|
|
67
66
|
);
|
|
68
67
|
}
|
|
@@ -130,41 +129,24 @@ var ScreenWrapSystem = class {
|
|
|
130
129
|
wrapRef.fsm = new ScreenWrapFSM();
|
|
131
130
|
}
|
|
132
131
|
const handle = gameEntity.runtimeHandle ?? -1;
|
|
133
|
-
if (this.wasmStage
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
132
|
+
if (!this.wasmStage || handle < 0) continue;
|
|
133
|
+
this.ensureWasmAttached(handle, options);
|
|
134
|
+
const pose = this.wasmStage.getPose(handle);
|
|
135
|
+
const query = this.wasmStage.queryScreenWrap(handle);
|
|
136
|
+
if (pose && query) {
|
|
137
|
+
const bounds = createBounds2DRect(options);
|
|
138
|
+
wrapRef.fsm.update(
|
|
139
|
+
{ x: pose.position[0], y: pose.position[1] },
|
|
140
|
+
{
|
|
141
|
+
minX: bounds.minX,
|
|
142
|
+
maxX: bounds.maxX,
|
|
143
|
+
minY: bounds.minY,
|
|
144
|
+
maxY: bounds.maxY,
|
|
145
|
+
edgeThreshold: options.edgeThreshold
|
|
146
|
+
},
|
|
147
|
+
query.lastWrappedAxes !== 0
|
|
148
|
+
);
|
|
152
149
|
}
|
|
153
|
-
if (!gameEntity.body) continue;
|
|
154
|
-
const wrapped = this.wrapEntity(gameEntity, options);
|
|
155
|
-
const pos = gameEntity.body.translation();
|
|
156
|
-
const bounds = createBounds2DRect(options);
|
|
157
|
-
wrapRef.fsm.update(
|
|
158
|
-
{ x: pos.x, y: pos.y },
|
|
159
|
-
{
|
|
160
|
-
minX: bounds.minX,
|
|
161
|
-
maxX: bounds.maxX,
|
|
162
|
-
minY: bounds.minY,
|
|
163
|
-
maxY: bounds.maxY,
|
|
164
|
-
edgeThreshold: options.edgeThreshold
|
|
165
|
-
},
|
|
166
|
-
wrapped
|
|
167
|
-
);
|
|
168
150
|
}
|
|
169
151
|
}
|
|
170
152
|
ensureWasmAttached(handle, options) {
|
|
@@ -178,17 +160,6 @@ var ScreenWrapSystem = class {
|
|
|
178
160
|
});
|
|
179
161
|
this.attachedRuntimeSlots.add(handle);
|
|
180
162
|
}
|
|
181
|
-
wrapEntity(entity, options) {
|
|
182
|
-
const body = entity.body;
|
|
183
|
-
if (!body) return false;
|
|
184
|
-
const pos = body.translation();
|
|
185
|
-
const bounds = createBounds2DRect(options);
|
|
186
|
-
const result = wrapPoint2D({ x: pos.x, y: pos.y }, bounds);
|
|
187
|
-
if (result.wrapped) {
|
|
188
|
-
body.setTranslation({ x: result.x, y: result.y, z: pos.z }, true);
|
|
189
|
-
}
|
|
190
|
-
return result.wrapped;
|
|
191
|
-
}
|
|
192
163
|
destroy(_ecs) {
|
|
193
164
|
this.attachedRuntimeSlots.clear();
|
|
194
165
|
}
|
|
@@ -205,4 +176,4 @@ export {
|
|
|
205
176
|
ScreenWrapFSM,
|
|
206
177
|
ScreenWrapBehavior
|
|
207
178
|
};
|
|
208
|
-
//# sourceMappingURL=chunk-
|
|
179
|
+
//# sourceMappingURL=chunk-2PAHQZZD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/screen-wrap/screen-wrap-fsm.ts","../src/lib/behaviors/screen-wrap/screen-wrap.descriptor.ts"],"sourcesContent":["/**\n * ScreenWrapFSM\n * \n * State machine for screen wrap behavior.\n * Reports position relative to bounds edges.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapState {\n\tCenter = 'center',\n\tNearEdgeLeft = 'near-edge-left',\n\tNearEdgeRight = 'near-edge-right',\n\tNearEdgeTop = 'near-edge-top',\n\tNearEdgeBottom = 'near-edge-bottom',\n\tWrapped = 'wrapped',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapEvent {\n\tEnterCenter = 'enter-center',\n\tApproachLeft = 'approach-left',\n\tApproachRight = 'approach-right',\n\tApproachTop = 'approach-top',\n\tApproachBottom = 'approach-bottom',\n\tWrap = 'wrap',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ScreenWrapFSM\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ScreenWrapFSM {\n\tmachine: SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>;\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>(\n\t\t\tScreenWrapState.Center,\n\t\t\t[\n\t\t\t\t// From Center\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t\t\n\t\t\t\t// From NearEdge to Wrapped\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\n\t\t\t\t// From NearEdge back to Center\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped back to Center\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped to NearEdge (landed near opposite edge)\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t]\n\t\t);\n\t}\n\n\tgetState(): ScreenWrapState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: ScreenWrapEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM based on entity position relative to bounds\n\t */\n\tupdate(position: { x: number; y: number }, bounds: {\n\t\tminX: number; maxX: number; minY: number; maxY: number;\n\t\tedgeThreshold: number;\n\t}, wrapped: boolean): void {\n\t\tconst { x, y } = position;\n\t\tconst { minX, maxX, minY, maxY, edgeThreshold } = bounds;\n\n\t\tif (wrapped) {\n\t\t\tthis.dispatch(ScreenWrapEvent.Wrap);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if near edges\n\t\tconst nearLeft = x < minX + edgeThreshold;\n\t\tconst nearRight = x > maxX - edgeThreshold;\n\t\tconst nearBottom = y < minY + edgeThreshold;\n\t\tconst nearTop = y > maxY - edgeThreshold;\n\n\t\tif (nearLeft) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachLeft);\n\t\t} else if (nearRight) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachRight);\n\t\t} else if (nearTop) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachTop);\n\t\t} else if (nearBottom) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachBottom);\n\t\t} else {\n\t\t\tthis.dispatch(ScreenWrapEvent.EnterCenter);\n\t\t}\n\t}\n}\n","/**\n * ScreenWrapBehavior\n * \n * When an entity exits the defined 2D bounds, it wraps around to the opposite edge.\n * Asteroids-style screen wrapping with FSM for edge detection.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { ScreenWrapFSM } from './screen-wrap-fsm';\nimport { createBounds2DRect } from '../shared/bounds-2d';\nimport type { BehaviorRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Screen wrap options (typed for entity.use() autocomplete)\n */\nexport interface ScreenWrapOptions {\n\t/** Width of the wrapping area (default: 20) */\n\twidth: number;\n\t/** Height of the wrapping area (default: 15) */\n\theight: number;\n\t/** Center X position (default: 0) */\n\tcenterX: number;\n\t/** Center Y position (default: 0) */\n\tcenterY: number;\n\t/** Distance from edge to trigger NearEdge state (default: 2) */\n\tedgeThreshold: number;\n}\n\nconst defaultOptions: ScreenWrapOptions = {\n\twidth: 20,\n\theight: 15,\n\tcenterX: 0,\n\tcenterY: 0,\n\tedgeThreshold: 2,\n};\n\nconst SCREEN_WRAP_BEHAVIOR_KEY = Symbol.for('zylem:behavior:screen-wrap');\n\n/**\n * ScreenWrapSystem - Wraps entities around 2D bounds\n *\n * The Rust `screen_wrap` Stage behavior owns the wrap; this system attaches\n * it and mirrors the queried state into the local FSM so handles can observe\n * edge/wrap states.\n */\nclass ScreenWrapSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(SCREEN_WRAP_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst wrapRef = link.ref as any;\n\t\t\tconst options = wrapRef.options as ScreenWrapOptions;\n\n\t\t\tif (!wrapRef.fsm) {\n\t\t\t\twrapRef.fsm = new ScreenWrapFSM();\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tconst pose = this.wasmStage.getPose(handle);\n\t\t\tconst query = this.wasmStage.queryScreenWrap(handle);\n\t\t\tif (pose && query) {\n\t\t\t\tconst bounds = createBounds2DRect(options);\n\t\t\t\twrapRef.fsm.update(\n\t\t\t\t\t{ x: pose.position[0], y: pose.position[1] },\n\t\t\t\t\t{\n\t\t\t\t\t\tminX: bounds.minX,\n\t\t\t\t\t\tmaxX: bounds.maxX,\n\t\t\t\t\t\tminY: bounds.minY,\n\t\t\t\t\t\tmaxY: bounds.maxY,\n\t\t\t\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t\t\t\t},\n\t\t\t\t\tquery.lastWrappedAxes !== 0,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ScreenWrapOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachScreenWrap(handle, {\n\t\t\twidth: options.width,\n\t\t\theight: options.height,\n\t\t\tcenterX: options.centerX,\n\t\t\tcenterY: options.centerY,\n\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * ScreenWrapBehavior - Wraps entities around 2D bounds\n * \n * @example\n * ```typescript\n * import { ScreenWrapBehavior } from \"@zylem/game-lib/behavior\";\n * \n * const ship = createSprite({ ... });\n * const wrapRef = ship.use(ScreenWrapBehavior, { width: 20, height: 15 });\n * \n * // Access FSM to observe edge state\n * const fsm = wrapRef.getFSM();\n * console.log(fsm?.getState()); // 'center', 'near-edge-left', 'wrapped', etc.\n * ```\n */\nexport const ScreenWrapBehavior = defineBehavior({\n\tname: 'screen-wrap',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ScreenWrapSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":";;;;;;;;;;;;AAaO,IAAK,kBAAL,kBAAKA,qBAAL;AACN,EAAAA,iBAAA,YAAS;AACT,EAAAA,iBAAA,kBAAe;AACf,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,oBAAiB;AACjB,EAAAA,iBAAA,aAAU;AANC,SAAAA;AAAA,GAAA;AAaL,IAAK,kBAAL,kBAAKC,qBAAL;AACN,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,kBAAe;AACf,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,oBAAiB;AACjB,EAAAA,iBAAA,UAAO;AANI,SAAAA;AAAA,GAAA;AAaL,IAAM,gBAAN,MAAoB;AAAA,EAC1B;AAAA,EAEA,cAAc;AACb,SAAK,UAAU,IAAI;AAAA,MAClB;AAAA,MACA;AAAA;AAAA,YAEC,yBAAE,uBAAwB,oCAA8B,mCAA4B;AAAA,YACpF,yBAAE,uBAAwB,sCAA+B,qCAA6B;AAAA,YACtF,yBAAE,uBAAwB,kCAA6B,iCAA2B;AAAA,YAClF,yBAAE,uBAAwB,wCAAgC,uCAA8B;AAAA;AAAA,YAGxF,yBAAE,qCAA8B,mBAAsB,uBAAuB;AAAA,YAC7E,yBAAE,uCAA+B,mBAAsB,uBAAuB;AAAA,YAC9E,yBAAE,mCAA6B,mBAAsB,uBAAuB;AAAA,YAC5E,yBAAE,yCAAgC,mBAAsB,uBAAuB;AAAA;AAAA,YAG/E,yBAAE,qCAA8B,kCAA6B,qBAAsB;AAAA,YACnF,yBAAE,uCAA+B,kCAA6B,qBAAsB;AAAA,YACpF,yBAAE,mCAA6B,kCAA6B,qBAAsB;AAAA,YAClF,yBAAE,yCAAgC,kCAA6B,qBAAsB;AAAA;AAAA,YAGrF,yBAAE,yBAAyB,kCAA6B,qBAAsB;AAAA;AAAA,YAG9E,yBAAE,yBAAyB,oCAA8B,mCAA4B;AAAA,YACrF,yBAAE,yBAAyB,sCAA+B,qCAA6B;AAAA,YACvF,yBAAE,yBAAyB,kCAA6B,iCAA2B;AAAA,YACnF,yBAAE,yBAAyB,wCAAgC,uCAA8B;AAAA;AAAA,YAGzF,yBAAE,uBAAwB,kCAA6B,qBAAsB;AAAA,YAC7E,yBAAE,qCAA8B,oCAA8B,mCAA4B;AAAA,YAC1F,yBAAE,uCAA+B,sCAA+B,qCAA6B;AAAA,YAC7F,yBAAE,mCAA6B,kCAA6B,iCAA2B;AAAA,YACvF,yBAAE,yCAAgC,wCAAgC,uCAA8B;AAAA,MACjG;AAAA,IACD;AAAA,EACD;AAAA,EAEA,WAA4B;AAC3B,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC9B;AAAA,EAEA,SAAS,OAA8B;AACtC,QAAI,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC5B,WAAK,QAAQ,aAAa,KAAK;AAAA,IAChC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,UAAoC,QAGxC,SAAwB;AAC1B,UAAM,EAAE,GAAG,EAAE,IAAI;AACjB,UAAM,EAAE,MAAM,MAAM,MAAM,MAAM,cAAc,IAAI;AAElD,QAAI,SAAS;AACZ,WAAK,SAAS,iBAAoB;AAClC;AAAA,IACD;AAGA,UAAM,WAAW,IAAI,OAAO;AAC5B,UAAM,YAAY,IAAI,OAAO;AAC7B,UAAM,aAAa,IAAI,OAAO;AAC9B,UAAM,UAAU,IAAI,OAAO;AAE3B,QAAI,UAAU;AACb,WAAK,SAAS,kCAA4B;AAAA,IAC3C,WAAW,WAAW;AACrB,WAAK,SAAS,oCAA6B;AAAA,IAC5C,WAAW,SAAS;AACnB,WAAK,SAAS,gCAA2B;AAAA,IAC1C,WAAW,YAAY;AACtB,WAAK,SAAS,sCAA8B;AAAA,IAC7C,OAAO;AACN,WAAK,SAAS,gCAA2B;AAAA,IAC1C;AAAA,EACD;AACD;;;ACjGA,IAAM,iBAAoC;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe;AAChB;AAEA,IAAM,2BAA2B,uBAAO,IAAI,4BAA4B;AASxE,IAAM,mBAAN,MAAiD;AAAA,EAGhD,YACS,WACA,kBACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD,uBAAuB,oBAAI,IAAY;AAAA,EAO/C,OAAO,MAAe,QAAsB;AAC3C,UAAM,QAAQ,KAAK,mBAAmB,wBAAwB;AAC9D,QAAI,CAAC,MAAO;AAEZ,eAAW,QAAQ,OAAO;AACzB,YAAM,aAAa,KAAK;AACxB,YAAM,UAAU,KAAK;AACrB,YAAM,UAAU,QAAQ;AAExB,UAAI,CAAC,QAAQ,KAAK;AACjB,gBAAQ,MAAM,IAAI,cAAc;AAAA,MACjC;AAEA,YAAM,SAAU,WAAW,iBAAiB;AAC5C,UAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AAEnC,WAAK,mBAAmB,QAAQ,OAAO;AACvC,YAAM,OAAO,KAAK,UAAU,QAAQ,MAAM;AAC1C,YAAM,QAAQ,KAAK,UAAU,gBAAgB,MAAM;AACnD,UAAI,QAAQ,OAAO;AAClB,cAAM,SAAS,mBAAmB,OAAO;AACzC,gBAAQ,IAAI;AAAA,UACX,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,EAAE;AAAA,UAC3C;AAAA,YACC,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,eAAe,QAAQ;AAAA,UACxB;AAAA,UACA,MAAM,oBAAoB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,mBAAmB,QAAgB,SAAkC;AAC5E,QAAI,CAAC,KAAK,aAAa,KAAK,qBAAqB,IAAI,MAAM,EAAG;AAC9D,SAAK,UAAU,iBAAiB,QAAQ;AAAA,MACvC,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,eAAe,QAAQ;AAAA,IACxB,CAAC;AACD,SAAK,qBAAqB,IAAI,MAAM;AAAA,EACrC;AAAA,EAEA,QAAQ,MAAqB;AAC5B,SAAK,qBAAqB,MAAM;AAAA,EACjC;AACD;AAiBO,IAAM,qBAAqB,eAAe;AAAA,EAChD,MAAM;AAAA,EACN;AAAA,EACA,eAAe,CAAC,QACf,IAAI,iBAAiB,IAAI,aAAa,MAAM,IAAI,gBAAgB;AAClE,CAAC;","names":["ScreenWrapState","ScreenWrapEvent"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getEntityFacingAngle2D,
|
|
3
|
+
resolveAim2D
|
|
4
|
+
} from "./chunk-TBUKJKY6.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/coordinators/shared/shooter-fire.ts
|
|
7
|
+
function fireShooter2DIfRequested(entity, shooter, stage, input, aim) {
|
|
8
|
+
if (!input.shootPressed && !input.shootHeld) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const sourcePosition = entity.body?.translation();
|
|
12
|
+
if (!sourcePosition) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const resolved = aim ?? resolveAim2D(input.aimX, input.aimY, getEntityFacingAngle2D(entity));
|
|
16
|
+
void shooter.fire({
|
|
17
|
+
source: entity,
|
|
18
|
+
stage,
|
|
19
|
+
target: {
|
|
20
|
+
x: sourcePosition.x + resolved.direction.x,
|
|
21
|
+
y: sourcePosition.y + resolved.direction.y
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
fireShooter2DIfRequested
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=chunk-52FJIDGL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/coordinators/shared/shooter-fire.ts"],"sourcesContent":["import type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../../behaviors/shooter-2d/shooter-2d.descriptor';\nimport {\n\tgetEntityFacingAngle2D,\n\tresolveAim2D,\n\ttype ResolvedAim2D,\n} from './top-down-aim';\n\n/**\n * Aim + fire input fields shared by the 2D shooter coordinators\n * (top-down-shooter, multidirectional-space-shooter).\n */\nexport interface Shooter2DAimFireInput {\n\taimX: number;\n\taimY: number;\n\tshootPressed: boolean;\n\tshootHeld: boolean;\n}\n\n/**\n * Fire the entity's Shooter2D behavior when the input requests it.\n *\n * Resolves the 2D aim (explicit aim axes, falling back to the entity's\n * current facing) and fires toward a point one unit along the aim direction.\n * Pass a pre-resolved `aim` to avoid recomputing when the coordinator already\n * resolved it for rotation.\n *\n * @returns true when a fire attempt was issued\n */\nexport function fireShooter2DIfRequested(\n\tentity: Shooter2DSourceEntity,\n\tshooter: Shooter2DHandle,\n\tstage: Shooter2DStageLike,\n\tinput: Shooter2DAimFireInput,\n\taim?: ResolvedAim2D,\n): boolean {\n\tif (!input.shootPressed && !input.shootHeld) {\n\t\treturn false;\n\t}\n\n\tconst sourcePosition = entity.body?.translation();\n\tif (!sourcePosition) {\n\t\treturn false;\n\t}\n\n\tconst resolved =\n\t\taim ?? resolveAim2D(input.aimX, input.aimY, getEntityFacingAngle2D(entity));\n\n\tvoid shooter.fire({\n\t\tsource: entity,\n\t\tstage,\n\t\ttarget: {\n\t\t\tx: sourcePosition.x + resolved.direction.x,\n\t\t\ty: sourcePosition.y + resolved.direction.y,\n\t\t},\n\t});\n\treturn true;\n}\n"],"mappings":";;;;;;AAgCO,SAAS,yBACf,QACA,SACA,OACA,OACA,KACU;AACV,MAAI,CAAC,MAAM,gBAAgB,CAAC,MAAM,WAAW;AAC5C,WAAO;AAAA,EACR;AAEA,QAAM,iBAAiB,OAAO,MAAM,YAAY;AAChD,MAAI,CAAC,gBAAgB;AACpB,WAAO;AAAA,EACR;AAEA,QAAM,WACL,OAAO,aAAa,MAAM,MAAM,MAAM,MAAM,uBAAuB,MAAM,CAAC;AAE3E,OAAK,QAAQ,KAAK;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,MACP,GAAG,eAAe,IAAI,SAAS,UAAU;AAAA,MACzC,GAAG,eAAe,IAAI,SAAS,UAAU;AAAA,IAC1C;AAAA,EACD,CAAC;AACD,SAAO;AACR;","names":[]}
|