@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts","../src/lib/behaviors/destructible-3d/index.ts"],"sourcesContent":["import {\n\tDestructibleMesh,\n\tFractureOptions as PinataFractureOptions,\n} from '@dgreenheck/three-pinata';\nimport {\n\tBox3,\n\tBufferAttribute,\n\tBufferGeometry,\n\tGroup,\n\tMatrix4,\n\tQuaternion,\n\tVector2,\n\tVector3,\n\ttype Material,\n\ttype Mesh,\n\ttype Object3D,\n} from 'three';\n\nimport * as Comlink from 'comlink';\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { CreateEntityFn, GameEntity } from '../../entities/entity';\n\nimport {\n\tbuildFractureGeometryCacheKey,\n\tbuildNormalizedFractureSourceGeometry,\n\tbufferGeometryToPlain,\n\ttype DestructiblePrebakeWorkerAPI,\n\tpinataFractureOptionsToPlain,\n\tplainWorkerResultToTemplateParts,\n} from '../../destructible-prebake';\n\nexport type FractureOptionsInput =\n\tNonNullable<ConstructorParameters<typeof PinataFractureOptions>[0]>;\n\nexport type Destructible3DFragmentColliderShape =\n\t| 'convexHull'\n\t| 'cuboid'\n\t| 'trimesh';\n\nexport interface Destructible3DColliderOptions {\n\tshape?: Destructible3DFragmentColliderShape;\n\tsensor?: boolean;\n\tcollisionGroups?: number;\n}\n\n/**\n * Plain-data collider definition produced for fracture fragments. The host\n * (game-lib) translates these into simulation colliders when it attaches\n * fragment entities to the WASM stage.\n */\nexport interface Destructible3DFragmentColliderDefinition {\n\tshape:\n\t\t| { type: 'convexHull'; vertices: Float32Array }\n\t\t| { type: 'trimesh'; vertices: Float32Array; indices: Uint32Array }\n\t\t| { type: 'box'; halfExtents: [number, number, number] };\n\toffset?: [number, number, number];\n\tsensor: boolean;\n\tcollisionGroups?: number;\n}\n\n/** Plain-data body definition produced for independent fracture fragments. */\nexport interface Destructible3DFragmentBodyDefinition {\n\tkind: 'dynamic';\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n\tcanSleep: boolean;\n\tccdEnabled: boolean;\n}\n\nexport interface Destructible3DFragmentPhysicsOptions {\n\tmode?: 'compound' | 'independent';\n\tinheritSourceVelocity?: boolean;\n\toutwardVelocity?: number;\n\tangularVelocity?: number;\n}\n\nexport interface Destructible3DBehaviorOptions {\n\tfractureOptions?: FractureOptionsInput | PinataFractureOptions;\n\tinnerMaterial?: Material | null;\n\tcollider?: Destructible3DColliderOptions;\n\tfragmentPhysics?: Destructible3DFragmentPhysicsOptions;\n\t/**\n\t * When set, {@link Destructible3DHandle.prebakeAsync} runs Voronoi fracture\n\t * in a Web Worker (see `destructible-prebake-worker` bundle).\n\t */\n\tprebakeWorkerUrl?: URL | string;\n}\n\nexport interface Destructible3DHandle {\n\tfracture(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): readonly DestructibleMesh[];\n\tprebake(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): void;\n\tprebakeAsync(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): Promise<void>;\n\trepair(): void;\n\tisFractured(): boolean;\n\tgetFragments(): readonly DestructibleMesh[];\n}\n\ninterface PrebakedFragmentTemplate {\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}\n\ninterface RuntimeState {\n\tfragmentContainer: Group | null;\n\tfragmentEntities: GameEntity<any>[];\n\tfragments: DestructibleMesh[];\n\tprebakedFragments: PrebakedFragmentTemplate[];\n\tprebakedFractureKey: string | null;\n\tcreatedRootGroup: boolean;\n\tfractureMode: 'compound' | 'independent' | null;\n\tisFractured: boolean;\n\toriginalMeshParent: Object3D | null;\n\toriginalColliderDesc: unknown | undefined;\n\toriginalColliderDescs: unknown[];\n\toriginalMeshVisible: boolean;\n\toriginalGroupVisible: boolean;\n\tsourceBodySnapshot: PhysicsSnapshot | null;\n\tsourcePhysicsAttached: boolean;\n}\n\ninterface PhysicsSnapshot {\n\ttranslation: { x: number; y: number; z: number };\n\trotation: { x: number; y: number; z: number; w: number };\n\tlinearVelocity: { x: number; y: number; z: number };\n\tangularVelocity: { x: number; y: number; z: number };\n}\n\n/**\n * Structural view of the host-attached physics body. The host materializes\n * bodies in the WASM simulation and may expose this shape on entities for\n * velocity/pose access; no Rapier types are involved.\n */\ninterface PhysicsBodyLike {\n\ttranslation(): { x: number; y: number; z: number };\n\trotation(): { x: number; y: number; z: number; w: number };\n\tlinvel(): { x: number; y: number; z: number };\n\tangvel(): { x: number; y: number; z: number };\n\tsetTranslation(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n\tsetRotation(value: { x: number; y: number; z: number; w: number }, wakeUp?: boolean): void;\n\tsetLinvel(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n\tsetAngvel(value: { x: number; y: number; z: number }, wakeUp?: boolean): void;\n}\n\nfunction getBodyLike(entity: GameEntity<any>): PhysicsBodyLike | null {\n\treturn (entity.body as PhysicsBodyLike | null | undefined) ?? null;\n}\n\ntype BehaviorWorld = {\n\tinterpolationAlpha?: number;\n\tdestroyEntity(entity: GameEntity<any>): void;\n\taddEntity(entity: GameEntity<any>): void;\n};\n\ntype BehaviorScene = {\n\tscene: {\n\t\tadd(object: Object3D): void;\n\t\tremove(object: Object3D): void;\n\t};\n};\n\nconst DESTRUCTIBLE_3D_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:destructible-3d',\n);\n\nconst DEFAULT_FRACTURE_OPTIONS: FractureOptionsInput = {\n\tfractureMethod: 'voronoi',\n\tfragmentCount: 12,\n\tvoronoiOptions: {\n\t\tmode: '3D',\n\t},\n\tfracturePlanes: {\n\t\tx: true,\n\t\ty: true,\n\t\tz: true,\n\t},\n\ttextureScale: new Vector2(1, 1),\n\ttextureOffset: new Vector2(0, 0),\n};\n\nconst DEFAULT_FRAGMENT_PHYSICS: Required<Destructible3DFragmentPhysicsOptions> = {\n\tmode: 'compound',\n\tinheritSourceVelocity: true,\n\toutwardVelocity: 3,\n\tangularVelocity: 1.5,\n};\n\nconst defaultOptions: Destructible3DBehaviorOptions = {\n\tfractureOptions: DEFAULT_FRACTURE_OPTIONS,\n\tinnerMaterial: null,\n\tcollider: {\n\t\tshape: 'convexHull',\n\t\tsensor: false,\n\t},\n\tfragmentPhysics: DEFAULT_FRAGMENT_PHYSICS,\n};\n\nconst runtimeStates = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tRuntimeState\n>();\n\nfunction getRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): RuntimeState {\n\tconst existing = runtimeStates.get(ref);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconst state: RuntimeState = {\n\t\tfragmentContainer: null,\n\t\tfragmentEntities: [],\n\t\tfragments: [],\n\t\tprebakedFragments: [],\n\t\tprebakedFractureKey: null,\n\t\tcreatedRootGroup: false,\n\t\tfractureMode: null,\n\t\tisFractured: false,\n\t\toriginalMeshParent: null,\n\t\toriginalColliderDesc: undefined,\n\t\toriginalColliderDescs: [],\n\t\toriginalMeshVisible: true,\n\t\toriginalGroupVisible: true,\n\t\tsourceBodySnapshot: null,\n\t\tsourcePhysicsAttached: false,\n\t};\n\truntimeStates.set(ref, state);\n\treturn state;\n}\n\nconst prebakeWorkerApis = new Map<\n\tstring,\n\tComlink.Remote<DestructiblePrebakeWorkerAPI>\n>();\n\n/** One in-flight worker prebake per behavior ref (dedupes duplicate bind calls). */\nconst prebakeAsyncInFlight = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tPromise<void>\n>();\n\nfunction resolvePrebakeWorkerHref(url: URL | string): string {\n\treturn typeof url === 'string' ? url : url.href;\n}\n\nfunction getPrebakeWorkerApi(\n\turl: URL | string,\n): Comlink.Remote<DestructiblePrebakeWorkerAPI> {\n\tif (typeof Worker === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'Destructible3D prebakeAsync requires a Web Worker-capable environment.',\n\t\t);\n\t}\n\tconst key = resolvePrebakeWorkerHref(url);\n\tlet api = prebakeWorkerApis.get(key);\n\tif (api) {\n\t\treturn api;\n\t}\n\tconst worker = new Worker(key, { type: 'module' });\n\tapi = Comlink.wrap(worker);\n\tprebakeWorkerApis.set(key, api);\n\treturn api;\n}\n\nfunction requireEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): GameEntity<any> {\n\tconst entity = (ref as any).__entity as GameEntity<any> | undefined;\n\tif (!entity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to be registered on a stage before calling fracture() or repair().',\n\t\t);\n\t}\n\n\treturn entity;\n}\n\nfunction getBehaviorWorld(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorWorld | null {\n\treturn ((ref as any).__world ?? null) as BehaviorWorld | null;\n}\n\nfunction getBehaviorScene(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorScene | null {\n\treturn ((ref as any).__scene ?? null) as BehaviorScene | null;\n}\n\nfunction getBehaviorCreateEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): CreateEntityFn | null {\n\treturn ((ref as any).__createEntity ?? null) as CreateEntityFn | null;\n}\n\nfunction getBehaviorGlobals(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\n\nfunction cloneFractureOptionsInput(\n\tvalue?: FractureOptionsInput | PinataFractureOptions,\n): FractureOptionsInput {\n\tif (!value) {\n\t\treturn {};\n\t}\n\n\tif (value instanceof PinataFractureOptions) {\n\t\treturn {\n\t\t\tfractureMethod: value.fractureMethod,\n\t\t\tfragmentCount: value.fragmentCount,\n\t\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t\t? {\n\t\t\t\t\tmode: value.voronoiOptions.mode,\n\t\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\t\tpoint.clone()),\n\t\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\t\timpactRadius: value.voronoiOptions.impactRadius,\n\t\t\t\t\tprojectionAxis: value.voronoiOptions.projectionAxis,\n\t\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t\t\tuseApproximation: value.voronoiOptions.useApproximation,\n\t\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\t\tvalue.voronoiOptions.approximationNeighborCount,\n\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tfracturePlanes: value.fracturePlanes\n\t\t\t\t? { ...value.fracturePlanes }\n\t\t\t\t: undefined,\n\t\t\ttextureScale: value.textureScale?.clone(),\n\t\t\ttextureOffset: value.textureOffset?.clone(),\n\t\t\tseed: value.seed,\n\t\t};\n\t}\n\n\treturn {\n\t\t...value,\n\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t? {\n\t\t\t\t...value.voronoiOptions,\n\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\tpoint.clone()),\n\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t}\n\t\t\t: undefined,\n\t\tfracturePlanes: value.fracturePlanes\n\t\t\t? { ...value.fracturePlanes }\n\t\t\t: undefined,\n\t\ttextureScale: value.textureScale?.clone(),\n\t\ttextureOffset: value.textureOffset?.clone(),\n\t};\n}\n\nfunction resolveFractureOptions(\n\tbaseValue?: FractureOptionsInput | PinataFractureOptions,\n\toverrideValue?: FractureOptionsInput | PinataFractureOptions,\n): PinataFractureOptions {\n\tconst base = cloneFractureOptionsInput(baseValue);\n\tconst override = cloneFractureOptionsInput(overrideValue);\n\n\tconst fractureMethod =\n\t\toverride.fractureMethod\n\t\t?? base.fractureMethod\n\t\t?? DEFAULT_FRACTURE_OPTIONS.fractureMethod\n\t\t?? 'voronoi';\n\n\tconst voronoiOptions = fractureMethod === 'voronoi'\n\t\t? {\n\t\t\tmode:\n\t\t\t\toverride.voronoiOptions?.mode\n\t\t\t\t?? base.voronoiOptions?.mode\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.voronoiOptions?.mode\n\t\t\t\t?? '3D',\n\t\t\tseedPoints:\n\t\t\t\toverride.voronoiOptions?.seedPoints\n\t\t\t\t?? base.voronoiOptions?.seedPoints,\n\t\t\timpactPoint:\n\t\t\t\toverride.voronoiOptions?.impactPoint\n\t\t\t\t?? base.voronoiOptions?.impactPoint,\n\t\t\timpactRadius:\n\t\t\t\toverride.voronoiOptions?.impactRadius\n\t\t\t\t?? base.voronoiOptions?.impactRadius,\n\t\t\tprojectionAxis:\n\t\t\t\toverride.voronoiOptions?.projectionAxis\n\t\t\t\t?? base.voronoiOptions?.projectionAxis,\n\t\t\tprojectionNormal:\n\t\t\t\toverride.voronoiOptions?.projectionNormal\n\t\t\t\t?? base.voronoiOptions?.projectionNormal,\n\t\t\tuseApproximation:\n\t\t\t\toverride.voronoiOptions?.useApproximation\n\t\t\t\t?? base.voronoiOptions?.useApproximation,\n\t\t\tapproximationNeighborCount:\n\t\t\t\toverride.voronoiOptions?.approximationNeighborCount\n\t\t\t\t?? base.voronoiOptions?.approximationNeighborCount,\n\t\t}\n\t\t: undefined;\n\n\treturn new PinataFractureOptions({\n\t\tfractureMethod,\n\t\tfragmentCount:\n\t\t\toverride.fragmentCount\n\t\t\t?? base.fragmentCount\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fragmentCount\n\t\t\t?? 12,\n\t\tvoronoiOptions,\n\t\tfracturePlanes: {\n\t\t\tx:\n\t\t\t\toverride.fracturePlanes?.x\n\t\t\t\t?? base.fracturePlanes?.x\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.x\n\t\t\t\t?? true,\n\t\t\ty:\n\t\t\t\toverride.fracturePlanes?.y\n\t\t\t\t?? base.fracturePlanes?.y\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.y\n\t\t\t\t?? true,\n\t\t\tz:\n\t\t\t\toverride.fracturePlanes?.z\n\t\t\t\t?? base.fracturePlanes?.z\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.z\n\t\t\t\t?? true,\n\t\t},\n\t\ttextureScale:\n\t\t\toverride.textureScale?.clone()\n\t\t\t?? base.textureScale?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureScale?.clone()\n\t\t\t?? new Vector2(1, 1),\n\t\ttextureOffset:\n\t\t\toverride.textureOffset?.clone()\n\t\t\t?? base.textureOffset?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureOffset?.clone()\n\t\t\t?? new Vector2(0, 0),\n\t\tseed: override.seed ?? base.seed,\n\t});\n}\n\nfunction resolveColliderOptions(\n\tinput?: Destructible3DColliderOptions,\n): Required<\n\tPick<Destructible3DColliderOptions, 'shape' | 'sensor'>\n> & Omit<Destructible3DColliderOptions, 'shape' | 'sensor'> {\n\treturn {\n\t\tshape: input?.shape ?? defaultOptions.collider?.shape ?? 'convexHull',\n\t\tsensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,\n\t\tcollisionGroups: input?.collisionGroups,\n\t};\n}\n\nfunction resolveFragmentPhysicsOptions(\n\tinput?: Destructible3DFragmentPhysicsOptions,\n): Required<Destructible3DFragmentPhysicsOptions> {\n\treturn {\n\t\tmode: input?.mode ?? DEFAULT_FRAGMENT_PHYSICS.mode,\n\t\tinheritSourceVelocity:\n\t\t\tinput?.inheritSourceVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.inheritSourceVelocity,\n\t\toutwardVelocity:\n\t\t\tinput?.outwardVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.outwardVelocity,\n\t\tangularVelocity:\n\t\t\tinput?.angularVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.angularVelocity,\n\t};\n}\n\nfunction findFirstMesh(root: Object3D | null | undefined): Mesh | null {\n\tlet resolved: Mesh | null = null;\n\troot?.traverse((child) => {\n\t\tif (resolved) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ((child as { isMesh?: boolean }).isMesh) {\n\t\t\tresolved = child as Mesh;\n\t\t}\n\t});\n\treturn resolved;\n}\n\nfunction requireEntityMesh(entity: GameEntity<any>): Mesh {\n\tif (entity.mesh?.geometry) {\n\t\treturn entity.mesh;\n\t}\n\n\tconst mesh = findFirstMesh(entity.group);\n\tif (!mesh?.geometry) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to have a primary mesh geometry.',\n\t\t);\n\t}\n\n\tentity.mesh = mesh;\n\tif (!entity.materials?.length) {\n\t\tif (Array.isArray(mesh.material)) {\n\t\t\tentity.materials = [...mesh.material];\n\t\t} else if (mesh.material) {\n\t\t\tentity.materials = [mesh.material];\n\t\t}\n\t}\n\n\treturn mesh;\n}\n\nfunction getPrimaryMaterial(mesh: Mesh): Material {\n\tif (Array.isArray(mesh.material)) {\n\t\tconst material = mesh.material[0];\n\t\tif (material) {\n\t\t\treturn material;\n\t\t}\n\t} else if (mesh.material) {\n\t\treturn mesh.material;\n\t}\n\n\tthrow new Error(\n\t\t'Destructible3DBehavior requires the entity mesh to have a material.',\n\t);\n}\n\nfunction ensureRootGroup(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): Group {\n\tif (entity.group) {\n\t\tstate.createdRootGroup = false;\n\t\treturn entity.group;\n\t}\n\n\tconst originalMesh = requireEntityMesh(entity);\n\tconst parent = originalMesh.parent;\n\tconst root = new Group();\n\troot.name = `${entity.name ?? entity.uuid}-destructible-root`;\n\troot.position.copy(originalMesh.position);\n\troot.quaternion.copy(originalMesh.quaternion);\n\troot.scale.copy(originalMesh.scale);\n\n\toriginalMesh.position.set(0, 0, 0);\n\toriginalMesh.quaternion.identity();\n\toriginalMesh.scale.set(1, 1, 1);\n\n\tif (parent) {\n\t\tparent.remove(originalMesh);\n\t\tparent.add(root);\n\t}\n\n\troot.add(originalMesh);\n\tentity.group = root;\n\tstate.createdRootGroup = true;\n\treturn root;\n}\n\nfunction createFractureSourceMesh(\n\tmesh: Mesh,\n\troot: Group,\n\tinnerMaterial: Material | null | undefined,\n): DestructibleMesh {\n\tconst geometry = buildNormalizedFractureSourceGeometry(mesh, root);\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn new DestructibleMesh(\n\t\tgeometry,\n\t\touterMaterial,\n\t\tinnerMaterial ?? outerMaterial,\n\t);\n}\n\nfunction createPrebakedFragmentTemplates(\n\tfragments: readonly DestructibleMesh[],\n): PrebakedFragmentTemplate[] {\n\treturn fragments.map((fragment) => {\n\t\tconst geometry = fragment.geometry.clone();\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: fragment.position.clone(),\n\t\t\tquaternion: fragment.quaternion.clone(),\n\t\t\tscale: fragment.scale.clone(),\n\t\t};\n\t});\n}\n\nfunction disposePrebakedFragmentTemplates(\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): void {\n\tfor (const template of templates) {\n\t\ttemplate.geometry.dispose();\n\t}\n}\n\nfunction cachePrebakedFragments(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tfragments: readonly DestructibleMesh[],\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = createPrebakedFragmentTemplates(fragments);\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction installPrebakedTemplateParts(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tparts: Array<{\n\t\tgeometry: BufferGeometry;\n\t\tposition: Vector3;\n\t\tquaternion: Quaternion;\n\t\tscale: Vector3;\n\t}>,\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\tfor (const part of parts) {\n\t\t\tpart.geometry.dispose();\n\t\t}\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = parts.map((part) => ({\n\t\tgeometry: part.geometry,\n\t\tposition: part.position.clone(),\n\t\tquaternion: part.quaternion.clone(),\n\t\tscale: part.scale.clone(),\n\t}));\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction instantiatePrebakedFragments(\n\tmesh: Mesh,\n\tinnerMaterial: Material | null | undefined,\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): readonly DestructibleMesh[] {\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn templates.map((template) => {\n\t\tconst fragment = new DestructibleMesh(\n\t\t\ttemplate.geometry.clone(),\n\t\t\touterMaterial,\n\t\t\tinnerMaterial ?? outerMaterial,\n\t\t);\n\t\tfragment.position.copy(template.position);\n\t\tfragment.quaternion.copy(template.quaternion);\n\t\tfragment.scale.copy(template.scale);\n\t\treturn fragment;\n\t});\n}\n\nfunction getFragmentVertices(fragment: DestructibleMesh): Float32Array {\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\tthrow new Error('Fragment geometry is missing a position attribute.');\n\t}\n\n\treturn new Float32Array(position.array as ArrayLike<number>);\n}\n\nfunction getFragmentIndices(fragment: DestructibleMesh): Uint32Array {\n\tconst geometryIndex = fragment.geometry.getIndex();\n\tif (geometryIndex) {\n\t\treturn new Uint32Array(geometryIndex.array as ArrayLike<number>);\n\t}\n\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\treturn new Uint32Array();\n\t}\n\n\treturn Uint32Array.from({ length: position.count }, (_value, index) => index);\n}\n\nfunction createCuboidColliderShape(\n\tfragment: DestructibleMesh,\n): { type: 'box'; halfExtents: [number, number, number] } {\n\tconst bounds = fragment.geometry.boundingBox ?? new Box3();\n\tif (!fragment.geometry.boundingBox) {\n\t\tfragment.geometry.computeBoundingBox();\n\t}\n\tbounds.copy(fragment.geometry.boundingBox ?? bounds);\n\tconst size = bounds.getSize(new Vector3());\n\treturn {\n\t\ttype: 'box',\n\t\thalfExtents: [\n\t\t\tMath.max(size.x / 2, 0.001),\n\t\t\tMath.max(size.y / 2, 0.001),\n\t\t\tMath.max(size.z / 2, 0.001),\n\t\t],\n\t};\n}\n\nfunction createFragmentColliderDefinition(\n\tfragment: DestructibleMesh,\n\toptions: Destructible3DColliderOptions | undefined,\n\ttranslation?: Vector3 | null,\n): Destructible3DFragmentColliderDefinition {\n\tconst resolved = resolveColliderOptions(options);\n\tconst vertices = getFragmentVertices(fragment);\n\n\tlet shape: Destructible3DFragmentColliderDefinition['shape'] | null = null;\n\n\tif (resolved.shape === 'convexHull' && vertices.length >= 12) {\n\t\tshape = { type: 'convexHull', vertices };\n\t}\n\n\tif (!shape && resolved.shape === 'trimesh') {\n\t\tshape = { type: 'trimesh', vertices, indices: getFragmentIndices(fragment) };\n\t}\n\n\tif (!shape) {\n\t\tshape = createCuboidColliderShape(fragment);\n\t}\n\n\tconst definition: Destructible3DFragmentColliderDefinition = {\n\t\tshape,\n\t\tsensor: resolved.sensor,\n\t};\n\tif (translation) {\n\t\tdefinition.offset = [translation.x, translation.y, translation.z];\n\t}\n\tif (resolved.collisionGroups !== undefined) {\n\t\tdefinition.collisionGroups = resolved.collisionGroups;\n\t}\n\treturn definition;\n}\n\nfunction snapshotBody(entity: GameEntity<any>): PhysicsSnapshot | null {\n\tconst body = getBodyLike(entity);\n\tif (!body) {\n\t\treturn null;\n\t}\n\n\tconst translation = body.translation();\n\tconst rotation = body.rotation();\n\tconst linearVelocity = body.linvel();\n\tconst angularVelocity = body.angvel();\n\n\treturn {\n\t\ttranslation: { ...translation },\n\t\trotation: { ...rotation },\n\t\tlinearVelocity: { ...linearVelocity },\n\t\tangularVelocity: { ...angularVelocity },\n\t};\n}\n\nfunction restoreBodySnapshot(\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst body = getBodyLike(entity);\n\tif (!snapshot || !body) {\n\t\treturn;\n\t}\n\n\tbody.setTranslation(snapshot.translation, true);\n\tbody.setRotation(snapshot.rotation, true);\n\tbody.setLinvel(snapshot.linearVelocity, true);\n\tbody.setAngvel(snapshot.angularVelocity, true);\n}\n\nfunction attachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.colliderDesc) {\n\t\treturn;\n\t}\n\n\tif (entity.physicsAttached) {\n\t\tworld.destroyEntity(entity);\n\t}\n\n\tworld.addEntity(entity);\n\trestoreBodySnapshot(entity, snapshot);\n}\n\nfunction detachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.physicsAttached) {\n\t\treturn;\n\t}\n\n\tworld.destroyEntity(entity);\n}\n\nfunction disposeFragments(fragments: readonly DestructibleMesh[]): void {\n\tfor (const fragment of fragments) {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n}\n\nfunction syncRuntimeFragmentEntityTransform(\n\tentity: GameEntity<any>,\n\t_interpolationAlpha: number,\n): void {\n\tconst target = entity.group ?? entity.mesh;\n\tif (!target) {\n\t\treturn;\n\t}\n\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\ttarget.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);\n\t\ttarget.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);\n\t}\n}\n\nfunction bakeScaleIntoFragmentGeometry(\n\tfragment: DestructibleMesh,\n\tscale: Vector3,\n): void {\n\tif (\n\t\tMath.abs(scale.x - 1) < 1e-6\n\t\t&& Math.abs(scale.y - 1) < 1e-6\n\t\t&& Math.abs(scale.z - 1) < 1e-6\n\t) {\n\t\treturn;\n\t}\n\n\tfragment.geometry.applyMatrix4(\n\t\tnew Matrix4().makeScale(scale.x, scale.y, scale.z),\n\t);\n\tfragment.geometry.computeBoundingBox();\n\tfragment.geometry.computeBoundingSphere();\n}\n\nfunction getRootWorldPosition(root: Group): Vector3 {\n\troot.updateMatrixWorld(true);\n\treturn root.getWorldPosition(new Vector3());\n}\n\nfunction getImpactPointWorld(\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n): Vector3 | null {\n\tconst localImpactPoint = fractureOptions.voronoiOptions?.impactPoint;\n\tif (!localImpactPoint) {\n\t\treturn null;\n\t}\n\n\troot.updateMatrixWorld(true);\n\treturn localImpactPoint.clone().applyMatrix4(root.matrixWorld);\n}\n\nfunction computeFragmentWorldPose(\n\troot: Group,\n\tfragment: DestructibleMesh,\n): {\n\tposition: Vector3;\n\trotation: Quaternion;\n\tscale: Vector3;\n} {\n\troot.updateMatrixWorld(true);\n\tfragment.updateMatrix();\n\n\tconst worldMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.multiply(fragment.matrix);\n\tconst position = new Vector3();\n\tconst rotation = new Quaternion();\n\tconst scale = new Vector3();\n\n\tworldMatrix.decompose(position, rotation, scale);\n\treturn {\n\t\tposition,\n\t\trotation,\n\t\tscale,\n\t};\n}\n\nfunction pseudoRandomSigned(index: number, salt: number): number {\n\tconst value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;\n\treturn (value - Math.floor(value)) * 2 - 1;\n}\n\nfunction computeFragmentAngularVelocity(\n\tindex: number,\n\tmagnitude: number,\n): { x: number; y: number; z: number } {\n\tif (magnitude <= 0) {\n\t\treturn { x: 0, y: 0, z: 0 };\n\t}\n\n\tconst axis = new Vector3(\n\t\tpseudoRandomSigned(index, 0.13),\n\t\tpseudoRandomSigned(index, 0.47),\n\t\tpseudoRandomSigned(index, 0.91),\n\t);\n\tif (axis.lengthSq() <= 1e-6) {\n\t\taxis.set(0.35, 1, 0.2);\n\t}\n\taxis.normalize().multiplyScalar(magnitude);\n\treturn {\n\t\tx: axis.x,\n\t\ty: axis.y,\n\t\tz: axis.z,\n\t};\n}\n\nfunction computeFragmentLinearVelocity(\n\tfragmentWorldPosition: Vector3,\n\trootWorldPosition: Vector3,\n\timpactPointWorld: Vector3 | null,\n\tphysicsOptions: Required<Destructible3DFragmentPhysicsOptions>,\n\tsourceVelocity: { x: number; y: number; z: number } | null,\n): { x: number; y: number; z: number } {\n\tconst velocity = new Vector3();\n\n\tif (physicsOptions.inheritSourceVelocity && sourceVelocity) {\n\t\tvelocity.set(\n\t\t\tsourceVelocity.x,\n\t\t\tsourceVelocity.y,\n\t\t\tsourceVelocity.z,\n\t\t);\n\t}\n\n\tif (physicsOptions.outwardVelocity <= 0) {\n\t\treturn {\n\t\t\tx: velocity.x,\n\t\t\ty: velocity.y,\n\t\t\tz: velocity.z,\n\t\t};\n\t}\n\n\tconst direction = fragmentWorldPosition.clone().sub(\n\t\timpactPointWorld ?? rootWorldPosition,\n\t);\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.copy(fragmentWorldPosition).sub(rootWorldPosition);\n\t}\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.set(0, 1, 0);\n\t}\n\tdirection.normalize().multiplyScalar(physicsOptions.outwardVelocity);\n\tvelocity.add(direction);\n\n\treturn {\n\t\tx: velocity.x,\n\t\ty: velocity.y,\n\t\tz: velocity.z,\n\t};\n}\n\nfunction createRuntimeFragmentEntity(\n\tcreateEntity: CreateEntityFn,\n\tparentEntity: GameEntity<any>,\n\tfragment: DestructibleMesh,\n\tindex: number,\n\tcolliderOptions: Destructible3DColliderOptions | undefined,\n\tposition: Vector3,\n\trotation: Quaternion,\n): GameEntity<any> {\n\tconst entity = createEntity({\n\t\tname: `${parentEntity.name ?? parentEntity.uuid}-fragment-${index}`,\n\t});\n\n\tentity.onCleanup(() => {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t});\n\tentity.create();\n\n\tentity.mesh = fragment;\n\tif (Array.isArray(fragment.material)) {\n\t\tentity.materials = [...fragment.material];\n\t} else if (fragment.material) {\n\t\tentity.materials = [fragment.material];\n\t}\n\n\tentity.colliderDesc = createFragmentColliderDefinition(fragment, colliderOptions);\n\tentity.colliderDescs = [entity.colliderDesc];\n\tconst bodyDefinition: Destructible3DFragmentBodyDefinition = {\n\t\tkind: 'dynamic',\n\t\tposition: [position.x, position.y, position.z],\n\t\trotation: [rotation.x, rotation.y, rotation.z, rotation.w],\n\t\tcanSleep: false,\n\t\tccdEnabled: true,\n\t};\n\tentity.bodyDesc = bodyDefinition;\n\n\tfragment.position.set(0, 0, 0);\n\tfragment.quaternion.identity();\n\tfragment.scale.set(1, 1, 1);\n\n\treturn entity;\n}\n\n/**\n * {@link ZylemWorld} locks translations and rotations on every new rigid body\n * when world gravity is `(0,0,0)`, so entities do not drift in zero‑G scenes.\n * Independent destructible fragments are still meant to move via\n * `setLinvel` / `setAngvel`, so they must opt out of that lock after spawn.\n */\nfunction unlockIndependentFragmentPhysicsBody(entity: GameEntity<any>): void {\n\tconst body = entity.body as\n\t\t| {\n\t\t\tlockTranslations?(locked: boolean, wakeUp?: boolean): void;\n\t\t\tlockRotations?(locked: boolean, wakeUp?: boolean): void;\n\t\t}\n\t\t| null\n\t\t| undefined;\n\tif (!body?.lockTranslations || !body.lockRotations) {\n\t\treturn;\n\t}\n\tbody.lockTranslations(false, true);\n\tbody.lockRotations(false, true);\n}\n\nfunction destroyRuntimeFragmentEntities(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tconst handledFragments = new Set<DestructibleMesh>();\n\n\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\tconst fragmentMesh = fragmentEntity.mesh as DestructibleMesh | undefined;\n\t\tif (fragmentMesh) {\n\t\t\thandledFragments.add(fragmentMesh);\n\t\t}\n\n\t\ttry {\n\t\t\tfragmentEntity.nodeDestroy({\n\t\t\t\tme: fragmentEntity,\n\t\t\t\tglobals: getBehaviorGlobals(ref)?.() ?? {},\n\t\t\t} as any);\n\t\t} catch {\n\t\t\t// Cleanup is best-effort for behavior-managed runtime fragments.\n\t\t}\n\n\t\tif (world && fragmentEntity.physicsAttached) {\n\t\t\tworld.destroyEntity(fragmentEntity);\n\t\t}\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene?.scene.remove(target);\n\t\t}\n\t}\n\n\tfor (const fragment of state.fragments) {\n\t\tif (handledFragments.has(fragment)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n\n\tstate.fragmentEntities = [];\n}\n\nfunction restoreOriginalMesh(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): void {\n\tif (!entity.mesh) {\n\t\treturn;\n\t}\n\n\tif (state.createdRootGroup && entity.group) {\n\t\tconst root = entity.group;\n\t\tconst parent = root.parent;\n\t\tentity.mesh.position.copy(root.position);\n\t\tentity.mesh.quaternion.copy(root.quaternion);\n\t\tentity.mesh.scale.copy(root.scale);\n\t\tentity.mesh.removeFromParent();\n\n\t\tif (parent) {\n\t\t\tparent.remove(root);\n\t\t\tparent.add(entity.mesh);\n\t\t}\n\n\t\tentity.group = undefined;\n\t\treturn;\n\t}\n\n\tconst parent = state.originalMeshParent ?? entity.group;\n\tif (parent && entity.mesh.parent !== parent) {\n\t\tparent.add(entity.mesh);\n\t}\n}\n\nfunction restoreRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\trefreshPhysics: boolean,\n): void {\n\tconst state = getRuntimeState(ref);\n\tif (!state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst entity = requireEntity(ref);\n\n\tif (state.fractureMode === 'independent') {\n\t\tdestroyRuntimeFragmentEntities(ref, state);\n\t} else {\n\t\tstate.fragmentContainer?.removeFromParent();\n\t\tstate.fragmentContainer?.clear();\n\t\tdisposeFragments(state.fragments);\n\t}\n\n\tstate.fragmentContainer = null;\n\tstate.fragments = [];\n\n\trestoreOriginalMesh(entity, state);\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = state.originalMeshVisible;\n\t}\n\tif (entity.group) {\n\t\tentity.group.visible = state.originalGroupVisible;\n\t}\n\n\tentity.colliderDesc = state.originalColliderDesc;\n\tentity.colliderDescs = [...state.originalColliderDescs];\n\tif (!entity.colliderDesc && entity.colliderDescs.length > 0) {\n\t\tentity.colliderDesc = entity.colliderDescs[0];\n\t}\n\n\tif (refreshPhysics && state.sourcePhysicsAttached) {\n\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t}\n\n\tstate.createdRootGroup = false;\n\tstate.fractureMode = null;\n\tstate.originalMeshParent = null;\n\tstate.originalColliderDesc = undefined;\n\tstate.originalColliderDescs = [];\n\tstate.originalMeshVisible = true;\n\tstate.originalGroupVisible = true;\n\tstate.sourceBodySnapshot = null;\n\tstate.sourcePhysicsAttached = false;\n\tstate.isFractured = false;\n}\n\nfunction disposeRuntimeState(state: RuntimeState): void {\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = [];\n\tstate.prebakedFractureKey = null;\n}\n\nfunction fractureCompoundEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst fragmentContainer = new Group();\n\tfragmentContainer.name = `${entity.name ?? entity.uuid}-fracture-fragments`;\n\tfor (const fragment of fragments) {\n\t\tfragmentContainer.add(fragment);\n\t}\n\n\tentity.mesh?.removeFromParent();\n\troot.add(fragmentContainer);\n\n\tstate.fragmentContainer = fragmentContainer;\n\tstate.fractureMode = 'compound';\n\n\tconst colliderDescs = fragments.map((fragment) =>\n\t\tcreateFragmentColliderDefinition(\n\t\t\tfragment,\n\t\t\tref.options.collider,\n\t\t\tfragment.position,\n\t\t));\n\tif (colliderDescs.length > 0) {\n\t\tentity.colliderDescs = colliderDescs;\n\t\tentity.colliderDesc = colliderDescs[0];\n\t\tif (state.sourcePhysicsAttached) {\n\t\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t\t}\n\t}\n}\n\nfunction fractureIndependentEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tif (!world || !scene) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require an active scene and physics world.',\n\t\t);\n\t}\n\n\tconst createEntity = getBehaviorCreateEntity(ref);\n\tif (!createEntity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require a host entity factory (BehaviorSystemContext.createEntity).',\n\t\t);\n\t}\n\n\tconst physicsOptions = resolveFragmentPhysicsOptions(ref.options.fragmentPhysics);\n\tconst rootWorldPosition = getRootWorldPosition(root);\n\tconst impactPointWorld = getImpactPointWorld(root, fractureOptions);\n\tconst sourceVelocity = state.sourceBodySnapshot?.linearVelocity ?? null;\n\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = false;\n\t}\n\tif (state.sourcePhysicsAttached) {\n\t\tdetachEntityPhysics(ref, entity);\n\t}\n\n\tconst fragmentEntities: GameEntity<any>[] = [];\n\n\tfor (const [index, fragment] of fragments.entries()) {\n\t\tconst fragmentWorldPose = computeFragmentWorldPose(root, fragment);\n\t\tbakeScaleIntoFragmentGeometry(fragment, fragmentWorldPose.scale);\n\n\t\tconst fragmentEntity = createRuntimeFragmentEntity(\n\t\t\tcreateEntity,\n\t\t\tentity,\n\t\t\tfragment,\n\t\t\tindex,\n\t\t\tref.options.collider,\n\t\t\tfragmentWorldPose.position,\n\t\t\tfragmentWorldPose.rotation,\n\t\t);\n\n\t\tworld.addEntity(fragmentEntity);\n\t\tunlockIndependentFragmentPhysicsBody(fragmentEntity);\n\t\tconst linearVelocity = computeFragmentLinearVelocity(\n\t\t\tfragmentWorldPose.position,\n\t\t\trootWorldPosition,\n\t\t\timpactPointWorld,\n\t\t\tphysicsOptions,\n\t\t\tsourceVelocity,\n\t\t);\n\t\tconst fragmentBody = getBodyLike(fragmentEntity);\n\t\tfragmentBody?.setLinvel(linearVelocity, true);\n\t\tfragmentBody?.setAngvel(\n\t\t\tcomputeFragmentAngularVelocity(\n\t\t\t\tindex,\n\t\t\t\tphysicsOptions.angularVelocity,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\tfragmentEntity,\n\t\t\tworld.interpolationAlpha ?? 0,\n\t\t);\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene.scene.add(target);\n\t\t}\n\n\t\tfragmentEntities.push(fragmentEntity);\n\t}\n\n\tstate.fragmentEntities = fragmentEntities;\n\tstate.fractureMode = 'independent';\n}\n\nfunction fractureEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): readonly DestructibleMesh[] {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\trestoreRuntimeState(ref, true);\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\n\tconst root = ensureRootGroup(entity, state);\n\tstate.originalMeshParent = sourceMesh.parent;\n\tstate.originalColliderDesc = entity.colliderDesc;\n\tstate.originalColliderDescs = entity.colliderDescs.length > 0\n\t\t? [...entity.colliderDescs]\n\t\t: entity.colliderDesc\n\t\t\t? [entity.colliderDesc]\n\t\t\t: [];\n\tstate.originalMeshVisible = sourceMesh.visible;\n\tstate.originalGroupVisible = entity.group?.visible ?? true;\n\tstate.sourceBodySnapshot = snapshotBody(entity);\n\tstate.sourcePhysicsAttached = entity.physicsAttached;\n\n\tconst usePrebakedFragments =\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0;\n\tconst source = usePrebakedFragments\n\t\t? null\n\t\t: createFractureSourceMesh(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t\tref.options.innerMaterial,\n\t\t);\n\n\ttry {\n\t\tconst fragmentPhysics = resolveFragmentPhysicsOptions(\n\t\t\tref.options.fragmentPhysics,\n\t\t);\n\t\tconst fragments = usePrebakedFragments\n\t\t\t? instantiatePrebakedFragments(\n\t\t\t\tsourceMesh,\n\t\t\t\tref.options.innerMaterial,\n\t\t\t\tstate.prebakedFragments,\n\t\t\t)\n\t\t\t: source!.fracture(fractureOptions);\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\n\t\tstate.fragments = [...fragments];\n\t\tstate.isFractured = true;\n\n\t\tif (fragmentPhysics.mode === 'independent') {\n\t\t\tfractureIndependentEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfractureOptions,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t} else {\n\t\t\tfractureCompoundEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t}\n\n\t\treturn fragments;\n\t} catch (error) {\n\t\trestoreRuntimeState(ref, true);\n\t\tthrow error;\n\t} finally {\n\t\tsource?.geometry.dispose();\n\t}\n}\n\nfunction prebakeEntityGeometryOnly(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst root = ensureRootGroup(entity, state);\n\tconst createdRootGroup = state.createdRootGroup;\n\n\tconst source = createFractureSourceMesh(\n\t\tsourceMesh,\n\t\troot,\n\t\tref.options.innerMaterial,\n\t);\n\ttry {\n\t\tconst fragments = source.fracture(fractureOptions) as DestructibleMesh[];\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\t\tfor (const fragment of fragments) {\n\t\t\tfragment.geometry.dispose();\n\t\t}\n\t} finally {\n\t\tsource.geometry.dispose();\n\t}\n\n\tif (createdRootGroup) {\n\t\trestoreOriginalMesh(entity, state);\n\t\tstate.createdRootGroup = false;\n\t}\n}\n\nasync function prebakeEntityAsync(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): Promise<void> {\n\tconst workerUrl = ref.options.prebakeWorkerUrl;\n\tif (!workerUrl) {\n\t\tprebakeEntityGeometryOnly(ref, overrideOptions);\n\t\treturn;\n\t}\n\n\tconst existing = prebakeAsyncInFlight.get(ref);\n\tif (existing) {\n\t\tawait existing;\n\t\treturn;\n\t}\n\n\tconst job = (async () => {\n\t\tconst entity = requireEntity(ref);\n\t\tif (entity.isInstanced) {\n\t\t\tthrow new Error(\n\t\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t\t);\n\t\t}\n\n\t\tconst state = getRuntimeState(ref);\n\t\tif (state.isFractured) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fractureOptions = resolveFractureOptions(\n\t\t\tref.options.fractureOptions,\n\t\t\toverrideOptions,\n\t\t);\n\t\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\t\tif (\n\t\t\tstate.prebakedFractureKey === cacheKey\n\t\t\t&& state.prebakedFragments.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourceMesh = requireEntityMesh(entity);\n\t\tconst root = ensureRootGroup(entity, state);\n\t\tconst createdRootGroup = state.createdRootGroup;\n\n\t\tconst normalizedGeometry = buildNormalizedFractureSourceGeometry(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t);\n\n\t\tif (createdRootGroup) {\n\t\t\trestoreOriginalMesh(entity, state);\n\t\t\tstate.createdRootGroup = false;\n\t\t}\n\n\t\tconst { payload, transferables } = bufferGeometryToPlain(normalizedGeometry);\n\t\tnormalizedGeometry.dispose();\n\n\t\tconst plainOptions = pinataFractureOptionsToPlain(fractureOptions);\n\t\tconst api = getPrebakeWorkerApi(workerUrl);\n\t\tconst request = Comlink.transfer(\n\t\t\t{ geometry: payload, options: plainOptions },\n\t\t\ttransferables,\n\t\t);\n\n\t\tconst response = await api.prebake(request);\n\t\tconst parts = plainWorkerResultToTemplateParts(response);\n\t\tinstallPrebakedTemplateParts(state, cacheKey, parts);\n\t})();\n\n\tprebakeAsyncInFlight.set(ref, job);\n\ttry {\n\t\tawait job;\n\t} finally {\n\t\tif (prebakeAsyncInFlight.get(ref) === job) {\n\t\t\tprebakeAsyncInFlight.delete(ref);\n\t\t}\n\t}\n}\n\nfunction prebakeEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tprebakeEntityGeometryOnly(ref, overrideOptions);\n}\n\nfunction createDestructible3DHandle(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): Destructible3DHandle {\n\treturn {\n\t\tfracture: (overrideOptions) => fractureEntity(ref, overrideOptions),\n\t\tprebake: (overrideOptions) => {\n\t\t\tprebakeEntity(ref, overrideOptions);\n\t\t},\n\t\tprebakeAsync: (overrideOptions) => prebakeEntityAsync(ref, overrideOptions),\n\t\trepair: () => restoreRuntimeState(ref, true),\n\t\tisFractured: () => getRuntimeState(ref).isFractured,\n\t\tgetFragments: () => getRuntimeState(ref).fragments,\n\t};\n}\n\nclass Destructible3DSystem implements BehaviorSystem {\n\tconstructor(\n\t\tprivate world: unknown,\n\t\tprivate scene: unknown,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate createEntity?: CreateEntityFn,\n\t\tprivate getGlobals?: () => any,\n\t) {\n\t\tthis.primeLinks();\n\t}\n\n\tattach(link: BehaviorEntityLink): void {\n\t\tif (link.ref?.descriptor?.key !== DESTRUCTIBLE_3D_BEHAVIOR_KEY) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.primeLink(link);\n\t}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tthis.primeLinks();\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst interpolationAlpha =\n\t\t\t(this.world as { interpolationAlpha?: number } | null)?.interpolationAlpha\n\t\t\t?? 0;\n\t\tfor (const link of links) {\n\t\t\tconst state = getRuntimeState(\n\t\t\t\tlink.ref as BehaviorRef<Destructible3DBehaviorOptions>,\n\t\t\t);\n\t\t\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\t\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\t\t\tfragmentEntity,\n\t\t\t\t\tinterpolationAlpha,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions>;\n\t\t\trestoreRuntimeState(ref, false);\n\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t}\n\t}\n\n\tprivate primeLinks(): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tthis.primeLink(link);\n\t\t}\n\t}\n\n\tprivate primeLink(link: BehaviorEntityLink): void {\n\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions> & {\n\t\t\t__cleanupRegistered?: boolean;\n\t\t};\n\t\tconst entity = link.entity as GameEntity<any>;\n\t\t(ref as any).__entity = entity;\n\t\t(ref as any).__world = this.world;\n\t\t(ref as any).__scene = this.scene;\n\t\t(ref as any).__createEntity = this.createEntity;\n\t\t(ref as any).__getGlobals = this.getGlobals;\n\n\t\tif (!ref.__cleanupRegistered) {\n\t\t\tentity.onCleanup(() => {\n\t\t\t\trestoreRuntimeState(ref, false);\n\t\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t\t});\n\t\t\tref.__cleanupRegistered = true;\n\t\t}\n\t}\n}\n\nexport const Destructible3DBehavior = defineBehavior<\n\tDestructible3DBehaviorOptions,\n\tDestructible3DHandle\n>({\n\tname: 'destructible-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Destructible3DSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.getBehaviorLinks,\n\t\t\tctx.createEntity,\n\t\t\tctx.getGlobals,\n\t\t),\n\tcreateHandle: createDestructible3DHandle,\n});\n","export * from './destructible-3d.descriptor';\nexport type {\n\tDestructiblePrebakeWorkerAPI,\n\tPlainBufferGeometryPayload,\n\tPlainFractureOptions,\n\tPrebakeWorkerRequest,\n\tPrebakeWorkerResponse,\n} from '../../destructible-prebake';\nexport {\n\tDestructibleMesh,\n\tFractureOptions,\n\ttype VoronoiOptions,\n} from '@dgreenheck/three-pinata';\n"],"mappings":"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","names":["parent","DestructibleMesh"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fireShooter2DIfRequested
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-52FJIDGL.js";
|
|
4
4
|
import {
|
|
5
5
|
createTopDownMovementInputComponent
|
|
6
6
|
} from "./chunk-EIWQM6U3.js";
|
|
@@ -30,4 +30,4 @@ var TopDownShooterCoordinator = class {
|
|
|
30
30
|
export {
|
|
31
31
|
TopDownShooterCoordinator
|
|
32
32
|
};
|
|
33
|
-
//# sourceMappingURL=chunk-
|
|
33
|
+
//# sourceMappingURL=chunk-KIYUUSPK.js.map
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SyncStateMachine,
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
import_typescript_fsm
|
|
4
|
+
} from "./chunk-AS3HR7AS.js";
|
|
5
5
|
import {
|
|
6
6
|
StageRicochetDim,
|
|
7
7
|
StageRicochetReflection
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-E4X4YJZB.js";
|
|
9
9
|
import {
|
|
10
10
|
defineBehavior
|
|
11
11
|
} from "./chunk-EZNCCO4L.js";
|
|
12
12
|
|
|
13
13
|
// src/lib/behaviors/ricochet-2d/ricochet-2d-fsm.ts
|
|
14
|
+
function bodyOf(entity) {
|
|
15
|
+
const body = entity?.body;
|
|
16
|
+
if (body && typeof body.linvel === "function" && typeof body.translation === "function") {
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
14
21
|
var Ricochet2DState = /* @__PURE__ */ ((Ricochet2DState2) => {
|
|
15
22
|
Ricochet2DState2["Idle"] = "idle";
|
|
16
23
|
Ricochet2DState2["Ricocheting"] = "ricocheting";
|
|
@@ -34,11 +41,11 @@ var Ricochet2DFSM = class {
|
|
|
34
41
|
this.machine = new SyncStateMachine(
|
|
35
42
|
"idle" /* Idle */,
|
|
36
43
|
[
|
|
37
|
-
t("idle" /* Idle */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */),
|
|
38
|
-
t("ricocheting" /* Ricocheting */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
|
|
44
|
+
(0, import_typescript_fsm.t)("idle" /* Idle */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */),
|
|
45
|
+
(0, import_typescript_fsm.t)("ricocheting" /* Ricocheting */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
|
|
39
46
|
// Self transitions (no-ops)
|
|
40
|
-
t("idle" /* Idle */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
|
|
41
|
-
t("ricocheting" /* Ricocheting */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */)
|
|
47
|
+
(0, import_typescript_fsm.t)("idle" /* Idle */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
|
|
48
|
+
(0, import_typescript_fsm.t)("ricocheting" /* Ricocheting */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */)
|
|
42
49
|
]
|
|
43
50
|
);
|
|
44
51
|
}
|
|
@@ -159,14 +166,16 @@ var Ricochet2DFSM = class {
|
|
|
159
166
|
let selfPosition = ctx.selfPosition;
|
|
160
167
|
let otherPosition = ctx.otherPosition;
|
|
161
168
|
let otherSize = ctx.otherSize;
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
const selfBody = bodyOf(ctx.entity);
|
|
170
|
+
if (selfBody) {
|
|
171
|
+
const vel = selfBody.linvel();
|
|
164
172
|
selfVelocity = selfVelocity ?? { x: vel.x, y: vel.y, z: vel.z };
|
|
165
|
-
const pos =
|
|
173
|
+
const pos = selfBody.translation();
|
|
166
174
|
selfPosition = selfPosition ?? { x: pos.x, y: pos.y, z: pos.z };
|
|
167
175
|
}
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
const otherBody = bodyOf(ctx.otherEntity);
|
|
177
|
+
if (otherBody) {
|
|
178
|
+
const pos = otherBody.translation();
|
|
170
179
|
otherPosition = otherPosition ?? { x: pos.x, y: pos.y, z: pos.z };
|
|
171
180
|
}
|
|
172
181
|
if (ctx.otherEntity && "size" in ctx.otherEntity) {
|
|
@@ -410,4 +419,4 @@ export {
|
|
|
410
419
|
Ricochet2DFSM,
|
|
411
420
|
Ricochet2DBehavior
|
|
412
421
|
};
|
|
413
|
-
//# sourceMappingURL=chunk-
|
|
422
|
+
//# sourceMappingURL=chunk-KOWGILCN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/ricochet-2d/ricochet-2d-fsm.ts","../src/lib/behaviors/ricochet-2d/ricochet-2d.descriptor.ts"],"sourcesContent":["/**\n * Ricochet2DFSM\n *\n * FSM + extended state to track ricochet events and results.\n * The FSM state tracks whether a ricochet is currently occurring.\n */\nimport { BaseEntityInterface } from \"../../types/entity-types\";\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\n\nexport interface Ricochet2DResult {\n\t/** The reflected velocity vector */\n\tvelocity: { x: number; y: number; z?: number };\n\t/** The resulting speed after reflection */\n\tspeed: number;\n\t/** The collision normal used for reflection */\n\tnormal: { x: number; y: number; z?: number };\n}\n\nexport interface Ricochet2DCollisionContext {\n\tentity?: BaseEntityInterface;\n\totherEntity?: BaseEntityInterface;\n\t/** Current velocity of the entity (optional if entity is provided) */\n\tselfVelocity?: { x: number; y: number; z?: number };\n\t/** Contact information from the collision */\n\tcontact: {\n\t\t/** The collision normal */\n\t\tnormal?: { x: number; y: number; z?: number };\n\t\t/**\n\t\t * Optional position where the collision occurred.\n\t\t * If provided, used for precise offset calculation.\n\t\t */\n\t\tposition?: { x: number; y: number; z?: number };\n\t};\n\t/**\n\t * Optional position of the entity that owns this behavior.\n\t * Used with contact.position for offset calculations.\n\t */\n\tselfPosition?: { x: number; y: number; z?: number };\n\t/**\n\t * Optional position of the other entity in the collision.\n\t * Used for paddle-style deflection: offset = (contactY - otherY) / halfHeight.\n\t */\n\totherPosition?: { x: number; y: number; z?: number };\n\t/**\n\t * Optional size of the other entity (e.g., paddle size).\n\t * If provided, used to normalize the offset based on the collision face.\n\t */\n\totherSize?: { x: number; y: number; z?: number };\n}\n\n/** Structural view of a host-attached body (harness/simulation facade). */\ninterface RicochetBodyLike {\n\tlinvel(): { x: number; y: number; z: number };\n\ttranslation(): { x: number; y: number; z: number };\n}\n\nfunction bodyOf(entity: BaseEntityInterface | undefined): RicochetBodyLike | null {\n\tconst body = entity?.body as Partial<RicochetBodyLike> | null | undefined;\n\tif (body && typeof body.linvel === 'function' && typeof body.translation === 'function') {\n\t\treturn body as RicochetBodyLike;\n\t}\n\treturn null;\n}\n\nexport enum Ricochet2DState {\n\tIdle = 'idle',\n\tRicocheting = 'ricocheting',\n}\n\nexport enum Ricochet2DEvent {\n\tStartRicochet = 'start-ricochet',\n\tEndRicochet = 'end-ricochet',\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\n/**\n * Callback type for ricochet event listeners.\n */\nexport type RicochetCallback = (result: Ricochet2DResult) => void;\n\n/**\n * FSM wrapper with extended state (lastResult).\n * Systems or consumers call `computeRicochet(...)` when a collision occurs.\n */\nexport class Ricochet2DFSM {\n\tpublic readonly machine: SyncStateMachine<Ricochet2DState, Ricochet2DEvent, never>;\n\n\tprivate lastResult: Ricochet2DResult | null = null;\n\tprivate lastUpdatedAtMs: number | null = null;\n\tprivate currentTimeMs: number = 0;\n\tprivate listeners: Set<RicochetCallback> = new Set();\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<Ricochet2DState, Ricochet2DEvent, never>(\n\t\t\tRicochet2DState.Idle,\n\t\t\t[\n\t\t\t\tt(Ricochet2DState.Idle, Ricochet2DEvent.StartRicochet, Ricochet2DState.Ricocheting),\n\t\t\t\tt(Ricochet2DState.Ricocheting, Ricochet2DEvent.EndRicochet, Ricochet2DState.Idle),\n\n\t\t\t\t// Self transitions (no-ops)\n\t\t\t\tt(Ricochet2DState.Idle, Ricochet2DEvent.EndRicochet, Ricochet2DState.Idle),\n\t\t\t\tt(Ricochet2DState.Ricocheting, Ricochet2DEvent.StartRicochet, Ricochet2DState.Ricocheting),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Add a listener for ricochet events.\n\t * @returns Unsubscribe function\n\t */\n\taddListener(callback: RicochetCallback): () => void {\n\t\tthis.listeners.add(callback);\n\t\treturn () => this.listeners.delete(callback);\n\t}\n\n\t/**\n\t * Emit result to all listeners.\n\t */\n\tprivate emitToListeners(result: Ricochet2DResult): void {\n\t\tfor (const callback of this.listeners) {\n\t\t\ttry {\n\t\t\t\tcallback(result);\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error('[Ricochet2DFSM] Listener error:', e);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetState(): Ricochet2DState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Returns the last computed ricochet result, or null if none.\n\t */\n\tgetLastResult(): Ricochet2DResult | null {\n\t\treturn this.lastResult;\n\t}\n\n\t/**\n\t * Best-effort timestamp (ms) of the last computation.\n\t */\n\tgetLastUpdatedAtMs(): number | null {\n\t\treturn this.lastUpdatedAtMs;\n\t}\n\n\t/**\n\t * Set current game time (called by system each frame).\n\t * Used for cooldown calculations.\n\t */\n\tsetCurrentTimeMs(timeMs: number): void {\n\t\tthis.currentTimeMs = timeMs;\n\t}\n\n\t/**\n\t * Check if ricochet is on cooldown (to prevent rapid duplicate applications).\n\t * @param cooldownMs Cooldown duration in milliseconds (default: 50ms)\n\t */\n\tisOnCooldown(cooldownMs: number = 50): boolean {\n\t\tif (this.lastUpdatedAtMs === null) return false;\n\t\treturn (this.currentTimeMs - this.lastUpdatedAtMs) < cooldownMs;\n\t}\n\n\t/**\n\t * Reset cooldown state (e.g., on entity respawn).\n\t */\n\tresetCooldown(): void {\n\t\tthis.lastUpdatedAtMs = null;\n\t}\n\n\t/**\n\t * Compute a ricochet result from collision context.\n\t * Returns the result for the consumer to apply, or null if invalid input.\n\t */\n\tcomputeRicochet(\n\t\tctx: Ricochet2DCollisionContext,\n\t\toptions: {\n\t\t\tminSpeed?: number;\n\t\t\tmaxSpeed?: number;\n\t\t\tspeedMultiplier?: number;\n\t\t\treflectionMode?: 'simple' | 'angled';\n\t\t\tmaxAngleDeg?: number;\n\t\t} = {}\n\t): Ricochet2DResult | null {\n\t\tconst {\n\t\t\tminSpeed = 2,\n\t\t\tmaxSpeed = 20,\n\t\t\tspeedMultiplier = 1.05,\n\t\t\treflectionMode = 'angled',\n\t\t\tmaxAngleDeg = 60,\n\t\t} = options;\n\n\t\t// Extract data from entities if provided\n\t\tconst { selfVelocity, selfPosition, otherPosition, otherSize } = this.extractDataFromEntities(ctx);\n\n\t\tif (!selfVelocity) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst speed = Math.hypot(selfVelocity.x, selfVelocity.y);\n\t\tif (speed === 0) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\t// Compute or extract collision normal\n\t\tconst normal = ctx.contact.normal ?? this.computeNormalFromPositions(selfPosition, otherPosition);\n\t\tif (!normal) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\t// Compute basic reflection\n\t\tlet reflected = this.computeBasicReflection(selfVelocity, normal);\n\n\t\t// Apply angled deflection if requested\n\t\tif (reflectionMode === 'angled') {\n\t\t\treflected = this.computeAngledDeflection(\n\t\t\t\tselfVelocity,\n\t\t\t\tnormal,\n\t\t\t\tspeed,\n\t\t\t\tmaxAngleDeg,\n\t\t\t\tspeedMultiplier,\n\t\t\t\tselfPosition,\n\t\t\t\totherPosition,\n\t\t\t\totherSize,\n\t\t\t\tctx.contact.position\n\t\t\t);\n\t\t}\n\n\t\t// Apply final speed constraints\n\t\treflected = this.applySpeedClamp(reflected, minSpeed, maxSpeed);\n\n\t\tconst result: Ricochet2DResult = {\n\t\t\tvelocity: { x: reflected.x, y: reflected.y, z: 0 },\n\t\t\tspeed: Math.hypot(reflected.x, reflected.y),\n\t\t\tnormal: { x: normal.x, y: normal.y, z: 0 },\n\t\t};\n\n\t\tthis.lastResult = result;\n\t\tthis.lastUpdatedAtMs = this.currentTimeMs;\n\t\tthis.dispatch(Ricochet2DEvent.StartRicochet);\n\t\tthis.emitToListeners(result);\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Extract velocity, position, and size data from entities or context.\n\t */\n\tprivate extractDataFromEntities(ctx: Ricochet2DCollisionContext) {\n\t\tlet selfVelocity = ctx.selfVelocity;\n\t\tlet selfPosition = ctx.selfPosition;\n\t\tlet otherPosition = ctx.otherPosition;\n\t\tlet otherSize = ctx.otherSize;\n\n\t\tconst selfBody = bodyOf(ctx.entity);\n\t\tif (selfBody) {\n\t\t\tconst vel = selfBody.linvel();\n\t\t\tselfVelocity = selfVelocity ?? { x: vel.x, y: vel.y, z: vel.z };\n\t\t\tconst pos = selfBody.translation();\n\t\t\tselfPosition = selfPosition ?? { x: pos.x, y: pos.y, z: pos.z };\n\t\t}\n\n\t\tconst otherBody = bodyOf(ctx.otherEntity);\n\t\tif (otherBody) {\n\t\t\tconst pos = otherBody.translation();\n\t\t\totherPosition = otherPosition ?? { x: pos.x, y: pos.y, z: pos.z };\n\t\t}\n\n\t\tif (ctx.otherEntity && 'size' in ctx.otherEntity) {\n\t\t\tconst size = (ctx.otherEntity as any).size;\n\t\t\tif (size && typeof size.x === 'number') {\n\t\t\t\totherSize = otherSize ?? { x: size.x, y: size.y, z: size.z };\n\t\t\t}\n\t\t}\n\n\t\treturn { selfVelocity, selfPosition, otherPosition, otherSize };\n\t}\n\n\t/**\n\t * Compute collision normal from entity positions using AABB heuristic.\n\t */\n\tprivate computeNormalFromPositions(\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number }\n\t): { x: number; y: number; z?: number } | null {\n\t\tif (!selfPosition || !otherPosition) return null;\n\n\t\tconst dx = selfPosition.x - otherPosition.x;\n\t\tconst dy = selfPosition.y - otherPosition.y;\n\n\t\t// Simple \"which face was hit\" logic for box collisions\n\t\tif (Math.abs(dx) > Math.abs(dy)) {\n\t\t\treturn { x: dx > 0 ? 1 : -1, y: 0, z: 0 };\n\t\t} else {\n\t\t\treturn { x: 0, y: dy > 0 ? 1 : -1, z: 0 };\n\t\t}\n\t}\n\n\t/**\n\t * Compute basic reflection using the formula: v' = v - 2(v·n)n\n\t */\n\tprivate computeBasicReflection(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number }\n\t): { x: number; y: number } {\n\t\tconst vx = velocity.x;\n\t\tconst vy = velocity.y;\n\t\tconst dotProduct = vx * normal.x + vy * normal.y;\n\n\t\treturn {\n\t\t\tx: vx - 2 * dotProduct * normal.x,\n\t\t\ty: vy - 2 * dotProduct * normal.y,\n\t\t};\n\t}\n\n\t/**\n\t * Compute angled deflection for paddle-style reflections.\n\t */\n\tprivate computeAngledDeflection(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number },\n\t\tspeed: number,\n\t\tmaxAngleDeg: number,\n\t\tspeedMultiplier: number,\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number },\n\t\totherSize?: { x: number; y: number; z?: number },\n\t\tcontactPosition?: { x: number; y: number; z?: number }\n\t): { x: number; y: number } {\n\t\tconst maxAngleRad = (maxAngleDeg * Math.PI) / 180;\n\n\t\t// Tangent vector (perpendicular to normal)\n\t\tlet tx = -normal.y;\n\t\tlet ty = normal.x;\n\n\t\t// Ensure tangent points in positive direction of the deflection axis\n\t\t// so that positive offset (right/top) results in positive deflection\n\t\tif (Math.abs(normal.x) > Math.abs(normal.y)) {\n\t\t\t// Vertical face (Normal is X-aligned). Deflection axis is Y.\n\t\t\t// We want ty > 0.\n\t\t\tif (ty < 0) {\n\t\t\t\ttx = -tx;\n\t\t\t\tty = -ty;\n\t\t\t}\n\t\t} else {\n\t\t\t// Horizontal face (Normal is Y-aligned). Deflection axis is X.\n\t\t\t// We want tx > 0.\n\t\t\tif (tx < 0) {\n\t\t\t\ttx = -tx;\n\t\t\t\tty = -ty;\n\t\t\t}\n\t\t}\n\n\t\t// Compute offset based on hit position\n\t\tconst offset = this.computeHitOffset(\n\t\t\tvelocity,\n\t\t\tnormal,\n\t\t\tspeed,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tselfPosition,\n\t\t\totherPosition,\n\t\t\totherSize,\n\t\t\tcontactPosition\n\t\t);\n\n\t\tconst angle = clamp(offset, -1, 1) * maxAngleRad;\n\n\t\tconst cosA = Math.cos(angle);\n\t\tconst sinA = Math.sin(angle);\n\n\t\tconst newSpeed = speed * speedMultiplier;\n\n\t\treturn {\n\t\t\tx: newSpeed * (normal.x * cosA + tx * sinA),\n\t\t\ty: newSpeed * (normal.y * cosA + ty * sinA),\n\t\t};\n\t}\n\n\t/**\n\t * Compute hit offset for angled deflection (-1 to 1).\n\t */\n\tprivate computeHitOffset(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number },\n\t\tspeed: number,\n\t\ttx: number,\n\t\tty: number,\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number },\n\t\totherSize?: { x: number; y: number; z?: number },\n\t\tcontactPosition?: { x: number; y: number; z?: number }\n\t): number {\n\t\t// Use position-based offset if available\n\t\tif (otherPosition && otherSize) {\n\t\t\tconst useY = Math.abs(normal.x) > Math.abs(normal.y);\n\t\t\tconst halfExtent = useY ? otherSize.y / 2 : otherSize.x / 2;\n\n\t\t\tif (useY) {\n\t\t\t\tconst selfY = selfPosition?.y ?? contactPosition?.y ?? 0;\n\t\t\t\tconst paddleY = otherPosition.y;\n\t\t\t\treturn (selfY - paddleY) / halfExtent;\n\t\t\t} else {\n\t\t\t\tconst selfX = selfPosition?.x ?? contactPosition?.x ?? 0;\n\t\t\t\tconst paddleX = otherPosition.x;\n\t\t\t\treturn (selfX - paddleX) / halfExtent;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback: use velocity-based offset\n\t\treturn (velocity.x * tx + velocity.y * ty) / speed;\n\t}\n\n\t/**\n\t * Apply speed constraints to the reflected velocity.\n\t */\n\tprivate applySpeedClamp(\n\t\tvelocity: { x: number; y: number },\n\t\tminSpeed: number,\n\t\tmaxSpeed: number\n\t): { x: number; y: number } {\n\t\tconst currentSpeed = Math.hypot(velocity.x, velocity.y);\n\t\tif (currentSpeed === 0) return velocity;\n\n\t\tconst targetSpeed = clamp(currentSpeed, minSpeed, maxSpeed);\n\t\tconst scale = targetSpeed / currentSpeed;\n\n\t\treturn {\n\t\t\tx: velocity.x * scale,\n\t\t\ty: velocity.y * scale,\n\t\t};\n\t}\n\n\t/**\n\t * Clear the ricochet state (call after consumer has applied the result).\n\t */\n\tclearRicochet(): void {\n\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t}\n\n\tprivate dispatch(event: Ricochet2DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n}\n","/**\n * Ricochet2DBehavior\n *\n * Computes 2D ricochet/reflection results for entities during collisions.\n * The behavior computes the result; the consumer decides how to apply it.\n *\n * Use `getRicochet(ctx)` on the behavior handle to compute reflection results.\n */\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { Ricochet2DFSM, type Ricochet2DResult, type Ricochet2DCollisionContext, type RicochetCallback } from './ricochet-2d-fsm';\nimport {\n\tStageRicochetDim,\n\tStageRicochetReflection,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\nexport type { Ricochet2DResult };\n\nexport interface Ricochet2DOptions {\n\t/**\n\t * Minimum speed after reflection.\n\t * Default: 2\n\t */\n\tminSpeed: number;\n\n\t/**\n\t * Maximum speed after reflection.\n\t * Default: 20\n\t */\n\tmaxSpeed: number;\n\n\t/**\n\t * Speed multiplier applied during angled reflection.\n\t * Default: 1.05\n\t */\n\tspeedMultiplier: number;\n\n\t/**\n\t * Reflection mode:\n\t * - 'simple': Basic axis inversion\n\t * - 'angled': Paddle-style deflection based on contact point\n\t * Default: 'angled'\n\t */\n\treflectionMode: 'simple' | 'angled';\n\n\t/**\n\t * Maximum deflection angle in degrees for angled mode.\n\t * Default: 60\n\t */\n\tmaxAngleDeg: number;\n}\n\n/**\n * Handle methods provided by Ricochet2DBehavior\n */\nexport interface Ricochet2DHandle {\n\t/**\n\t * Compute a ricochet/reflection result from collision context.\n\t * Returns the result for the consumer to apply, or null if invalid input.\n\t *\n\t * @param ctx - Collision context with selfVelocity and contact normal\n\t * @returns Ricochet result with velocity, speed, and normal, or null\n\t */\n\tgetRicochet(ctx: Ricochet2DCollisionContext): Ricochet2DResult | null;\n\n\t/**\n\t * Compute ricochet and apply velocity directly via transformStore.\n\t * Emits to onRicochet listeners if successful.\n\t *\n\t * @param ctx - Collision context with entity and contact normal\n\t * @returns true if ricochet was computed and applied, false otherwise\n\t */\n\tapplyRicochet(ctx: Ricochet2DCollisionContext): boolean;\n\n\t/**\n\t * Get the last computed ricochet result, or null if none.\n\t */\n\tgetLastResult(): Ricochet2DResult | null;\n\n\t/**\n\t * Register a listener for ricochet events.\n\t * Called whenever a ricochet is computed (from getRicochet or applyRicochet).\n\t *\n\t * @param callback - Function to call with ricochet result\n\t * @returns Unsubscribe function\n\t */\n\tonRicochet(callback: RicochetCallback): () => void;\n}\n\nconst defaultOptions: Ricochet2DOptions = {\n\tminSpeed: 2,\n\tmaxSpeed: 20,\n\tspeedMultiplier: 1.05,\n\treflectionMode: 'angled',\n\tmaxAngleDeg: 60,\n};\n\nconst RICOCHET_BEHAVIOR_KEY = Symbol.for('zylem:behavior:ricochet-2d');\n\n/**\n * Creates behavior-specific handle methods for Ricochet2DBehavior.\n */\nfunction createRicochet2DHandle(\n\tref: BehaviorRef<Ricochet2DOptions>\n): Ricochet2DHandle {\n\treturn {\n\t\tgetRicochet: (ctx: Ricochet2DCollisionContext) => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) return null;\n\t\t\treturn fsm.computeRicochet(ctx, ref.options);\n\t\t},\n\t\tapplyRicochet: (ctx: Ricochet2DCollisionContext): boolean => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) return false;\n\n\t\t\t// Skip if on cooldown (prevents rapid duplicate applications)\n\t\t\tif (fsm.isOnCooldown()) return false;\n\n\t\t\tconst result = fsm.computeRicochet(ctx, ref.options);\n\t\t\tif (!result) return false;\n\n\t\t\t// Apply velocity via transformStore\n\t\t\tconst entity = ctx.entity as any;\n\t\t\tif (entity?.transformStore) {\n\t\t\t\tentity.transformStore.velocity.x = result.velocity.x;\n\t\t\t\tentity.transformStore.velocity.y = result.velocity.y;\n\t\t\t\tentity.transformStore.velocity.z = result.velocity.z ?? 0;\n\t\t\t\tentity.transformStore.dirty.velocityX = true;\n\t\t\t\tentity.transformStore.dirty.velocityY = true;\n\t\t\t\tentity.transformStore.dirty.velocityZ = true;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t\tgetLastResult: () => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\treturn fsm?.getLastResult() ?? null;\n\t\t},\n\t\tonRicochet: (callback: RicochetCallback): (() => void) => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) {\n\t\t\t\t// FSM not ready yet - queue callback for later\n\t\t\t\t// System will apply pending callbacks when FSM is created\n\t\t\t\tif (!(ref as any).pendingListeners) {\n\t\t\t\t\t(ref as any).pendingListeners = [];\n\t\t\t\t}\n\t\t\t\t(ref as any).pendingListeners.push(callback);\n\t\t\t\t\n\t\t\t\t// Return unsubscribe that removes from pending queue\n\t\t\t\treturn () => {\n\t\t\t\t\tconst pending = (ref as any).pendingListeners as RicochetCallback[];\n\t\t\t\t\tconst idx = pending.indexOf(callback);\n\t\t\t\t\tif (idx >= 0) pending.splice(idx, 1);\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn fsm.addListener(callback);\n\t\t},\n\t};\n}\n\n/**\n * Ricochet2DSystem\n *\n * Stage-level system that:\n * - finds entities with this behavior attached\n * - lazily creates FSM instances for each entity\n *\n * Note: This behavior is consumer-driven. The system only manages FSM lifecycle.\n * Consumers call `getRicochet(ctx)` during collision callbacks to compute results.\n */\nclass Ricochet2DSystem implements BehaviorSystem {\n\tprivate elapsedMs: number = 0;\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\tthis.elapsedMs += delta * 1000;\n\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst ricochetRef = link.ref as any;\n\t\t\tconst gameEntity = link.entity as any;\n\n\t\t\tif (!ricochetRef.fsm) {\n\t\t\t\tricochetRef.fsm = new Ricochet2DFSM();\n\n\t\t\t\tconst pending = (ricochetRef as any).pendingListeners as RicochetCallback[] | undefined;\n\t\t\t\tif (pending) {\n\t\t\t\t\tfor (const cb of pending) {\n\t\t\t\t\t\tricochetRef.fsm.addListener(cb);\n\t\t\t\t\t}\n\t\t\t\t\t(ricochetRef as any).pendingListeners = [];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tricochetRef.fsm.setCurrentTimeMs(this.elapsedMs);\n\n\t\t\tconst handle = (gameEntity?.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, ricochetRef.options as Ricochet2DOptions);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Ricochet2DOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst reflectionMode = options.reflectionMode === 'simple'\n\t\t\t? StageRicochetReflection.Mirror\n\t\t\t: StageRicochetReflection.Angled;\n\t\tthis.wasmStage.attachRicochet(handle, StageRicochetDim.Two, {\n\t\t\tminSpeed: options.minSpeed,\n\t\t\tmaxSpeed: options.maxSpeed,\n\t\t\tspeedMultiplier: options.speedMultiplier,\n\t\t\tmaxAngleDeg: options.maxAngleDeg,\n\t\t\treflectionMode,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\tconst ricochetRef = link.ref as any;\n\t\t\t\tif (ricochetRef?.fsm) {\n\t\t\t\t\tricochetRef.fsm.resetCooldown();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * Ricochet2DBehavior\n *\n * @example\n * ```ts\n * import { Ricochet2DBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const ball = createSphere({ ... });\n * const ricochet = ball.use(Ricochet2DBehavior, {\n * minSpeed: 3,\n * maxSpeed: 15,\n * reflectionMode: 'angled',\n * });\n *\n * ball.onCollision(({ entity, other }) => {\n * const velocity = entity.body.linvel();\n * const result = ricochet.getRicochet({\n * selfVelocity: velocity,\n * contact: { normal: { x: 1, y: 0 } }, // from collision data\n * });\n *\n * if (result) {\n * entity.body.setLinvel(result.velocity, true);\n * }\n * });\n * ```\n */\nexport const Ricochet2DBehavior = defineBehavior({\n\tname: 'ricochet-2d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Ricochet2DSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createRicochet2DHandle,\n});\n"],"mappings":"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","names":["Ricochet2DState","Ricochet2DEvent"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/lib/core/vector.ts
|
|
2
2
|
import { Vector2 as ThreeVector2, Vector3 as ThreeVector3 } from "three";
|
|
3
|
-
import { Vector3 as RapierVector3 } from "@dimforge/rapier3d-compat";
|
|
4
3
|
var VEC2_ZERO = Object.freeze({
|
|
5
4
|
x: 0,
|
|
6
5
|
y: 0
|
|
@@ -99,10 +98,6 @@ function toThreeVector3(input, defaults = VEC3_ZERO) {
|
|
|
99
98
|
const { x, y, z } = normalizeVec3(input, defaults);
|
|
100
99
|
return new ThreeVector3(x, y, z);
|
|
101
100
|
}
|
|
102
|
-
function toRapierVector3(input, defaults = VEC3_ZERO) {
|
|
103
|
-
const { x, y, z } = normalizeVec3(input, defaults);
|
|
104
|
-
return new RapierVector3(x, y, z);
|
|
105
|
-
}
|
|
106
101
|
|
|
107
102
|
export {
|
|
108
103
|
VEC2_ZERO,
|
|
@@ -114,7 +109,6 @@ export {
|
|
|
114
109
|
normalizeVec2,
|
|
115
110
|
normalizeVec3,
|
|
116
111
|
toThreeVector2,
|
|
117
|
-
toThreeVector3
|
|
118
|
-
toRapierVector3
|
|
112
|
+
toThreeVector3
|
|
119
113
|
};
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-M3QDKKDF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/core/vector.ts"],"sourcesContent":["import { Vector2 as ThreeVector2, Vector3 as ThreeVector3 } from 'three';\n\nexport type Vec2 = ThreeVector2;\nexport type Vec3 = ThreeVector3 | Vec3Components;\n\nexport type Vec2Components = { x: number; y: number };\nexport type Vec3Components = { x: number; y: number; z: number };\n\ntype Vec2Tuple = readonly [number?, number?] & { x?: number; y?: number };\ntype Vec3Tuple = readonly [number?, number?, number?] & {\n x?: number;\n y?: number;\n z?: number;\n};\n\nexport type Vec2Input = Vec2 | { x?: number; y?: number } | Vec2Tuple;\nexport type Vec3Input =\n | Vec3\n | { x?: number; y?: number; z?: number }\n | Vec3Tuple;\n\nexport const VEC2_ZERO: Readonly<Vec2Components> = Object.freeze({\n x: 0,\n y: 0,\n});\nexport const VEC2_ONE: Readonly<Vec2Components> = Object.freeze({ x: 1, y: 1 });\nexport const VEC3_ZERO: Readonly<Vec3Components> = Object.freeze({\n x: 0,\n y: 0,\n z: 0,\n});\nexport const VEC3_ONE: Readonly<Vec3Components> = Object.freeze({\n x: 1,\n y: 1,\n z: 1,\n});\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nfunction hasVec2Shape(value: unknown): value is { x?: unknown; y?: unknown } {\n return (\n value != null && typeof value === 'object' && ('x' in value || 'y' in value)\n );\n}\n\nfunction hasVec3Shape(\n value: unknown,\n): value is { x?: unknown; y?: unknown; z?: unknown } {\n return (\n value != null &&\n typeof value === 'object' &&\n ('x' in value || 'y' in value || 'z' in value)\n );\n}\n\nfunction getArrayAxis(\n value: readonly unknown[] | undefined,\n index: number,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n const axis = value[index];\n return isFiniteNumber(axis) ? axis : fallback;\n}\n\nfunction getObjectAxis(\n value: { [key: string]: unknown } | undefined,\n key: 'x' | 'y' | 'z',\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n const axis = value[key];\n return isFiniteNumber(axis) ? axis : fallback;\n}\n\nfunction getVec2Axis(\n value: Vec2Input | Partial<Vec2Components> | null | undefined,\n key: 'x' | 'y',\n index: 0 | 1,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n if (Array.isArray(value)) {\n return getArrayAxis(value, index, fallback);\n }\n return getObjectAxis(value as { [key: string]: unknown }, key, fallback);\n}\n\nfunction getVec3Axis(\n value: Vec3Input | Partial<Vec3Components> | null | undefined,\n key: 'x' | 'y' | 'z',\n index: 0 | 1 | 2,\n fallback: number,\n): number {\n if (!value) {\n return fallback;\n }\n if (Array.isArray(value)) {\n return getArrayAxis(value, index, fallback);\n }\n return getObjectAxis(value as { [key: string]: unknown }, key, fallback);\n}\n\nfunction normalizeVec2Defaults(\n defaults: Vec2Input | Partial<Vec2Components> | null | undefined,\n): Vec2Components {\n return {\n x: getVec2Axis(defaults, 'x', 0, 0),\n y: getVec2Axis(defaults, 'y', 1, 0),\n };\n}\n\nfunction normalizeVec3Defaults(\n defaults: Vec3Input | Partial<Vec3Components> | null | undefined,\n): Vec3Components {\n return {\n x: getVec3Axis(defaults, 'x', 0, 0),\n y: getVec3Axis(defaults, 'y', 1, 0),\n z: getVec3Axis(defaults, 'z', 2, 0),\n };\n}\n\nexport function isVec2Input(value: unknown): value is Vec2Input {\n return Array.isArray(value) || hasVec2Shape(value);\n}\n\nexport function isVec3Input(value: unknown): value is Vec3Input {\n return Array.isArray(value) || hasVec3Shape(value);\n}\n\nexport function normalizeVec2(\n input?: Vec2Input | null,\n defaults: Vec2Input | Partial<Vec2Components> = VEC2_ZERO,\n): Vec2Components {\n const fallback = normalizeVec2Defaults(defaults);\n return {\n x: getVec2Axis(input, 'x', 0, fallback.x),\n y: getVec2Axis(input, 'y', 1, fallback.y),\n };\n}\n\nexport function normalizeVec3(\n input?: Vec3Input | null,\n defaults: Vec3Input | Partial<Vec3Components> = VEC3_ZERO,\n): Vec3Components {\n const fallback = normalizeVec3Defaults(defaults);\n return {\n x: getVec3Axis(input, 'x', 0, fallback.x),\n y: getVec3Axis(input, 'y', 1, fallback.y),\n z: getVec3Axis(input, 'z', 2, fallback.z),\n };\n}\n\nexport function toThreeVector2(\n input?: Vec2Input | null,\n defaults: Vec2Input | Partial<Vec2Components> = VEC2_ZERO,\n): ThreeVector2 {\n const { x, y } = normalizeVec2(input, defaults);\n return new ThreeVector2(x, y);\n}\n\nexport function toThreeVector3(\n input?: Vec3Input | null,\n defaults: Vec3Input | Partial<Vec3Components> = VEC3_ZERO,\n): ThreeVector3 {\n const { x, y, z } = normalizeVec3(input, defaults);\n return new ThreeVector3(x, y, z);\n}\n\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
fireShooter2DIfRequested
|
|
3
|
-
|
|
4
|
-
resolveAim2D
|
|
5
|
-
} from "./chunk-UL6Q5HDP.js";
|
|
2
|
+
fireShooter2DIfRequested
|
|
3
|
+
} from "./chunk-52FJIDGL.js";
|
|
6
4
|
import {
|
|
7
5
|
createThrusterInputComponent
|
|
8
6
|
} from "./chunk-IZJFUAXB.js";
|
|
7
|
+
import {
|
|
8
|
+
getEntityFacingAngle2D,
|
|
9
|
+
resolveAim2D
|
|
10
|
+
} from "./chunk-TBUKJKY6.js";
|
|
9
11
|
|
|
10
12
|
// src/lib/coordinators/multidirectional-space-shooter.coordinator.ts
|
|
11
13
|
var MultidirectionalSpaceShooterCoordinator = class {
|
|
@@ -40,4 +42,4 @@ var MultidirectionalSpaceShooterCoordinator = class {
|
|
|
40
42
|
export {
|
|
41
43
|
MultidirectionalSpaceShooterCoordinator
|
|
42
44
|
};
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
45
|
+
//# sourceMappingURL=chunk-NQPYMUDF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/multidirectional-space-shooter.coordinator.ts"],"sourcesContent":["import {\n\tcreateThrusterInputComponent,\n\ttype ThrusterInputComponent,\n} from '../behaviors/thruster/components';\nimport type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../behaviors/shooter-2d/shooter-2d.descriptor';\nimport { getEntityFacingAngle2D, resolveAim2D } from './shared/top-down-aim';\nimport {\n\tfireShooter2DIfRequested,\n\ttype Shooter2DAimFireInput,\n} from './shared/shooter-fire';\n\nexport interface MultidirectionalSpaceShooterInput extends Shooter2DAimFireInput {\n\tmoveX: number;\n\tmoveY: number;\n}\n\nexport type MultidirectionalSpaceShooterEntity = Shooter2DSourceEntity & {\n\t$thruster?: ThrusterInputComponent;\n\tsetRotationZ(angle: number): void;\n};\n\n/**\n * Coordinator that fans a single input snapshot out to the thruster behavior\n * (vector thrust), entity rotation (aim), and the Shooter2D behavior (fire\n * requests).\n */\nexport class MultidirectionalSpaceShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: MultidirectionalSpaceShooterEntity,\n\t\tprivate shooter: Shooter2DHandle,\n\t\tprivate stage: Shooter2DStageLike,\n\t) {}\n\n\tpublic update(input: MultidirectionalSpaceShooterInput): void {\n\t\tif (!this.entity.$thruster) {\n\t\t\tthis.entity.$thruster = createThrusterInputComponent();\n\t\t}\n\n\t\tthis.entity.$thruster.thrustX = input.moveX;\n\t\tthis.entity.$thruster.thrustY = input.moveY;\n\t\tthis.entity.$thruster.thrust = 0;\n\t\tthis.entity.$thruster.rotate = 0;\n\n\t\tconst aim = resolveAim2D(\n\t\t\tinput.aimX,\n\t\t\tinput.aimY,\n\t\t\tgetEntityFacingAngle2D(this.entity),\n\t\t);\n\t\tif (aim.hasAimInput) {\n\t\t\tthis.entity.setRotationZ(aim.angle);\n\t\t}\n\n\t\tfireShooter2DIfRequested(this.entity, this.shooter, this.stage, input, aim);\n\t}\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/lib/coordinators/multidirectional-space-shooter.coordinator.ts"],"sourcesContent":["import {\n\tcreateThrusterInputComponent,\n\ttype ThrusterInputComponent,\n} from '../behaviors/thruster/components';\nimport type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../behaviors/shooter-2d/shooter-2d.descriptor';\nimport { getEntityFacingAngle2D, resolveAim2D } from './shared/top-down-aim';\nimport {\n\tfireShooter2DIfRequested,\n\ttype Shooter2DAimFireInput,\n} from './shared/shooter-fire';\n\nexport interface MultidirectionalSpaceShooterInput extends Shooter2DAimFireInput {\n\tmoveX: number;\n\tmoveY: number;\n}\n\nexport type MultidirectionalSpaceShooterEntity = Shooter2DSourceEntity & {\n\t$thruster?: ThrusterInputComponent;\n\tsetRotationZ(angle: number): void;\n};\n\n/**\n * Coordinator that fans a single input snapshot out to the thruster behavior\n * (vector thrust), entity rotation (aim), and the Shooter2D behavior (fire\n * requests).\n */\nexport class MultidirectionalSpaceShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: MultidirectionalSpaceShooterEntity,\n\t\tprivate shooter: Shooter2DHandle,\n\t\tprivate stage: Shooter2DStageLike,\n\t) {}\n\n\tpublic update(input: MultidirectionalSpaceShooterInput): void {\n\t\tif (!this.entity.$thruster) {\n\t\t\tthis.entity.$thruster = createThrusterInputComponent();\n\t\t}\n\n\t\tthis.entity.$thruster.thrustX = input.moveX;\n\t\tthis.entity.$thruster.thrustY = input.moveY;\n\t\tthis.entity.$thruster.thrust = 0;\n\t\tthis.entity.$thruster.rotate = 0;\n\n\t\tconst aim = resolveAim2D(\n\t\t\tinput.aimX,\n\t\t\tinput.aimY,\n\t\t\tgetEntityFacingAngle2D(this.entity),\n\t\t);\n\t\tif (aim.hasAimInput) {\n\t\t\tthis.entity.setRotationZ(aim.angle);\n\t\t}\n\n\t\tfireShooter2DIfRequested(this.entity, this.shooter, this.stage, input, aim);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AA8BO,IAAM,0CAAN,MAA8C;AAAA,EACpD,YACS,QACA,SACA,OACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAHM;AAAA,EACA;AAAA,EACA;AAAA,EAGF,OAAO,OAAgD;AAC7D,QAAI,CAAC,KAAK,OAAO,WAAW;AAC3B,WAAK,OAAO,YAAY,6BAA6B;AAAA,IACtD;AAEA,SAAK,OAAO,UAAU,UAAU,MAAM;AACtC,SAAK,OAAO,UAAU,UAAU,MAAM;AACtC,SAAK,OAAO,UAAU,SAAS;AAC/B,SAAK,OAAO,UAAU,SAAS;AAE/B,UAAM,MAAM;AAAA,MACX,MAAM;AAAA,MACN,MAAM;AAAA,MACN,uBAAuB,KAAK,MAAM;AAAA,IACnC;AACA,QAAI,IAAI,aAAa;AACpB,WAAK,OAAO,aAAa,IAAI,KAAK;AAAA,IACnC;AAEA,6BAAyB,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,OAAO,GAAG;AAAA,EAC3E;AACD;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getBounds2DNormalFromHits
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OPZ2LVS2.js";
|
|
4
4
|
import {
|
|
5
5
|
updateBoundaryRicochet
|
|
6
6
|
} from "./chunk-LL4FLHIY.js";
|
|
@@ -37,4 +37,4 @@ var BoundaryRicochetCoordinator = class {
|
|
|
37
37
|
export {
|
|
38
38
|
BoundaryRicochetCoordinator
|
|
39
39
|
};
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-NW4SE5XW.js.map
|
|
@@ -41,26 +41,6 @@ function constrainMovementToBounds2D(hits, moveX, moveY) {
|
|
|
41
41
|
}
|
|
42
42
|
return { moveX: adjustedX, moveY: adjustedY };
|
|
43
43
|
}
|
|
44
|
-
function wrapPoint2D(position, bounds) {
|
|
45
|
-
let x = position.x;
|
|
46
|
-
let y = position.y;
|
|
47
|
-
let wrapped = false;
|
|
48
|
-
if (position.x < bounds.minX) {
|
|
49
|
-
x = bounds.maxX - (bounds.minX - position.x);
|
|
50
|
-
wrapped = true;
|
|
51
|
-
} else if (position.x > bounds.maxX) {
|
|
52
|
-
x = bounds.minX + (position.x - bounds.maxX);
|
|
53
|
-
wrapped = true;
|
|
54
|
-
}
|
|
55
|
-
if (position.y < bounds.minY) {
|
|
56
|
-
y = bounds.maxY - (bounds.minY - position.y);
|
|
57
|
-
wrapped = true;
|
|
58
|
-
} else if (position.y > bounds.maxY) {
|
|
59
|
-
y = bounds.minY + (position.y - bounds.maxY);
|
|
60
|
-
wrapped = true;
|
|
61
|
-
}
|
|
62
|
-
return { x, y, wrapped };
|
|
63
|
-
}
|
|
64
44
|
function getBounds2DNormalFromHits(hits) {
|
|
65
45
|
let x = 0;
|
|
66
46
|
let y = 0;
|
|
@@ -76,7 +56,6 @@ export {
|
|
|
76
56
|
computeBounds2DHits,
|
|
77
57
|
hasAnyBounds2DHit,
|
|
78
58
|
constrainMovementToBounds2D,
|
|
79
|
-
wrapPoint2D,
|
|
80
59
|
getBounds2DNormalFromHits
|
|
81
60
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
61
|
+
//# sourceMappingURL=chunk-OPZ2LVS2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/shared/bounds-2d.ts"],"sourcesContent":["export interface Bounds2DPoint {\n\tx: number;\n\ty: number;\n}\n\nexport interface Bounds2DRect {\n\tminX: number;\n\tmaxX: number;\n\tminY: number;\n\tmaxY: number;\n}\n\nexport interface Bounds2DSize {\n\twidth: number;\n\theight: number;\n\tcenterX?: number;\n\tcenterY?: number;\n}\n\nexport interface Bounds2DHits {\n\tleft: boolean;\n\tright: boolean;\n\ttop: boolean;\n\tbottom: boolean;\n}\n\nexport interface Bounds2DWrapResult {\n\tx: number;\n\ty: number;\n\twrapped: boolean;\n}\n\nexport function createBounds2DRect({\n\twidth,\n\theight,\n\tcenterX = 0,\n\tcenterY = 0,\n}: Bounds2DSize): Bounds2DRect {\n\tconst halfWidth = width / 2;\n\tconst halfHeight = height / 2;\n\treturn {\n\t\tminX: centerX - halfWidth,\n\t\tmaxX: centerX + halfWidth,\n\t\tminY: centerY - halfHeight,\n\t\tmaxY: centerY + halfHeight,\n\t};\n}\n\nexport function computeBounds2DHits(\n\tposition: Bounds2DPoint,\n\tbounds: Bounds2DRect,\n): Bounds2DHits {\n\tconst hits: Bounds2DHits = {\n\t\ttop: false,\n\t\tbottom: false,\n\t\tleft: false,\n\t\tright: false,\n\t};\n\n\tif (position.x <= bounds.minX) hits.left = true;\n\telse if (position.x >= bounds.maxX) hits.right = true;\n\n\tif (position.y <= bounds.minY) hits.bottom = true;\n\telse if (position.y >= bounds.maxY) hits.top = true;\n\n\treturn hits;\n}\n\nexport function hasAnyBounds2DHit(hits: Bounds2DHits): boolean {\n\treturn hits.left || hits.right || hits.top || hits.bottom;\n}\n\nexport function constrainMovementToBounds2D(\n\thits: Bounds2DHits,\n\tmoveX: number,\n\tmoveY: number,\n): { moveX: number; moveY: number } {\n\tlet adjustedX = moveX;\n\tlet adjustedY = moveY;\n\n\tif ((hits.left && moveX < 0) || (hits.right && moveX > 0)) {\n\t\tadjustedX = 0;\n\t}\n\n\tif ((hits.bottom && moveY < 0) || (hits.top && moveY > 0)) {\n\t\tadjustedY = 0;\n\t}\n\n\treturn { moveX: adjustedX, moveY: adjustedY };\n}\n\nexport function wrapPoint2D(\n\tposition: Bounds2DPoint,\n\tbounds: Bounds2DRect,\n): Bounds2DWrapResult {\n\tlet x = position.x;\n\tlet y = position.y;\n\tlet wrapped = false;\n\n\tif (position.x < bounds.minX) {\n\t\tx = bounds.maxX - (bounds.minX - position.x);\n\t\twrapped = true;\n\t} else if (position.x > bounds.maxX) {\n\t\tx = bounds.minX + (position.x - bounds.maxX);\n\t\twrapped = true;\n\t}\n\n\tif (position.y < bounds.minY) {\n\t\ty = bounds.maxY - (bounds.minY - position.y);\n\t\twrapped = true;\n\t} else if (position.y > bounds.maxY) {\n\t\ty = bounds.minY + (position.y - bounds.maxY);\n\t\twrapped = true;\n\t}\n\n\treturn { x, y, wrapped };\n}\n\nexport function getBounds2DNormalFromHits(\n\thits: Bounds2DHits,\n): { x: number; y: number } {\n\tlet x = 0;\n\tlet y = 0;\n\n\tif (hits.left) x = 1;\n\tif (hits.right) x = -1;\n\tif (hits.bottom) y = 1;\n\tif (hits.top) y = -1;\n\n\treturn { x, y };\n}\n"],"mappings":";AAgCO,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AACX,GAA+B;AAC9B,QAAM,YAAY,QAAQ;AAC1B,QAAM,aAAa,SAAS;AAC5B,SAAO;AAAA,IACN,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,EACjB;AACD;AAEO,SAAS,oBACf,UACA,QACe;AACf,QAAM,OAAqB;AAAA,IAC1B,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,EACR;AAEA,MAAI,SAAS,KAAK,OAAO,KAAM,MAAK,OAAO;AAAA,WAClC,SAAS,KAAK,OAAO,KAAM,MAAK,QAAQ;AAEjD,MAAI,SAAS,KAAK,OAAO,KAAM,MAAK,SAAS;AAAA,WACpC,SAAS,KAAK,OAAO,KAAM,MAAK,MAAM;AAE/C,SAAO;AACR;AAEO,SAAS,kBAAkB,MAA6B;AAC9D,SAAO,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK;AACpD;AAEO,SAAS,4BACf,MACA,OACA,OACmC;AACnC,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,MAAK,KAAK,QAAQ,QAAQ,KAAO,KAAK,SAAS,QAAQ,GAAI;AAC1D,gBAAY;AAAA,EACb;AAEA,MAAK,KAAK,UAAU,QAAQ,KAAO,KAAK,OAAO,QAAQ,GAAI;AAC1D,gBAAY;AAAA,EACb;AAEA,SAAO,EAAE,OAAO,WAAW,OAAO,UAAU;AAC7C;
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/shared/bounds-2d.ts"],"sourcesContent":["export interface Bounds2DPoint {\n\tx: number;\n\ty: number;\n}\n\nexport interface Bounds2DRect {\n\tminX: number;\n\tmaxX: number;\n\tminY: number;\n\tmaxY: number;\n}\n\nexport interface Bounds2DSize {\n\twidth: number;\n\theight: number;\n\tcenterX?: number;\n\tcenterY?: number;\n}\n\nexport interface Bounds2DHits {\n\tleft: boolean;\n\tright: boolean;\n\ttop: boolean;\n\tbottom: boolean;\n}\n\nexport interface Bounds2DWrapResult {\n\tx: number;\n\ty: number;\n\twrapped: boolean;\n}\n\nexport function createBounds2DRect({\n\twidth,\n\theight,\n\tcenterX = 0,\n\tcenterY = 0,\n}: Bounds2DSize): Bounds2DRect {\n\tconst halfWidth = width / 2;\n\tconst halfHeight = height / 2;\n\treturn {\n\t\tminX: centerX - halfWidth,\n\t\tmaxX: centerX + halfWidth,\n\t\tminY: centerY - halfHeight,\n\t\tmaxY: centerY + halfHeight,\n\t};\n}\n\nexport function computeBounds2DHits(\n\tposition: Bounds2DPoint,\n\tbounds: Bounds2DRect,\n): Bounds2DHits {\n\tconst hits: Bounds2DHits = {\n\t\ttop: false,\n\t\tbottom: false,\n\t\tleft: false,\n\t\tright: false,\n\t};\n\n\tif (position.x <= bounds.minX) hits.left = true;\n\telse if (position.x >= bounds.maxX) hits.right = true;\n\n\tif (position.y <= bounds.minY) hits.bottom = true;\n\telse if (position.y >= bounds.maxY) hits.top = true;\n\n\treturn hits;\n}\n\nexport function hasAnyBounds2DHit(hits: Bounds2DHits): boolean {\n\treturn hits.left || hits.right || hits.top || hits.bottom;\n}\n\nexport function constrainMovementToBounds2D(\n\thits: Bounds2DHits,\n\tmoveX: number,\n\tmoveY: number,\n): { moveX: number; moveY: number } {\n\tlet adjustedX = moveX;\n\tlet adjustedY = moveY;\n\n\tif ((hits.left && moveX < 0) || (hits.right && moveX > 0)) {\n\t\tadjustedX = 0;\n\t}\n\n\tif ((hits.bottom && moveY < 0) || (hits.top && moveY > 0)) {\n\t\tadjustedY = 0;\n\t}\n\n\treturn { moveX: adjustedX, moveY: adjustedY };\n}\n\nexport function wrapPoint2D(\n\tposition: Bounds2DPoint,\n\tbounds: Bounds2DRect,\n): Bounds2DWrapResult {\n\tlet x = position.x;\n\tlet y = position.y;\n\tlet wrapped = false;\n\n\tif (position.x < bounds.minX) {\n\t\tx = bounds.maxX - (bounds.minX - position.x);\n\t\twrapped = true;\n\t} else if (position.x > bounds.maxX) {\n\t\tx = bounds.minX + (position.x - bounds.maxX);\n\t\twrapped = true;\n\t}\n\n\tif (position.y < bounds.minY) {\n\t\ty = bounds.maxY - (bounds.minY - position.y);\n\t\twrapped = true;\n\t} else if (position.y > bounds.maxY) {\n\t\ty = bounds.minY + (position.y - bounds.maxY);\n\t\twrapped = true;\n\t}\n\n\treturn { x, y, wrapped };\n}\n\nexport function getBounds2DNormalFromHits(\n\thits: Bounds2DHits,\n): { x: number; y: number } {\n\tlet x = 0;\n\tlet y = 0;\n\n\tif (hits.left) x = 1;\n\tif (hits.right) x = -1;\n\tif (hits.bottom) y = 1;\n\tif (hits.top) y = -1;\n\n\treturn { x, y };\n}\n"],"mappings":";AAgCO,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AACX,GAA+B;AAC9B,QAAM,YAAY,QAAQ;AAC1B,QAAM,aAAa,SAAS;AAC5B,SAAO;AAAA,IACN,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,IAChB,MAAM,UAAU;AAAA,EACjB;AACD;AAEO,SAAS,oBACf,UACA,QACe;AACf,QAAM,OAAqB;AAAA,IAC1B,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,OAAO;AAAA,EACR;AAEA,MAAI,SAAS,KAAK,OAAO,KAAM,MAAK,OAAO;AAAA,WAClC,SAAS,KAAK,OAAO,KAAM,MAAK,QAAQ;AAEjD,MAAI,SAAS,KAAK,OAAO,KAAM,MAAK,SAAS;AAAA,WACpC,SAAS,KAAK,OAAO,KAAM,MAAK,MAAM;AAE/C,SAAO;AACR;AAEO,SAAS,kBAAkB,MAA6B;AAC9D,SAAO,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK;AACpD;AAEO,SAAS,4BACf,MACA,OACA,OACmC;AACnC,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,MAAK,KAAK,QAAQ,QAAQ,KAAO,KAAK,SAAS,QAAQ,GAAI;AAC1D,gBAAY;AAAA,EACb;AAEA,MAAK,KAAK,UAAU,QAAQ,KAAO,KAAK,OAAO,QAAQ,GAAI;AAC1D,gBAAY;AAAA,EACb;AAEA,SAAO,EAAE,OAAO,WAAW,OAAO,UAAU;AAC7C;AA6BO,SAAS,0BACf,MAC2B;AAC3B,MAAI,IAAI;AACR,MAAI,IAAI;AAER,MAAI,KAAK,KAAM,KAAI;AACnB,MAAI,KAAK,MAAO,KAAI;AACpB,MAAI,KAAK,OAAQ,KAAI;AACrB,MAAI,KAAK,IAAK,KAAI;AAElB,SAAO,EAAE,GAAG,EAAE;AACf;","names":[]}
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
getRotationAngle2D,
|
|
5
5
|
normalizeDirection2D,
|
|
6
6
|
rotateLocalOffset2D
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SGHIGTVZ.js";
|
|
8
8
|
import {
|
|
9
9
|
normalizeVec3
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-M3QDKKDF.js";
|
|
11
11
|
import {
|
|
12
12
|
defineBehavior
|
|
13
13
|
} from "./chunk-EZNCCO4L.js";
|
|
@@ -159,4 +159,4 @@ export {
|
|
|
159
159
|
createShooter2DStateComponent,
|
|
160
160
|
Shooter2DBehavior
|
|
161
161
|
};
|
|
162
|
-
//# sourceMappingURL=chunk-
|
|
162
|
+
//# sourceMappingURL=chunk-PLIXVF7B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/shooter-2d/components.ts","../src/lib/behaviors/shooter-2d/shooter-2d.descriptor.ts"],"sourcesContent":["export interface Shooter2DStateComponent {\n\tcooldownRemainingMs: number;\n}\n\nexport function createShooter2DStateComponent(): Shooter2DStateComponent {\n\treturn {\n\t\tcooldownRemainingMs: 0,\n\t};\n}\n","import { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { normalizeVec3, type Vec3Input } from '../../core/vector';\nimport type { BehaviorRuntime } from '../../runtime/wasm-stage-runtime';\nimport {\n\tangleFromDirection2D,\n\tdirectionFromAngle2D,\n\tgetRotationAngle2D,\n\tnormalizeDirection2D,\n\trotateLocalOffset2D,\n} from '../shared/direction-2d';\nimport {\n\tcreateShooter2DStateComponent,\n\ttype Shooter2DStateComponent,\n} from './components';\n\nexport interface Shooter2DTarget {\n\tx: number;\n\ty: number;\n}\n\nexport interface Shooter2DStageLike {\n\tadd(...inputs: any[]): void;\n}\n\nexport interface Shooter2DProjectileEntity {\n\ttransformStore: {\n\t\tvelocity: { x: number; y: number; z: number };\n\t\tdirty: { velocityX: boolean; velocityY: boolean; velocityZ: boolean };\n\t};\n\tprependSetup(\n\t\tcallback: (params: { me: Shooter2DProjectileEntity }) => void,\n\t): unknown;\n\tsetPosition(x: number, y: number, z: number): void;\n\tsetRotationZ(angle: number): void;\n}\n\nexport type Shooter2DProjectileFactory = () =>\n\t| Shooter2DProjectileEntity\n\t| Promise<Shooter2DProjectileEntity>;\n\nexport interface Shooter2DBehaviorOptions {\n\tprojectileFactory: Shooter2DProjectileFactory;\n\tprojectileSpeed: number;\n\tcooldownMs?: number;\n\tspawnOffset?: Shooter2DTarget;\n\trotateProjectile?: boolean;\n}\n\nexport interface Shooter2DSourceEntity {\n\tbody?: {\n\t\ttranslation(): { x: number; y: number; z: number };\n\t\trotation?: () => { x: number; y: number; z: number; w: number };\n\t} | null;\n\toptions?: {\n\t\tposition?: Vec3Input;\n\t};\n\ttopDownMovementState?: {\n\t\tfacingAngle: number;\n\t};\n\tshooter2dState?: Shooter2DStateComponent;\n\t_rotation2DAngle?: number;\n}\n\nexport interface Shooter2DFireArgs {\n\tsource: Shooter2DSourceEntity;\n\tstage: Shooter2DStageLike;\n\ttarget: Shooter2DTarget;\n}\n\nexport interface Shooter2DHandle {\n\tisReady(source: Shooter2DSourceEntity): boolean;\n\tfire(args: Shooter2DFireArgs): Promise<Shooter2DProjectileEntity | null>;\n}\n\nconst defaultOptions: Shooter2DBehaviorOptions = {\n\tprojectileFactory: () => {\n\t\tthrow new Error('Shooter2DBehavior requires a projectileFactory.');\n\t},\n\tprojectileSpeed: 12,\n\tcooldownMs: 0,\n\tspawnOffset: { x: 0, y: 1 },\n\trotateProjectile: true,\n};\n\nconst SHOOTER_2D_BEHAVIOR_KEY = Symbol.for('zylem:behavior:shooter-2d');\n\nfunction ensureShooterState(entity: Shooter2DSourceEntity): Shooter2DStateComponent {\n\tif (!entity.shooter2dState) {\n\t\tentity.shooter2dState = createShooter2DStateComponent();\n\t}\n\treturn entity.shooter2dState;\n}\n\nfunction getEntityPosition(\n\tentity: Shooter2DSourceEntity,\n): { x: number; y: number; z: number } | null {\n\tif (entity.body?.translation) {\n\t\treturn entity.body.translation();\n\t}\n\n\tconst position = entity.options?.position;\n\tif (!position) {\n\t\treturn null;\n\t}\n\n\treturn normalizeVec3(position);\n}\n\nfunction getEntityFacingAngle(entity: Shooter2DSourceEntity): number {\n\tif (entity.topDownMovementState) {\n\t\treturn entity.topDownMovementState.facingAngle;\n\t}\n\n\tif (entity.body?.rotation) {\n\t\treturn getRotationAngle2D(entity.body.rotation());\n\t}\n\n\treturn entity._rotation2DAngle ?? 0;\n}\n\nfunction createShooter2DHandle(\n\tref: BehaviorRef<Shooter2DBehaviorOptions>,\n): Shooter2DHandle {\n\treturn {\n\t\tisReady: (source: Shooter2DSourceEntity) =>\n\t\t\tensureShooterState(source).cooldownRemainingMs <= 0,\n\t\tfire: async ({\n\t\t\tsource,\n\t\t\tstage,\n\t\t\ttarget,\n\t\t}: Shooter2DFireArgs): Promise<Shooter2DProjectileEntity | null> => {\n\t\t\tconst state = ensureShooterState(source);\n\t\t\tif (state.cooldownRemainingMs > 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst sourcePosition = getEntityPosition(source);\n\t\t\tif (!sourcePosition) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst options = ref.options;\n\t\t\tconst aimDirection = normalizeDirection2D(\n\t\t\t\ttarget.x - sourcePosition.x,\n\t\t\t\ttarget.y - sourcePosition.y,\n\t\t\t);\n\t\t\tconst angle = aimDirection\n\t\t\t\t? angleFromDirection2D(aimDirection)\n\t\t\t\t: getEntityFacingAngle(source);\n\t\t\tconst direction = aimDirection ?? directionFromAngle2D(angle);\n\t\t\tconst offset = rotateLocalOffset2D(\n\t\t\t\toptions.spawnOffset ?? defaultOptions.spawnOffset!,\n\t\t\t\tangle,\n\t\t\t);\n\t\t\tconst spawnPosition = {\n\t\t\t\tx: sourcePosition.x + offset.x,\n\t\t\t\ty: sourcePosition.y + offset.y,\n\t\t\t\tz: sourcePosition.z,\n\t\t\t};\n\t\t\tconst projectile = await Promise.resolve(options.projectileFactory());\n\t\t\tprojectile.prependSetup(({ me }) => {\n\t\t\t\tme.setPosition(spawnPosition.x, spawnPosition.y, spawnPosition.z);\n\t\t\t\tif (options.rotateProjectile ?? true) {\n\t\t\t\t\tme.setRotationZ(angle);\n\t\t\t\t}\n\t\t\t\tme.transformStore.velocity.x = direction.x * options.projectileSpeed;\n\t\t\t\tme.transformStore.velocity.y = direction.y * options.projectileSpeed;\n\t\t\t\tme.transformStore.velocity.z = 0;\n\t\t\t\tme.transformStore.dirty.velocityX = true;\n\t\t\t\tme.transformStore.dirty.velocityY = true;\n\t\t\t\tme.transformStore.dirty.velocityZ = true;\n\t\t\t});\n\n\t\t\tstage.add(projectile);\n\t\t\tstate.cooldownRemainingMs = Math.max(0, options.cooldownMs ?? 0);\n\t\t\treturn projectile;\n\t\t},\n\t};\n}\n\nclass Shooter2DBehaviorSystem 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?.(SHOOTER_2D_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst entity = link.entity as Shooter2DSourceEntity & { runtimeHandle?: number };\n\t\t\tconst ref = link.ref as any;\n\t\t\tconst state = ensureShooterState(entity);\n\t\t\tstate.cooldownRemainingMs = Math.max(\n\t\t\t\t0,\n\t\t\t\tstate.cooldownRemainingMs - delta * 1000,\n\t\t\t);\n\t\t\tref.__entity = entity;\n\n\t\t\tconst handle = (entity.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, ref.options as Shooter2DBehaviorOptions);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Shooter2DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst offset = options.spawnOffset ?? defaultOptions.spawnOffset!;\n\t\tconst fireRateHz = options.cooldownMs && options.cooldownMs > 0\n\t\t\t? 1000 / options.cooldownMs\n\t\t\t: 0;\n\t\tthis.wasmStage.attachShooter2D(handle, {\n\t\t\tfireRateHz,\n\t\t\tmuzzleOffsetX: offset.x,\n\t\t\tmuzzleOffsetY: offset.y,\n\t\t\tmuzzleSpeed: options.projectileSpeed,\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\nexport const Shooter2DBehavior = defineBehavior<\n\tShooter2DBehaviorOptions,\n\tShooter2DHandle,\n\tShooter2DSourceEntity\n>({\n\tname: 'shooter-2d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) => new Shooter2DBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createShooter2DHandle,\n});\n"],"mappings":"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","names":[]}
|
|
@@ -10,15 +10,6 @@ function normalizeDirection2D(x, y) {
|
|
|
10
10
|
y: y / length
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
function normalizeDirection2DInto(x, y, out) {
|
|
14
|
-
const length = Math.hypot(x, y);
|
|
15
|
-
if (length <= DIRECTION_EPSILON) {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
out.x = x / length;
|
|
19
|
-
out.y = y / length;
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
13
|
function angleFromDirection2D(direction) {
|
|
23
14
|
return Math.atan2(-direction.x, direction.y);
|
|
24
15
|
}
|
|
@@ -51,10 +42,9 @@ function getRotationAngle2D(rotation) {
|
|
|
51
42
|
|
|
52
43
|
export {
|
|
53
44
|
normalizeDirection2D,
|
|
54
|
-
normalizeDirection2DInto,
|
|
55
45
|
angleFromDirection2D,
|
|
56
46
|
directionFromAngle2D,
|
|
57
47
|
rotateLocalOffset2D,
|
|
58
48
|
getRotationAngle2D
|
|
59
49
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
50
|
+
//# sourceMappingURL=chunk-SGHIGTVZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/shared/direction-2d.ts"],"sourcesContent":["export interface Direction2D {\n\tx: number;\n\ty: number;\n}\n\nconst DIRECTION_EPSILON = 1e-6;\n\nexport function normalizeDirection2D(x: number, y: number): Direction2D | null {\n\tconst length = Math.hypot(x, y);\n\tif (length <= DIRECTION_EPSILON) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tx: x / length,\n\t\ty: y / length,\n\t};\n}\n\n/**\n * Allocation-free variant of {@link normalizeDirection2D} for per-frame paths.\n * Writes the normalized direction into `out` and returns true, or returns\n * false (leaving `out` untouched) when the input is effectively zero-length.\n */\nexport function normalizeDirection2DInto(\n\tx: number,\n\ty: number,\n\tout: Direction2D,\n): boolean {\n\tconst length = Math.hypot(x, y);\n\tif (length <= DIRECTION_EPSILON) {\n\t\treturn false;\n\t}\n\n\tout.x = x / length;\n\tout.y = y / length;\n\treturn true;\n}\n\nexport function angleFromDirection2D(direction: Direction2D): number {\n\treturn Math.atan2(-direction.x, direction.y);\n}\n\nexport function directionFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.sin(-angle),\n\t\ty: Math.cos(-angle),\n\t};\n}\n\nexport function rightFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.cos(angle),\n\t\ty: Math.sin(angle),\n\t};\n}\n\nexport function rotateLocalOffset2D(\n\toffset: Direction2D,\n\tangle: number,\n): Direction2D {\n\tconst right = rightFromAngle2D(angle);\n\tconst forward = directionFromAngle2D(angle);\n\treturn {\n\t\tx: right.x * offset.x + forward.x * offset.y,\n\t\ty: right.y * offset.x + forward.y * offset.y,\n\t};\n}\n\nexport function getRotationAngle2D(\n\trotation: { x: number; y: number; z: number; w: number },\n): number {\n\treturn Math.atan2(\n\t\t2 * (rotation.w * rotation.z + rotation.x * rotation.y),\n\t\t1 - 2 * (rotation.y * rotation.y + rotation.z * rotation.z),\n\t);\n}\n"],"mappings":";AAKA,IAAM,oBAAoB;AAEnB,SAAS,qBAAqB,GAAW,GAA+B;AAC9E,QAAM,SAAS,KAAK,MAAM,GAAG,CAAC;AAC9B,MAAI,UAAU,mBAAmB;AAChC,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG,IAAI;AAAA,IACP,GAAG,IAAI;AAAA,EACR;AACD;
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/shared/direction-2d.ts"],"sourcesContent":["export interface Direction2D {\n\tx: number;\n\ty: number;\n}\n\nconst DIRECTION_EPSILON = 1e-6;\n\nexport function normalizeDirection2D(x: number, y: number): Direction2D | null {\n\tconst length = Math.hypot(x, y);\n\tif (length <= DIRECTION_EPSILON) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tx: x / length,\n\t\ty: y / length,\n\t};\n}\n\n/**\n * Allocation-free variant of {@link normalizeDirection2D} for per-frame paths.\n * Writes the normalized direction into `out` and returns true, or returns\n * false (leaving `out` untouched) when the input is effectively zero-length.\n */\nexport function normalizeDirection2DInto(\n\tx: number,\n\ty: number,\n\tout: Direction2D,\n): boolean {\n\tconst length = Math.hypot(x, y);\n\tif (length <= DIRECTION_EPSILON) {\n\t\treturn false;\n\t}\n\n\tout.x = x / length;\n\tout.y = y / length;\n\treturn true;\n}\n\nexport function angleFromDirection2D(direction: Direction2D): number {\n\treturn Math.atan2(-direction.x, direction.y);\n}\n\nexport function directionFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.sin(-angle),\n\t\ty: Math.cos(-angle),\n\t};\n}\n\nexport function rightFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.cos(angle),\n\t\ty: Math.sin(angle),\n\t};\n}\n\nexport function rotateLocalOffset2D(\n\toffset: Direction2D,\n\tangle: number,\n): Direction2D {\n\tconst right = rightFromAngle2D(angle);\n\tconst forward = directionFromAngle2D(angle);\n\treturn {\n\t\tx: right.x * offset.x + forward.x * offset.y,\n\t\ty: right.y * offset.x + forward.y * offset.y,\n\t};\n}\n\nexport function getRotationAngle2D(\n\trotation: { x: number; y: number; z: number; w: number },\n): number {\n\treturn Math.atan2(\n\t\t2 * (rotation.w * rotation.z + rotation.x * rotation.y),\n\t\t1 - 2 * (rotation.y * rotation.y + rotation.z * rotation.z),\n\t);\n}\n"],"mappings":";AAKA,IAAM,oBAAoB;AAEnB,SAAS,qBAAqB,GAAW,GAA+B;AAC9E,QAAM,SAAS,KAAK,MAAM,GAAG,CAAC;AAC9B,MAAI,UAAU,mBAAmB;AAChC,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG,IAAI;AAAA,IACP,GAAG,IAAI;AAAA,EACR;AACD;AAsBO,SAAS,qBAAqB,WAAgC;AACpE,SAAO,KAAK,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;AAC5C;AAEO,SAAS,qBAAqB,OAA4B;AAChE,SAAO;AAAA,IACN,GAAG,KAAK,IAAI,CAAC,KAAK;AAAA,IAClB,GAAG,KAAK,IAAI,CAAC,KAAK;AAAA,EACnB;AACD;AAEO,SAAS,iBAAiB,OAA4B;AAC5D,SAAO;AAAA,IACN,GAAG,KAAK,IAAI,KAAK;AAAA,IACjB,GAAG,KAAK,IAAI,KAAK;AAAA,EAClB;AACD;AAEO,SAAS,oBACf,QACA,OACc;AACd,QAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAM,UAAU,qBAAqB,KAAK;AAC1C,SAAO;AAAA,IACN,GAAG,MAAM,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO;AAAA,IAC3C,GAAG,MAAM,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO;AAAA,EAC5C;AACD;AAEO,SAAS,mBACf,UACS;AACT,SAAO,KAAK;AAAA,IACX,KAAK,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS;AAAA,IACrD,IAAI,KAAK,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS;AAAA,EAC1D;AACD;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
directionFromAngle2D,
|
|
4
4
|
getRotationAngle2D,
|
|
5
5
|
normalizeDirection2D
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SGHIGTVZ.js";
|
|
7
7
|
|
|
8
8
|
// src/lib/coordinators/shared/top-down-aim.ts
|
|
9
9
|
function getEntityFacingAngle2D(entity) {
|
|
@@ -31,30 +31,8 @@ function resolveAim2D(aimX, aimY, fallbackAngle) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// src/lib/coordinators/shared/shooter-fire.ts
|
|
35
|
-
function fireShooter2DIfRequested(entity, shooter, stage, input, aim) {
|
|
36
|
-
if (!input.shootPressed && !input.shootHeld) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
const sourcePosition = entity.body?.translation();
|
|
40
|
-
if (!sourcePosition) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
const resolved = aim ?? resolveAim2D(input.aimX, input.aimY, getEntityFacingAngle2D(entity));
|
|
44
|
-
void shooter.fire({
|
|
45
|
-
source: entity,
|
|
46
|
-
stage,
|
|
47
|
-
target: {
|
|
48
|
-
x: sourcePosition.x + resolved.direction.x,
|
|
49
|
-
y: sourcePosition.y + resolved.direction.y
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
34
|
export {
|
|
56
35
|
getEntityFacingAngle2D,
|
|
57
|
-
resolveAim2D
|
|
58
|
-
fireShooter2DIfRequested
|
|
36
|
+
resolveAim2D
|
|
59
37
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
38
|
+
//# sourceMappingURL=chunk-TBUKJKY6.js.map
|