@zylem/behaviors 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{behavior-system-DYbx-x_-.d.ts → behavior-system-DSNek0W9.d.ts} +205 -29
- package/dist/{chunk-Y6UJOUE5.js → chunk-4V7TIRO2.js} +1 -1
- package/dist/chunk-4V7TIRO2.js.map +1 -0
- package/dist/{chunk-DYLH6K7B.js → chunk-4WH2ZN7P.js} +1 -1
- package/dist/{chunk-DYLH6K7B.js.map → chunk-4WH2ZN7P.js.map} +1 -1
- package/dist/{chunk-ZPSAXX73.js → chunk-5SM5SH5O.js} +26 -26
- package/dist/chunk-5SM5SH5O.js.map +1 -0
- package/dist/{chunk-STCCNLPC.js → chunk-5XZWTFGF.js} +5 -3
- package/dist/chunk-5XZWTFGF.js.map +1 -0
- package/dist/{chunk-OYWFPIHF.js → chunk-64HKCSXD.js} +19 -16
- package/dist/chunk-64HKCSXD.js.map +1 -0
- package/dist/{chunk-JAN34G6S.js → chunk-FRJDQM23.js} +108 -154
- package/dist/chunk-FRJDQM23.js.map +1 -0
- package/dist/{chunk-RTRVBEIB.js → chunk-FTDZAKZW.js} +5 -18
- package/dist/chunk-FTDZAKZW.js.map +1 -0
- package/dist/{chunk-XIJNE67Y.js → chunk-GFARAJV2.js} +3 -5
- package/dist/{chunk-XIJNE67Y.js.map → chunk-GFARAJV2.js.map} +1 -1
- package/dist/{chunk-SS7ELMJ7.js → chunk-GTLA6LOJ.js} +16 -22
- package/dist/chunk-GTLA6LOJ.js.map +1 -0
- package/dist/{chunk-VAN4WW3F.js → chunk-H4TJ7X4O.js} +4 -7
- package/dist/chunk-H4TJ7X4O.js.map +1 -0
- package/dist/{chunk-4I6E6DGV.js → chunk-HNESASBB.js} +4 -6
- package/dist/{chunk-4I6E6DGV.js.map → chunk-HNESASBB.js.map} +1 -1
- package/dist/{chunk-KS72RZHX.js → chunk-IZJFUAXB.js} +1 -1
- package/dist/{chunk-KS72RZHX.js.map → chunk-IZJFUAXB.js.map} +1 -1
- package/dist/{chunk-SVLNF434.js → chunk-JXMF4NUI.js} +51 -3
- package/dist/chunk-JXMF4NUI.js.map +1 -0
- package/dist/chunk-KFFETUAL.js +40 -0
- package/dist/chunk-KFFETUAL.js.map +1 -0
- package/dist/chunk-LL4FLHIY.js +12 -0
- package/dist/chunk-LL4FLHIY.js.map +1 -0
- package/dist/{chunk-2CLT36VB.js → chunk-MJFMNRMZ.js} +13 -14
- package/dist/chunk-MJFMNRMZ.js.map +1 -0
- package/dist/{chunk-RTVRUNYR.js → chunk-OTLSUYQQ.js} +2 -2
- package/dist/chunk-OTLSUYQQ.js.map +1 -0
- package/dist/{chunk-XG2YMCJW.js → chunk-PWF757B6.js} +4 -6
- package/dist/{chunk-XG2YMCJW.js.map → chunk-PWF757B6.js.map} +1 -1
- package/dist/{chunk-LD5SMIB3.js → chunk-QVCMJ4Q2.js} +1 -1
- package/dist/{chunk-LD5SMIB3.js.map → chunk-QVCMJ4Q2.js.map} +1 -1
- package/dist/{chunk-F3KRX2V4.js → chunk-RONH2KDI.js} +10 -12
- package/dist/chunk-RONH2KDI.js.map +1 -0
- package/dist/chunk-RTRFJVCZ.js +454 -0
- package/dist/chunk-RTRFJVCZ.js.map +1 -0
- package/dist/{chunk-6C6NXNEW.js → chunk-UL6Q5HDP.js} +25 -3
- package/dist/chunk-UL6Q5HDP.js.map +1 -0
- package/dist/{chunk-KOZUNIIE.js → chunk-V74N7D6Q.js} +7 -7
- package/dist/{chunk-KOZUNIIE.js.map → chunk-V74N7D6Q.js.map} +1 -1
- package/dist/{chunk-YUO6SKJD.js → chunk-WXXXJ22R.js} +11 -13
- package/dist/chunk-WXXXJ22R.js.map +1 -0
- package/dist/{chunk-ARJWUNRE.js → chunk-XLUJDKCT.js} +7 -7
- package/dist/{chunk-ARJWUNRE.js.map → chunk-XLUJDKCT.js.map} +1 -1
- package/dist/{chunk-GCNRXAKH.js → chunk-XP3ASVGJ.js} +13 -10
- package/dist/chunk-XP3ASVGJ.js.map +1 -0
- package/dist/{chunk-ID5QJYF5.js → chunk-Y7YIAWPW.js} +11 -1
- package/dist/chunk-Y7YIAWPW.js.map +1 -0
- package/dist/{chunk-FPTWVCPN.js → chunk-ZA43LPRM.js} +4 -24
- package/dist/chunk-ZA43LPRM.js.map +1 -0
- package/dist/{chunk-K3UNLQ7W.js → chunk-ZRQWSURL.js} +2 -2
- package/dist/chunk-ZRQWSURL.js.map +1 -0
- package/dist/cooldown.d.ts +2 -1
- package/dist/cooldown.js +1 -1
- package/dist/coordinators/boundary-ricochet-3d.d.ts +12 -5
- package/dist/coordinators/boundary-ricochet-3d.js +2 -1
- package/dist/coordinators/boundary-ricochet.d.ts +9 -7
- package/dist/coordinators/boundary-ricochet.js +2 -1
- package/dist/coordinators/first-person-shooter.d.ts +9 -8
- package/dist/coordinators/first-person-shooter.js +3 -3
- package/dist/coordinators/multidirectional-space-shooter.d.ts +12 -9
- package/dist/coordinators/multidirectional-space-shooter.js +4 -4
- package/dist/coordinators/top-down-shooter.d.ts +9 -8
- package/dist/coordinators/top-down-shooter.js +3 -3
- package/dist/core.d.ts +4 -4
- package/dist/core.js +4 -32
- package/dist/core.js.map +1 -1
- package/dist/destructible-3d.d.ts +2 -1
- package/dist/first-person.d.ts +12 -12
- package/dist/first-person.js +8 -8
- package/dist/index.d.ts +37 -14
- package/dist/index.js +73 -44
- package/dist/jumper-2d.d.ts +7 -6
- package/dist/jumper-2d.js +5 -5
- package/dist/jumper-3d.d.ts +12 -11
- package/dist/jumper-3d.js +6 -6
- package/dist/{moveable-BCRpjAQb.d.ts → moveable-BLTHO7Jq.d.ts} +2 -78
- package/dist/particle-emitter.d.ts +1 -1
- package/dist/particle-emitter.js +1 -1
- package/dist/platformer-2d.d.ts +306 -0
- package/dist/platformer-2d.js +23 -0
- package/dist/platformer-3d.d.ts +74 -87
- package/dist/platformer-3d.js +4 -4
- package/dist/ricochet-2d.d.ts +1 -1
- package/dist/ricochet-2d.js +2 -2
- package/dist/ricochet-3d.d.ts +1 -1
- package/dist/ricochet-3d.js +2 -2
- package/dist/runtime-2d.d.ts +93 -2
- package/dist/runtime-2d.js +145 -22
- package/dist/runtime-2d.js.map +1 -1
- package/dist/screen-visibility.d.ts +2 -1
- package/dist/screen-wrap.d.ts +2 -1
- package/dist/screen-wrap.js +1 -1
- package/dist/shooter-2d.d.ts +5 -3
- package/dist/shooter-2d.js +2 -2
- package/dist/shooter-fire-DGripl0z.d.ts +55 -0
- package/dist/thruster.d.ts +8 -18
- package/dist/thruster.js +6 -6
- package/dist/top-down-movement.d.ts +7 -4
- package/dist/top-down-movement.js +5 -5
- package/dist/{use-behavior-D_82jAL3.d.ts → use-behavior-h9-T5FSv.d.ts} +1 -1
- package/dist/world-boundary-2d.d.ts +2 -1
- package/dist/world-boundary-2d.js +2 -2
- package/dist/world-boundary-3d.d.ts +2 -1
- package/dist/world-boundary-3d.js +2 -2
- package/package.json +5 -5
- package/dist/chunk-2C3Z5GE7.js +0 -176
- package/dist/chunk-2C3Z5GE7.js.map +0 -1
- package/dist/chunk-2CLT36VB.js.map +0 -1
- package/dist/chunk-3PYGRHAL.js +0 -35
- package/dist/chunk-3PYGRHAL.js.map +0 -1
- package/dist/chunk-6C6NXNEW.js.map +0 -1
- package/dist/chunk-F3KRX2V4.js.map +0 -1
- package/dist/chunk-FPTWVCPN.js.map +0 -1
- package/dist/chunk-GCNRXAKH.js.map +0 -1
- package/dist/chunk-ID5QJYF5.js.map +0 -1
- package/dist/chunk-JAN34G6S.js.map +0 -1
- package/dist/chunk-K3UNLQ7W.js.map +0 -1
- package/dist/chunk-OYWFPIHF.js.map +0 -1
- package/dist/chunk-RTRVBEIB.js.map +0 -1
- package/dist/chunk-RTVRUNYR.js.map +0 -1
- package/dist/chunk-SS7ELMJ7.js.map +0 -1
- package/dist/chunk-STCCNLPC.js.map +0 -1
- package/dist/chunk-SVLNF434.js.map +0 -1
- package/dist/chunk-VAN4WW3F.js.map +0 -1
- package/dist/chunk-Y6UJOUE5.js.map +0 -1
- package/dist/chunk-YUO6SKJD.js.map +0 -1
- package/dist/chunk-ZPSAXX73.js.map +0 -1
- package/dist/runtime-pong.d.ts +0 -92
- package/dist/runtime-pong.js +0 -38
- /package/dist/{runtime-pong.js.map → platformer-2d.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/actions/capabilities/velocity-intents.ts"],"sourcesContent":["import { TransformState, VelocityIntentMode } from './transform-store';\n\nexport interface VelocityIntentOptions {\n\tmode?: VelocityIntentMode;\n\tpriority?: number;\n}\n\nexport interface VelocityIntentVector {\n\tx?: number;\n\ty?: number;\n\tz?: number;\n}\n\nexport function setVelocityIntent(\n\tstore: TransformState,\n\tsourceId: string,\n\tvector: VelocityIntentVector,\n\toptions: VelocityIntentOptions = {},\n): void {\n\tconst prev = store.velocityChannels[sourceId];\n\tconst mode = options.mode ?? prev?.mode ?? 'replace';\n\tconst priority = options.priority ?? prev?.priority ?? 0;\n\tconst isAdditiveMerge = mode === 'add' && prev?.mode === 'add';\n\n\tconst x =\n\t\tvector.x == null\n\t\t\t? prev?.x\n\t\t\t: isAdditiveMerge\n\t\t\t\t? (prev?.x ?? 0) + vector.x\n\t\t\t\t: vector.x;\n\tconst y =\n\t\tvector.y == null\n\t\t\t? prev?.y\n\t\t\t: isAdditiveMerge\n\t\t\t\t? (prev?.y ?? 0) + vector.y\n\t\t\t\t: vector.y;\n\tconst z =\n\t\tvector.z == null\n\t\t\t? prev?.z\n\t\t\t: isAdditiveMerge\n\t\t\t\t? (prev?.z ?? 0) + vector.z\n\t\t\t\t: vector.z;\n\n\tstore.velocityChannels[sourceId] = {\n\t\tx,\n\t\ty,\n\t\tz,\n\t\tmode,\n\t\tpriority,\n\t};\n\tstore.dirty.velocityChannels = true;\n}\n\nexport function clearVelocityIntent(store: TransformState, sourceId: string): void {\n\tif (!(sourceId in store.velocityChannels)) return;\n\tdelete store.velocityChannels[sourceId];\n\tstore.dirty.velocityChannels = true;\n}\n"],"mappings":";AAaO,SAAS,kBACf,OACA,UACA,QACA,UAAiC,CAAC,GAC3B;AACP,QAAM,OAAO,MAAM,iBAAiB,QAAQ;AAC5C,QAAM,OAAO,QAAQ,QAAQ,MAAM,QAAQ;AAC3C,QAAM,WAAW,QAAQ,YAAY,MAAM,YAAY;AACvD,QAAM,kBAAkB,SAAS,SAAS,MAAM,SAAS;AAEzD,QAAM,IACL,OAAO,KAAK,OACT,MAAM,IACN,mBACE,MAAM,KAAK,KAAK,OAAO,IACxB,OAAO;AACZ,QAAM,IACL,OAAO,KAAK,OACT,MAAM,IACN,mBACE,MAAM,KAAK,KAAK,OAAO,IACxB,OAAO;AACZ,QAAM,IACL,OAAO,KAAK,OACT,MAAM,IACN,mBACE,MAAM,KAAK,KAAK,OAAO,IACxB,OAAO;AAEZ,QAAM,iBAAiB,QAAQ,IAAI;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,QAAM,MAAM,mBAAmB;AAChC;AAEO,SAAS,oBAAoB,OAAuB,UAAwB;AAClF,MAAI,EAAE,YAAY,MAAM,kBAAmB;AAC3C,SAAO,MAAM,iBAAiB,QAAQ;AACtC,QAAM,MAAM,mBAAmB;AAChC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/jumper-2d/components.ts","../src/lib/behaviors/jumper-2d/jumper-2d.behavior.ts","../src/lib/behaviors/jumper-2d/jumper-2d-fsm.ts","../src/lib/behaviors/jumper-2d/jumper-2d.descriptor.ts"],"sourcesContent":["export interface JumpConfig2D {\n\tjumpHeight: number;\n\tgravity: number;\n\tmaxFallSpeed?: number;\n\tmaxJumps: number;\n\tresetJumpsOnGround: boolean;\n\tcoyoteTimeMs: number;\n\tjumpBufferMs: number;\n\tminTimeBetweenJumpsMs?: number;\n\tvariableJump?: {\n\t\tenabled: boolean;\n\t\tcutGravityMultiplier: number;\n\t\tmaxHoldMs?: number;\n\t};\n}\n\nexport function createJumpConfig2D(\n\toptions: Partial<JumpConfig2D> = {},\n): JumpConfig2D {\n\treturn {\n\t\tjumpHeight: options.jumpHeight ?? 2.5,\n\t\tgravity: options.gravity ?? 20,\n\t\tmaxFallSpeed: options.maxFallSpeed,\n\t\tmaxJumps: options.maxJumps ?? 1,\n\t\tresetJumpsOnGround: options.resetJumpsOnGround ?? true,\n\t\tcoyoteTimeMs: options.coyoteTimeMs ?? 100,\n\t\tjumpBufferMs: options.jumpBufferMs ?? 80,\n\t\tminTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,\n\t\tvariableJump: options.variableJump,\n\t};\n}\n\nexport interface JumpInput2D {\n\tjumpPressed: boolean;\n\tjumpHeld: boolean;\n\tjumpReleased: boolean;\n\tfastFall?: boolean;\n}\n\nexport function createJumpInput2D(): JumpInput2D {\n\treturn {\n\t\tjumpPressed: false,\n\t\tjumpHeld: false,\n\t\tjumpReleased: false,\n\t\tfastFall: false,\n\t};\n}\n\nexport interface JumpContext2D {\n\tdt: number;\n\tvelocityY: number;\n\tisGrounded: boolean;\n\ttimeSinceGroundedMs: number;\n\tsetVerticalVelocity(y: number): void;\n}\n\nexport interface JumpState2D {\n\tjumpsUsed: number;\n\tlastJumpTimeMs: number;\n\tbufferedJumpMs: number;\n\tcoyoteMs: number;\n\tisJumping: boolean;\n\tjumpHoldMs: number;\n\tjumpCutApplied: boolean;\n}\n\nexport function createJumpState2D(): JumpState2D {\n\treturn {\n\t\tjumpsUsed: 0,\n\t\tlastJumpTimeMs: 0,\n\t\tbufferedJumpMs: 0,\n\t\tcoyoteMs: 0,\n\t\tisJumping: false,\n\t\tjumpHoldMs: 0,\n\t\tjumpCutApplied: false,\n\t};\n}\n","import type {\n\tJumpConfig2D,\n\tJumpContext2D,\n\tJumpInput2D,\n\tJumpState2D,\n} from './components';\n\nfunction jumpVelocityFromHeight(gravity: number, height: number): number {\n\treturn Math.sqrt(2 * gravity * height);\n}\n\nexport enum Jumper2DTickEvent {\n\tNone = 'none',\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper2DTickResult {\n\tevent: Jumper2DTickEvent;\n}\n\nexport class Jumper2DBehavior {\n\ttick(\n\t\tconfig: JumpConfig2D,\n\t\tinput: JumpInput2D,\n\t\tctx: JumpContext2D,\n\t\tstate: JumpState2D,\n\t): Jumper2DTickResult {\n\t\tconst dtMs = ctx.dt * 1000;\n\t\tconst now = performance.now();\n\t\tlet event = Jumper2DTickEvent.None;\n\t\tlet jumpedThisFrame = false;\n\n\t\tif (ctx.isGrounded) {\n\t\t\tstate.coyoteMs = config.coyoteTimeMs;\n\t\t\tif (config.resetJumpsOnGround) {\n\t\t\t\tstate.jumpsUsed = 0;\n\t\t\t}\n\t\t\tif (state.isJumping) {\n\t\t\t\tstate.isJumping = false;\n\t\t\t\tstate.jumpCutApplied = false;\n\t\t\t\tevent = Jumper2DTickEvent.Land;\n\t\t\t}\n\t\t} else {\n\t\t\tstate.coyoteMs = Math.max(0, state.coyoteMs - dtMs);\n\t\t}\n\n\t\tif (input.jumpPressed) {\n\t\t\tstate.bufferedJumpMs = config.jumpBufferMs;\n\t\t} else {\n\t\t\tstate.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);\n\t\t}\n\n\t\tif (state.isJumping && input.jumpHeld) {\n\t\t\tstate.jumpHoldMs += dtMs;\n\t\t}\n\n\t\tconst wantsJump = state.bufferedJumpMs > 0;\n\t\tconst isFirstJump =\n\t\t\tctx.isGrounded || (state.coyoteMs > 0 && state.jumpsUsed === 0);\n\t\tconst hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;\n\t\tconst canJump = isFirstJump || hasAirJumps;\n\t\tconst cooldownOk =\n\t\t\tconfig.minTimeBetweenJumpsMs == null ||\n\t\t\tnow - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;\n\n\t\tif (wantsJump && canJump && cooldownOk) {\n\t\t\tctx.setVerticalVelocity(jumpVelocityFromHeight(config.gravity, config.jumpHeight));\n\t\t\tjumpedThisFrame = true;\n\t\t\tstate.jumpsUsed++;\n\t\t\tstate.lastJumpTimeMs = now;\n\t\t\tstate.bufferedJumpMs = 0;\n\t\t\tstate.coyoteMs = 0;\n\t\t\tstate.isJumping = true;\n\t\t\tstate.jumpHoldMs = 0;\n\t\t\tstate.jumpCutApplied = false;\n\t\t\tevent = Jumper2DTickEvent.Jump;\n\t\t}\n\n\t\tif (!ctx.isGrounded || jumpedThisFrame) {\n\t\t\tlet gravityMul = 1;\n\t\t\tconst isFalling = ctx.velocityY < 0;\n\n\t\t\tif (isFalling) {\n\t\t\t\tgravityMul = input.fastFall ? 1.75 : 1;\n\t\t\t\tif (event !== Jumper2DTickEvent.Land) {\n\t\t\t\t\tevent = Jumper2DTickEvent.Fall;\n\t\t\t\t}\n\t\t\t} else if (state.isJumping) {\n\t\t\t\tconst variableJump = config.variableJump;\n\t\t\t\tif (variableJump?.enabled && !state.jumpCutApplied) {\n\t\t\t\t\tconst holdExpired =\n\t\t\t\t\t\tvariableJump.maxHoldMs != null &&\n\t\t\t\t\t\tstate.jumpHoldMs >= variableJump.maxHoldMs;\n\t\t\t\t\tif (!input.jumpHeld || holdExpired) {\n\t\t\t\t\t\tgravityMul = variableJump.cutGravityMultiplier;\n\t\t\t\t\t\tstate.jumpCutApplied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet newVelocityY = ctx.velocityY - config.gravity * gravityMul * ctx.dt;\n\t\t\tif (config.maxFallSpeed != null) {\n\t\t\t\tnewVelocityY = Math.max(-config.maxFallSpeed, newVelocityY);\n\t\t\t}\n\t\t\tctx.setVerticalVelocity(newVelocityY);\n\t\t} else {\n\t\t\tctx.setVerticalVelocity(0);\n\t\t}\n\n\t\treturn { event };\n\t}\n}\n","import { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState2D } from './components';\n\nexport enum Jumper2DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper2DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper2DFSMContext {\n\tstate: JumpState2D;\n}\n\nexport class Jumper2DFSM {\n\tmachine: SyncStateMachine<Jumper2DState, Jumper2DEvent, never>;\n\n\tconstructor(private ctx: Jumper2DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper2DState, Jumper2DEvent, never>(\n\t\t\tJumper2DState.Grounded,\n\t\t\t[\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper2DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper2DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper2DState.Jumping;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper2DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif (!isGrounded && this.getState() === Jumper2DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper2DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper2DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper2DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","import { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { setVelocityIntent } from '../../actions/capabilities/velocity-intents';\nimport {\n\tGroundProbe3D,\n\tgetGroundAnchorOffsetY,\n\tgetGroundSnapTargetY,\n\ttype GroundProbeSupportHit,\n} from '../shared/ground-probe-3d';\nimport {\n\tcreateJumpConfig2D,\n\tcreateJumpInput2D,\n\tcreateJumpState2D,\n\ttype JumpConfig2D,\n\ttype JumpContext2D,\n\ttype JumpInput2D,\n\ttype JumpState2D,\n} from './components';\nimport {\n\tJumper2DBehavior,\n\tJumper2DTickEvent,\n} from './jumper-2d.behavior';\nimport { Jumper2DFSM, Jumper2DState } from './jumper-2d-fsm';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\nexport interface Jumper2DBehaviorOptions {\n\tjumpHeight?: number;\n\tgravity?: number;\n\tmaxFallSpeed?: number;\n\tmaxJumps?: number;\n\tresetJumpsOnGround?: boolean;\n\tcoyoteTimeMs?: number;\n\tjumpBufferMs?: number;\n\tminTimeBetweenJumpsMs?: number;\n\tvariableJump?: JumpConfig2D['variableJump'];\n\tgroundRayLength?: number;\n\tsnapToGroundDistance?: number;\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper2DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_2D_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-2d');\nconst JUMPER_2D_OFFSETS = [\n\t{ x: 0, z: 0 },\n\t{ x: 0.35, z: 0 },\n\t{ x: -0.35, z: 0 },\n] as const;\n\nexport function isJumper2DGrounded(params: {\n\tnearGround?: boolean;\n\tvelocityY: number;\n\tsupportToi?: number | null;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.velocityY > 0) {\n\t\treturn false;\n\t}\n\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance\n\t\t);\n\t}\n\n\treturn params.nearGround === true;\n}\n\nfunction shouldSnapJumper2DToGround(\n\tsupport: GroundProbeSupportHit | null,\n\toptions: Jumper2DBehaviorOptions,\n\tvelocityY: number,\n): support is GroundProbeSupportHit {\n\treturn (\n\t\tsupport != null &&\n\t\toptions.snapToGroundDistance != null &&\n\t\tvelocityY <= 0 &&\n\t\tsupport.toi <= options.snapToGroundDistance\n\t);\n}\n\nexport interface Jumper2DEntity {\n\tuuid: string;\n\tbody: any;\n\ttransformStore: any;\n\tjumper2d: JumpConfig2D;\n\t$jumper2d: JumpInput2D;\n\tjumper2dState: JumpState2D;\n}\n\nclass Jumper2DBehaviorSystem implements BehaviorSystem {\n\tprivate behavior = new Jumper2DBehavior();\n\tprivate groundProbe: GroundProbe3D;\n\tprivate initializedEntities = new Set<string>();\n\tprivate timeSinceGroundedMs = new Map<string, number>();\n\tprivate wasJumpHeld = new Map<string, boolean>();\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate world: any,\n\t\tprivate scene: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.groundProbe = new GroundProbe3D(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(JUMPER_2D_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper2DBehaviorOptions;\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, options);\n\t\t\t\tconst input = gameEntity.$jumper2d as JumpInput2D | undefined;\n\t\t\t\tconst jumpPressed = !!(input?.jumpPressed || input?.jumpHeld);\n\t\t\t\tthis.wasmStage.setJumper2DInput(handle, jumpPressed);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!gameEntity.body) continue;\n\n\t\t\tif (!gameEntity.jumper2d) {\n\t\t\t\tgameEntity.jumper2d = createJumpConfig2D(options);\n\t\t\t}\n\t\t\tif (!gameEntity.$jumper2d) {\n\t\t\t\tgameEntity.$jumper2d = createJumpInput2D();\n\t\t\t}\n\t\t\tif (!gameEntity.jumper2dState) {\n\t\t\t\tgameEntity.jumper2dState = createJumpState2D();\n\t\t\t}\n\t\t\tif (!this.initializedEntities.has(gameEntity.uuid)) {\n\t\t\t\tthis.initializedEntities.add(gameEntity.uuid);\n\t\t\t\tgameEntity.body.setGravityScale(0, true);\n\t\t\t}\n\t\t\tif (!jumperRef.fsm && gameEntity.jumper2dState) {\n\t\t\t\tjumperRef.fsm = new Jumper2DFSM({\n\t\t\t\t\tstate: gameEntity.jumper2dState,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst rayLength = options.groundRayLength ?? 1;\n\t\t\tconst bodyVelocity = gameEntity.body.linvel();\n\t\t\tconst probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);\n\t\t\tconst support = this.groundProbe.probeSupport(gameEntity, {\n\t\t\t\trayLength,\n\t\t\t\toffsets: JUMPER_2D_OFFSETS,\n\t\t\t\tmode: 'any',\n\t\t\t\tdebug: options.debugGroundProbe ?? false,\n\t\t\t\tscene: this.scene,\n\t\t\t\toriginYOffset: probeOriginYOffset,\n\t\t\t});\n\t\t\tconst nearGround = support != null;\n\t\t\tconst isGrounded = isJumper2DGrounded({\n\t\t\t\tnearGround,\n\t\t\t\tvelocityY: bodyVelocity.y,\n\t\t\t\tsupportToi: support?.toi ?? null,\n\t\t\t\tsnapToGroundDistance: options.snapToGroundDistance,\n\t\t\t});\n\t\t\tif (shouldSnapJumper2DToGround(support, options, bodyVelocity.y)) {\n\t\t\t\tconst currentPosition = gameEntity.body.translation();\n\t\t\t\tgameEntity.body.setTranslation(\n\t\t\t\t\t{\n\t\t\t\t\t\tx: currentPosition.x,\n\t\t\t\t\t\ty: getGroundSnapTargetY(gameEntity, support),\n\t\t\t\t\t\tz: currentPosition.z,\n\t\t\t\t\t},\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet timeSinceGroundedMs = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;\n\t\t\tif (isGrounded) {\n\t\t\t\ttimeSinceGroundedMs = 0;\n\t\t\t} else {\n\t\t\t\ttimeSinceGroundedMs += delta * 1000;\n\t\t\t}\n\t\t\tthis.timeSinceGroundedMs.set(gameEntity.uuid, timeSinceGroundedMs);\n\n\t\t\tconst config: JumpConfig2D = gameEntity.jumper2d;\n\t\t\tconst input: JumpInput2D = gameEntity.$jumper2d;\n\t\t\tconst state: JumpState2D = gameEntity.jumper2dState;\n\t\t\tconst previousHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;\n\t\t\tconst held = input.jumpHeld === true;\n\t\t\tconst effectiveInput: JumpInput2D = {\n\t\t\t\t...input,\n\t\t\t\tjumpPressed: input.jumpPressed || (held && !previousHeld),\n\t\t\t\tjumpReleased: input.jumpReleased || (!held && previousHeld),\n\t\t\t};\n\n\t\t\tconst store = gameEntity.transformStore;\n\t\t\tconst ctx: JumpContext2D = {\n\t\t\t\tdt: delta,\n\t\t\t\tvelocityY: bodyVelocity.y,\n\t\t\t\tisGrounded,\n\t\t\t\ttimeSinceGroundedMs,\n\t\t\t\tsetVerticalVelocity: (y: number) => {\n\t\t\t\t\tsetVelocityIntent(\n\t\t\t\t\t\tstore,\n\t\t\t\t\t\t'jumper-2d',\n\t\t\t\t\t\t{ y },\n\t\t\t\t\t\t{ mode: 'replace', priority: 20 },\n\t\t\t\t\t);\n\t\t\t\t\tctx.velocityY = y;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tconst result = this.behavior.tick(config, effectiveInput, ctx, state);\n\t\t\tthis.wasJumpHeld.set(gameEntity.uuid, held);\n\n\t\t\tif (jumperRef.fsm) {\n\t\t\t\t(jumperRef.fsm as Jumper2DFSM).applyTickEvent(result.event, isGrounded);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper2DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper2D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tjumpBufferTime: (options.jumpBufferMs ?? 80) / 1000,\n\t\t\tcoyoteTime: (options.coyoteTimeMs ?? 100) / 1000,\n\t\t\tgravity: options.gravity ?? 20,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.groundProbe.destroy();\n\t\tthis.initializedEntities.clear();\n\t\tthis.timeSinceGroundedMs.clear();\n\t\tthis.wasJumpHeld.clear();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\nexport const Jumper2D = defineBehavior<\n\tJumper2DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper2DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper2DEntity\n>({\n\tname: 'jumper-2d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper2DBehaviorSystem(ctx.world, ctx.scene, ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: (ref) => ({\n\t\tgetState: () =>\n\t\t\t(ref.fsm as Jumper2DFSM | undefined)?.getState() ??\n\t\t\tJumper2DState.Grounded,\n\t\tisJumping: () =>\n\t\t\t(ref.fsm as Jumper2DFSM | undefined)?.isJumping() ?? false,\n\t\tgetJumpsUsed: () =>\n\t\t\t(ref.fsm as Jumper2DFSM | undefined)?.getJumpsUsed() ?? 0,\n\t\tgetJumpsRemaining: () => {\n\t\t\tconst maxJumps = ref.options.maxJumps ?? 1;\n\t\t\tconst used =\n\t\t\t\t(ref.fsm as Jumper2DFSM | undefined)?.getJumpsUsed() ?? 0;\n\t\t\treturn maxJumps - used;\n\t\t},\n\t}),\n});\n"],"mappings":"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","names":["Jumper2DTickEvent","Jumper2DState","Jumper2DEvent","input"]}
|
|
@@ -1 +0,0 @@
|
|
|
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 { WasmStageRuntime } 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: { velocity: 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.velocity = 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: WasmStageRuntime | 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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/shared/ground-probe-3d.ts","../src/lib/physics/collider-desc-inspect.ts"],"sourcesContent":["import { Cuboid } from '@dimforge/rapier3d-compat';\nimport {\n\tBoxGeometry,\n\tMesh,\n\tMeshBasicMaterial,\n} from 'three';\nimport { inspectColliderDesc } from '../../physics/collider-desc-inspect';\n\n/**\n * @deprecated Kept for type compatibility with older callers; ignored at runtime.\n * The boxcast implementation does not use offset rays.\n */\nexport interface GroundProbeOffset {\n\tx: number;\n\tz: number;\n}\n\n/**\n * Probe sizing hint.\n *\n * - `center`: prefer a tiny box that behaves close to a single downward ray\n * (used by `Jumper3D` for thin/single-point ground tests).\n * - `any`: prefer a box sized from the entity's collider footprint\n * (used by `Platformer3D` so the character \"feels\" the ground under any\n * foot, not just dead-center).\n *\n * The actual box dimensions are still configurable via `options.box`.\n */\nexport type GroundProbeMode = 'center' | 'any';\n\nexport interface GroundProbeEntity {\n\tuuid: string;\n\tbody: any;\n}\n\nexport interface GroundProbeOptions {\n\t/** Maximum cast distance in world units. */\n\trayLength: number;\n\t/** @deprecated No longer used by the boxcast implementation. */\n\toffsets?: readonly GroundProbeOffset[];\n\t/** Selects the default box size when `box` is not explicitly provided. */\n\tmode?: GroundProbeMode;\n\t/** Render a wireframe of the cast box for debugging. Requires `scene`. */\n\tdebug?: boolean;\n\t/** Three.js scene used to host the debug wireframe mesh. */\n\tscene?: any;\n\t/**\n\t * Vertical offset added to the body translation when computing the cast\n\t * origin. Allows callers to shift the probe to e.g. just above the\n\t * capsule's bottom face.\n\t */\n\toriginYOffset?: number;\n\t/**\n\t * Half-extents of the cast cuboid. When omitted the probe derives a\n\t * sensible default from the entity's collider:\n\t * - capsule: `(r * 0.7, 0.05, r * 0.7)` — a thin slab smaller than the\n\t * capsule footprint, so side walls don't register as ground.\n\t * - cuboid: shrink the bottom face by 30% so the probe sits well inside\n\t * the collider footprint.\n\t * - `mode: 'center'`: forces a tiny `(0.05, 0.05, 0.05)` box.\n\t */\n\tbox?: { x: number; y: number; z: number };\n}\n\nexport interface GroundProbeSupportHit {\n\ttoi: number;\n\tpoint: {\n\t\tx: number;\n\t\ty: number;\n\t\tz: number;\n\t};\n\torigin: {\n\t\tx: number;\n\t\ty: number;\n\t\tz: number;\n\t};\n\t/** Always 0 — kept for backward compatibility with the old multi-ray API. */\n\trayIndex: number;\n\tcolliderUuid?: string;\n}\n\nexport const GROUND_SNAP_EPSILON = 0.001;\n\n/**\n * Tiny box used when the caller selects `mode: 'center'` — close enough to a\n * point cast that it preserves the old single-ray behavior of `Jumper3D`.\n */\nconst CENTER_BOX_HALF = 0.05;\n\n/**\n * Default vertical thickness of the cast cuboid. The box is intentionally thin\n * vertically so the impact distance closely matches a downward ray's TOI;\n * existing snap-to-ground math (which assumes `point.y ≈ origin.y - toi`)\n * keeps working with negligible drift.\n */\nconst DEFAULT_BOX_THICKNESS = 0.05;\n\n/**\n * GroundProbe3D — single-cast cuboid probe used by 3D platformer and jumper\n * behaviors to detect the ground beneath an entity.\n *\n * Replaces the previous 5-ray probe: a single shape-cast handles edge cases\n * (corner of a platform, narrow gap) more robustly and produces a single,\n * intuitive debug visualization (a wireframe box).\n */\nexport class GroundProbe3D {\n\tprivate debugMeshes = new Map<string, Mesh>();\n\n\tconstructor(private world: any) {}\n\n\tprobeSupport(\n\t\tentity: GroundProbeEntity,\n\t\toptions: GroundProbeOptions,\n\t): GroundProbeSupportHit | null {\n\t\tif (!this.world?.world || !entity.body) return null;\n\n\t\tconst translation = entity.body.translation();\n\t\tconst originYOffset = options.originYOffset ?? 0;\n\t\tconst box = options.box ?? deriveDefaultBox(entity, options.mode ?? 'any');\n\n\t\tconst shapePos = {\n\t\t\tx: translation.x,\n\t\t\ty: translation.y + originYOffset,\n\t\t\tz: translation.z,\n\t\t};\n\t\tconst shapeRot = { x: 0, y: 0, z: 0, w: 1 };\n\t\tconst shapeVel = { x: 0, y: -1, z: 0 };\n\n\t\tconst shape = new Cuboid(box.x, box.y, box.z);\n\t\tconst hit = this.world.world.castShape(\n\t\t\tshapePos,\n\t\t\tshapeRot,\n\t\t\tshapeVel,\n\t\t\tshape,\n\t\t\toptions.rayLength,\n\t\t\ttrue,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tentity.body,\n\t\t);\n\n\t\tlet support: GroundProbeSupportHit | null = null;\n\t\tif (hit) {\n\t\t\tsupport = {\n\t\t\t\ttoi: hit.toi,\n\t\t\t\tpoint: {\n\t\t\t\t\tx: shapePos.x,\n\t\t\t\t\ty: shapePos.y - hit.toi - box.y,\n\t\t\t\t\tz: shapePos.z,\n\t\t\t\t},\n\t\t\t\torigin: { ...shapePos },\n\t\t\t\trayIndex: 0,\n\t\t\t\tcolliderUuid: hit.collider?._parent?.userData?.uuid,\n\t\t\t};\n\t\t}\n\n\t\tif (options.debug && options.scene) {\n\t\t\tthis.updateDebugMesh(\n\t\t\t\tentity.uuid,\n\t\t\t\tshapePos,\n\t\t\t\tbox,\n\t\t\t\toptions.rayLength,\n\t\t\t\tBoolean(support),\n\t\t\t\toptions.scene,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.disposeDebugMesh(entity.uuid);\n\t\t}\n\n\t\treturn support;\n\t}\n\n\tdetect(entity: GroundProbeEntity, options: GroundProbeOptions): boolean {\n\t\treturn this.probeSupport(entity, options) != null;\n\t}\n\n\tdestroyEntity(uuid: string): void {\n\t\tthis.disposeDebugMesh(uuid);\n\t}\n\n\tdestroy(): void {\n\t\tfor (const uuid of this.debugMeshes.keys()) {\n\t\t\tthis.disposeDebugMesh(uuid);\n\t\t}\n\t\tthis.debugMeshes.clear();\n\t}\n\n\tprivate updateDebugMesh(\n\t\tuuid: string,\n\t\tshapePos: { x: number; y: number; z: number },\n\t\tbox: { x: number; y: number; z: number },\n\t\trayLength: number,\n\t\thasGround: boolean,\n\t\tscene: any,\n\t): void {\n\t\tlet mesh = this.debugMeshes.get(uuid);\n\t\tif (!mesh) {\n\t\t\tconst geometry = new BoxGeometry(2 * box.x, 2 * box.y, 2 * box.z);\n\t\t\tconst material = new MeshBasicMaterial({\n\t\t\t\twireframe: true,\n\t\t\t\tcolor: 0xff0000,\n\t\t\t});\n\t\t\tmesh = new Mesh(geometry, material);\n\t\t\tscene.add(mesh);\n\t\t\tthis.debugMeshes.set(uuid, mesh);\n\t\t}\n\n\t\t// Position the box at the cast midpoint so users can see the swept volume.\n\t\tmesh.position.set(\n\t\t\tshapePos.x,\n\t\t\tshapePos.y - rayLength * 0.5,\n\t\t\tshapePos.z,\n\t\t);\n\t\tmesh.scale.set(1, Math.max(rayLength / Math.max(2 * box.y, 1e-6), 1), 1);\n\t\t(mesh.material as MeshBasicMaterial).color.setHex(\n\t\t\thasGround ? 0x00ff00 : 0xff0000,\n\t\t);\n\t}\n\n\tprivate disposeDebugMesh(uuid: string): void {\n\t\tconst mesh = this.debugMeshes.get(uuid);\n\t\tif (!mesh) return;\n\n\t\tmesh.removeFromParent();\n\t\tmesh.geometry.dispose();\n\t\t(mesh.material as MeshBasicMaterial).dispose();\n\n\t\tthis.debugMeshes.delete(uuid);\n\t}\n}\n\nfunction deriveDefaultBox(\n\tentity: GroundProbeEntity,\n\tmode: GroundProbeMode,\n): { x: number; y: number; z: number } {\n\tif (mode === 'center') {\n\t\treturn { x: CENTER_BOX_HALF, y: CENTER_BOX_HALF, z: CENTER_BOX_HALF };\n\t}\n\n\tconst runtimeColliderDesc = (entity as any)?.colliderDesc;\n\tif (runtimeColliderDesc) {\n\t\tconst inspected = inspectColliderDesc(runtimeColliderDesc);\n\t\tif (inspected.shape === 'capsule' && inspected.dimensions.length >= 2) {\n\t\t\tconst radius = inspected.dimensions[1] ?? 0.5;\n\t\t\tconst half = Math.max(radius * 0.7, CENTER_BOX_HALF);\n\t\t\treturn { x: half, y: DEFAULT_BOX_THICKNESS, z: half };\n\t\t}\n\t\tif (inspected.shape === 'cuboid' && inspected.dimensions.length >= 3) {\n\t\t\tconst halfX = (inspected.dimensions[0] ?? 0.5) * 0.7;\n\t\t\tconst halfZ = (inspected.dimensions[2] ?? 0.5) * 0.7;\n\t\t\treturn {\n\t\t\t\tx: Math.max(halfX, CENTER_BOX_HALF),\n\t\t\t\ty: DEFAULT_BOX_THICKNESS,\n\t\t\t\tz: Math.max(halfZ, CENTER_BOX_HALF),\n\t\t\t};\n\t\t}\n\t}\n\n\tconst collisionSize =\n\t\t(entity as any)?.options?.collision?.size ??\n\t\t(entity as any)?.options?.collisionSize ??\n\t\t(entity as any)?.options?.size;\n\tif (collisionSize) {\n\t\tconst halfX = ((collisionSize.x ?? 1) / 2) * 0.7;\n\t\tconst halfZ = ((collisionSize.z ?? collisionSize.x ?? 1) / 2) * 0.7;\n\t\treturn {\n\t\t\tx: Math.max(halfX, CENTER_BOX_HALF),\n\t\t\ty: DEFAULT_BOX_THICKNESS,\n\t\t\tz: Math.max(halfZ, CENTER_BOX_HALF),\n\t\t};\n\t}\n\n\treturn { x: 0.35, y: DEFAULT_BOX_THICKNESS, z: 0.35 };\n}\n\nexport function getGroundAnchorOffsetY(entity: any): number {\n\tconst runtimeColliderDesc = entity?.colliderDesc;\n\tif (runtimeColliderDesc) {\n\t\tconst inspected = inspectColliderDesc(runtimeColliderDesc);\n\t\tconst centerY = inspected.translation?.[1] ?? 0;\n\t\tif (inspected.shape === 'capsule' && inspected.dimensions.length >= 2) {\n\t\t\tconst halfCylinder = inspected.dimensions[0] ?? 0;\n\t\t\tconst radius = inspected.dimensions[1] ?? 0;\n\t\t\treturn halfCylinder + radius - centerY;\n\t\t}\n\t\tif (inspected.shape === 'cuboid' && inspected.dimensions.length >= 2) {\n\t\t\tconst halfHeight = inspected.dimensions[1] ?? 0;\n\t\t\treturn halfHeight - centerY;\n\t\t}\n\t}\n\n\tconst collisionSize =\n\t\tentity?.options?.collision?.size ??\n\t\tentity?.options?.collisionSize ??\n\t\tentity?.options?.size;\n\tconst height = collisionSize?.y ?? 0;\n\tif (height <= 0) {\n\t\treturn 0;\n\t}\n\n\tconst collisionPosition =\n\t\tentity?.options?.collision?.position ??\n\t\tentity?.options?.collisionPosition;\n\tconst centerY = collisionPosition?.y ?? height / 2;\n\treturn (height / 2) - centerY;\n}\n\nexport function getGroundSnapTargetY(\n\tentity: any,\n\tsupport: GroundProbeSupportHit,\n\tepsilon: number = GROUND_SNAP_EPSILON,\n): number {\n\treturn support.point.y + getGroundAnchorOffsetY(entity) + epsilon;\n}\n","import type { ColliderDesc } from '@dimforge/rapier3d-compat';\n\n/**\n * Subset of Rapier shape kinds that game-lib introspects for sizing decisions\n * (e.g. ground probes derive their cast box from the entity collider). Mirrors\n * the public Rapier shape vocabulary, kept as string literals so callers can\n * branch without depending on Rapier's internal shape enum.\n */\nexport type ColliderShapeKind =\n\t| 'ball'\n\t| 'cuboid'\n\t| 'capsule'\n\t| 'cone'\n\t| 'cylinder'\n\t| 'heightfield'\n\t| 'convexHull'\n\t| 'trimesh';\n\n/**\n * Plain, runtime-agnostic snapshot of a {@link ColliderDesc}'s shape and\n * placement. Only contains the fields game-lib needs today; extend as new\n * call sites appear.\n *\n * - `shape` — discriminator for the underlying Rapier shape.\n * - `dimensions` — shape-specific numbers (see {@link inspectColliderDesc}).\n * - `translation` — local offset relative to the parent body, when set.\n * - `vertices` / `indices` — raw geometry payload for `convexHull` and\n * `trimesh` shapes; tagged via `__zylemShapeData` at construction time.\n */\nexport interface ColliderDescInspection {\n\tshape: ColliderShapeKind;\n\tdimensions: number[];\n\ttranslation?: [number, number, number];\n\tvertices?: number[];\n\tindices?: number[];\n}\n\n/**\n * Read the shape kind, dimensions, and local translation off a Rapier\n * {@link ColliderDesc} without going through the WASM-backed accessors that\n * cannot cross worker boundaries.\n *\n * Layout per shape (matches Rapier's primitive constructors):\n * - `ball` → `[radius]`\n * - `cuboid` → `[halfX, halfY, halfZ]`\n * - `capsule` → `[halfHeight, radius]`\n * - `cone` → `[halfHeight, radius]`\n * - `cylinder` → `[halfHeight, radius]`\n * - `heightfield` → flattened heights array\n * - `convexHull` → flattened vertex array (set via the `__zylemShapeData` tag)\n * - `trimesh` → flattened vertex array (indices ignored here)\n */\nexport function inspectColliderDesc(desc: ColliderDesc): ColliderDescInspection {\n\tconst internal = desc as any;\n\tconst customShapeData = internal.__zylemShapeData as\n\t\t| { shape: 'convexHull'; vertices: number[] }\n\t\t| { shape: 'trimesh'; vertices: number[]; indices: number[] }\n\t\t| undefined;\n\n\tif (customShapeData?.shape === 'convexHull') {\n\t\tconst result = finalize('convexHull', [], internal);\n\t\tresult.vertices = [...customShapeData.vertices];\n\t\treturn result;\n\t}\n\tif (customShapeData?.shape === 'trimesh') {\n\t\tconst result = finalize('trimesh', [], internal);\n\t\tresult.vertices = [...customShapeData.vertices];\n\t\tresult.indices = [...customShapeData.indices];\n\t\treturn result;\n\t}\n\n\tconst shapeType = internal.shape?.type ?? internal.shapeType ?? 0;\n\tconst { shape, dimensions } = extractShapeData(shapeType, internal);\n\treturn finalize(shape, dimensions, internal);\n}\n\nfunction finalize(\n\tshape: ColliderShapeKind,\n\tdimensions: number[],\n\tinternal: any,\n): ColliderDescInspection {\n\tconst result: ColliderDescInspection = { shape, dimensions };\n\tconst t = internal.translation;\n\tif (t && (t.x !== 0 || t.y !== 0 || t.z !== 0)) {\n\t\tresult.translation = [t.x, t.y, t.z];\n\t}\n\treturn result;\n}\n\n/**\n * Rapier shape type enum values (from rapier internals):\n * 0 = Ball, 1 = Cuboid, 2 = Capsule, 6 = Cone, 7 = Cylinder, 11 = HeightField\n */\nfunction extractShapeData(\n\tshapeType: number,\n\tinternal: any,\n): { shape: ColliderShapeKind; dimensions: number[] } {\n\tswitch (shapeType) {\n\t\tcase 0:\n\t\t\treturn {\n\t\t\t\tshape: 'ball',\n\t\t\t\tdimensions: [internal.shape?.radius ?? internal.halfExtents?.x ?? 1],\n\t\t\t};\n\t\tcase 1:\n\t\t\treturn {\n\t\t\t\tshape: 'cuboid',\n\t\t\t\tdimensions: [\n\t\t\t\t\tinternal.shape?.halfExtents?.x ?? internal.halfExtents?.x ?? 0.5,\n\t\t\t\t\tinternal.shape?.halfExtents?.y ?? internal.halfExtents?.y ?? 0.5,\n\t\t\t\t\tinternal.shape?.halfExtents?.z ?? internal.halfExtents?.z ?? 0.5,\n\t\t\t\t],\n\t\t\t};\n\t\tcase 2:\n\t\t\treturn {\n\t\t\t\tshape: 'capsule',\n\t\t\t\tdimensions: [\n\t\t\t\t\tinternal.shape?.halfHeight ?? 0.5,\n\t\t\t\t\tinternal.shape?.radius ?? 0.5,\n\t\t\t\t],\n\t\t\t};\n\t\tcase 6:\n\t\t\treturn {\n\t\t\t\tshape: 'cone',\n\t\t\t\tdimensions: [\n\t\t\t\t\tinternal.shape?.halfHeight ?? 1,\n\t\t\t\t\tinternal.shape?.radius ?? 1,\n\t\t\t\t],\n\t\t\t};\n\t\tcase 7:\n\t\t\treturn {\n\t\t\t\tshape: 'cylinder',\n\t\t\t\tdimensions: [\n\t\t\t\t\tinternal.shape?.halfHeight ?? 1,\n\t\t\t\t\tinternal.shape?.radius ?? 1,\n\t\t\t\t],\n\t\t\t};\n\t\tcase 11: {\n\t\t\tconst heights = internal.shape?.heights;\n\t\t\treturn {\n\t\t\t\tshape: 'heightfield',\n\t\t\t\tdimensions: heights ? Array.from(heights) : [],\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn { shape: 'cuboid', dimensions: [0.5, 0.5, 0.5] };\n\t}\n}\n"],"mappings":"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","names":["centerY"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/coordinators/first-person-shooter.coordinator.ts"],"sourcesContent":["import type { GameEntity } from '../entities/entity';\nimport {\n\tcreateFirstPersonInputComponent,\n\ttype FirstPersonInputComponent,\n} from '../behaviors/first-person/components';\nimport {\n\tcreateJumpInput3D,\n\ttype JumpInput3D,\n} from '../behaviors/jumper-3d/components';\n\nexport interface FirstPersonShooterInput {\n\tmoveX: number;\n\tmoveZ: number;\n\tlookX: number;\n\tlookY: number;\n\tsprint: boolean;\n\tjumpPressed: boolean;\n\tjumpHeld: boolean;\n\tjumpReleased: boolean;\n\tfastFall?: boolean;\n}\n\ninterface FirstPersonShooterControllerHandle {\n\tgetYaw(): number;\n}\n\ninterface FirstPersonShooterJumperHandle {\n\tgetState(): unknown;\n}\n\ntype FirstPersonShooterEntity = GameEntity<any> & {\n\t$fps?: FirstPersonInputComponent;\n\t$jumper?: JumpInput3D;\n};\n\nexport class FirstPersonShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: FirstPersonShooterEntity,\n\t\tprivate fpsController: FirstPersonShooterControllerHandle,\n\t\tprivate jumper: FirstPersonShooterJumperHandle,\n\t) {}\n\n\tpublic update(input: FirstPersonShooterInput): void {\n\t\tif (!this.entity.$fps) {\n\t\t\tthis.entity.$fps = createFirstPersonInputComponent();\n\t\t}\n\t\tif (!this.entity.$jumper) {\n\t\t\tthis.entity.$jumper = createJumpInput3D();\n\t\t}\n\n\t\tconst fpsInput = this.entity.$fps;\n\t\tfpsInput.moveX = input.moveX;\n\t\tfpsInput.moveZ = input.moveZ;\n\t\tfpsInput.lookX = input.lookX;\n\t\tfpsInput.lookY = input.lookY;\n\t\tfpsInput.sprint = input.sprint;\n\n\t\tconst jumperInput = this.entity.$jumper;\n\t\tjumperInput.jumpPressed = input.jumpPressed;\n\t\tjumperInput.jumpHeld = input.jumpHeld;\n\t\tjumperInput.jumpReleased = input.jumpReleased;\n\t\tjumperInput.fastFall = input.fastFall ?? false;\n\t\tjumperInput.moveDirWorld = this.getMoveDirWorld(\n\t\t\tinput.moveX,\n\t\t\tinput.moveZ,\n\t\t\tthis.fpsController.getYaw(),\n\t\t);\n\n\t\t// Keep the jumper handle in the public contract even though the\n\t\t// coordinator only needs its current state for future extensions.\n\t\tvoid this.jumper.getState();\n\t}\n\n\tprivate getMoveDirWorld(\n\t\tmoveX: number,\n\t\tmoveZ: number,\n\t\tyaw: number,\n\t): { x: number; y: number; z: number } | undefined {\n\t\tconst sinYaw = Math.sin(yaw);\n\t\tconst cosYaw = Math.cos(yaw);\n\t\tconst rightX = cosYaw;\n\t\tconst rightZ = -sinYaw;\n\t\tconst forwardX = -sinYaw;\n\t\tconst forwardZ = -cosYaw;\n\t\tconst worldX = rightX * moveX + forwardX * -moveZ;\n\t\tconst worldZ = rightZ * moveX + forwardZ * -moveZ;\n\t\tconst length = Math.hypot(worldX, worldZ);\n\t\tif (length <= 1e-6) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tx: worldX / length,\n\t\t\ty: 0,\n\t\t\tz: worldZ / length,\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;AAmCO,IAAM,gCAAN,MAAoC;AAAA,EAC1C,YACS,QACA,eACA,QACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAHM;AAAA,EACA;AAAA,EACA;AAAA,EAGF,OAAO,OAAsC;AACnD,QAAI,CAAC,KAAK,OAAO,MAAM;AACtB,WAAK,OAAO,OAAO,gCAAgC;AAAA,IACpD;AACA,QAAI,CAAC,KAAK,OAAO,SAAS;AACzB,WAAK,OAAO,UAAU,kBAAkB;AAAA,IACzC;AAEA,UAAM,WAAW,KAAK,OAAO;AAC7B,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,QAAQ,MAAM;AACvB,aAAS,SAAS,MAAM;AAExB,UAAM,cAAc,KAAK,OAAO;AAChC,gBAAY,cAAc,MAAM;AAChC,gBAAY,WAAW,MAAM;AAC7B,gBAAY,eAAe,MAAM;AACjC,gBAAY,WAAW,MAAM,YAAY;AACzC,gBAAY,eAAe,KAAK;AAAA,MAC/B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,cAAc,OAAO;AAAA,IAC3B;AAIA,SAAK,KAAK,OAAO,SAAS;AAAA,EAC3B;AAAA,EAEQ,gBACP,OACA,OACA,KACkD;AAClD,UAAM,SAAS,KAAK,IAAI,GAAG;AAC3B,UAAM,SAAS,KAAK,IAAI,GAAG;AAC3B,UAAM,SAAS;AACf,UAAM,SAAS,CAAC;AAChB,UAAM,WAAW,CAAC;AAClB,UAAM,WAAW,CAAC;AAClB,UAAM,SAAS,SAAS,QAAQ,WAAW,CAAC;AAC5C,UAAM,SAAS,SAAS,QAAQ,WAAW,CAAC;AAC5C,UAAM,SAAS,KAAK,MAAM,QAAQ,MAAM;AACxC,QAAI,UAAU,MAAM;AACnB,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,GAAG,SAAS;AAAA,IACb;AAAA,EACD;AACD;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/runtime/wasm-stage-runtime.ts"],"sourcesContent":["export const StageBodyKind = {\n\tDynamic: 0,\n\tStatic: 1,\n\tKinematicPosition: 2,\n\tKinematicVelocity: 3,\n} as const;\n\nexport const StageBoundaryDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetReflection = {\n\tMirror: 0,\n\tAngled: 1,\n} as const;\n\nexport const StageTopDownPlane = {\n\tXy: 0,\n\tXz: 1,\n} as const;\n\nexport const StageEventType = {\n\tCollisionStarted: 1,\n\tCollisionStopped: 2,\n\tBoundaryHit: 3,\n\tRicochet: 4,\n\tRegionEntered: 5,\n\tJumpStarted: 6,\n\tLanded: 7,\n\tWrapped: 8,\n\tCooldownFired: 9,\n} as const;\n\nexport interface WasmStageRuntime {\n\tgetPose(handle: number): any;\n\tattachThruster(handle: number, opts: any): boolean;\n\tsetThrusterInput(handle: number, thrust: number, rotate: number): void;\n\tattachTopDown(handle: number, opts: { plane: number; speed: number; faceMovement?: boolean }): boolean;\n\tsetTopDownInput(handle: number, moveX: number, moveY: number): void;\n\tattachShooter2D(handle: number, opts: any): boolean;\n\tattachScreenWrap(handle: number, opts: any): boolean;\n\tqueryScreenWrap(handle: number): any;\n\tattachWorldBoundary(handle: number, dim: number, opts: any): boolean;\n\tqueryWorldBoundary(handle: number): any;\n\tattachRicochet(handle: number, dim: number, opts: any): boolean;\n\tattachPlatformer3D(handle: number, opts: any): boolean;\n\tsetPlatformer3DInputAxes(handle: number, moveX: number, moveZ: number): void;\n\tsetPlatformer3DInputButtons(handle: number, jump: boolean, run: boolean): void;\n\tattachFirstPerson(handle: number, opts: any): boolean;\n\tsetFirstPersonInput(handle: number, input: any): void;\n\tattachJumper2D(handle: number, opts: any): boolean;\n\tsetJumper2DInput(handle: number, jumpPressed: boolean): void;\n\tattachJumper3D(handle: number, opts: any): boolean;\n\tsetJumper3DInput(handle: number, jumpPressed: boolean): void;\n}\n\n/** Default options used when constructing a wasm-backed Stage runtime. */\nexport interface WasmStageRuntimeOptions {\n\tinitialCapacity?: number;\n\tgravity?: readonly [number, number, number];\n\timports?: WebAssembly.Imports;\n}\n"],"mappings":";AAAO,IAAM,gBAAgB;AAAA,EAC5B,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,mBAAmB;AACpB;AAEO,IAAM,mBAAmB;AAAA,EAC/B,KAAK;AAAA,EACL,OAAO;AACR;AAEO,IAAM,mBAAmB;AAAA,EAC/B,KAAK;AAAA,EACL,OAAO;AACR;AAEO,IAAM,0BAA0B;AAAA,EACtC,QAAQ;AAAA,EACR,QAAQ;AACT;AAEO,IAAM,oBAAoB;AAAA,EAChC,IAAI;AAAA,EACJ,IAAI;AACL;AAEO,IAAM,iBAAiB;AAAA,EAC7B,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,eAAe;AAAA,EACf,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAChB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/first-person/first-person-fsm.ts","../src/lib/behaviors/first-person/first-person.behavior.ts","../src/lib/behaviors/first-person/first-person.descriptor.ts"],"sourcesContent":["/**\n * First Person Controller Finite State Machine\n *\n * Manages state transitions for first-person movement:\n * - Idle: Standing still\n * - Walking: Moving at walk speed\n * - Running: Moving at run/sprint speed\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { FirstPersonInputComponent, FirstPersonStateComponent } from './components';\n\n/**\n * First-person movement states\n */\nexport enum FirstPersonState {\n\tIdle = 'idle',\n\tWalking = 'walking',\n\tRunning = 'running',\n}\n\n/**\n * Events that trigger state transitions\n */\nexport enum FirstPersonEvent {\n\tWalk = 'walk',\n\tRun = 'run',\n\tStop = 'stop',\n}\n\n/**\n * Context for the FSM\n */\nexport interface FirstPersonContext {\n\tinput: FirstPersonInputComponent;\n\tstate: FirstPersonStateComponent;\n}\n\n/**\n * First Person Controller FSM\n */\nexport class FirstPersonFSM {\n\tmachine: SyncStateMachine<FirstPersonState, FirstPersonEvent, never>;\n\n\tconstructor(private ctx: FirstPersonContext) {\n\t\tthis.machine = new SyncStateMachine<FirstPersonState, FirstPersonEvent, never>(\n\t\t\tFirstPersonState.Idle,\n\t\t\t[\n\t\t\t\t// Idle transitions\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\n\t\t\t\t// Walking transitions\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\n\t\t\t\t// Running transitions\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t],\n\t\t);\n\t}\n\n\t/** Get the current state */\n\tgetState(): FirstPersonState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/** Dispatch an event to the FSM */\n\tdispatch(event: FirstPersonEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/** Get the current yaw from context */\n\tgetYaw(): number {\n\t\treturn this.ctx.state.yaw;\n\t}\n\n\t/** Get the current pitch from context */\n\tgetPitch(): number {\n\t\treturn this.ctx.state.pitch;\n\t}\n\n\t/**\n\t * Update FSM based on current input and state.\n\t */\n\tupdate(input: FirstPersonInputComponent, state: FirstPersonStateComponent): void {\n\t\tthis.ctx.input = input;\n\t\tthis.ctx.state = state;\n\n\t\tconst hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\n\t\tif (hasMovement) {\n\t\t\tif (input.sprint) {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Run);\n\t\t\t} else {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Walk);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.dispatch(FirstPersonEvent.Stop);\n\t\t}\n\t}\n}\n","/**\n * First Person Controller Behavior System\n *\n * Handles first-person camera control and movement:\n * - Reads input component for WASD movement and mouse look deltas\n * - Drives a FirstPersonPerspective (yaw/pitch accumulation)\n * - Writes velocity to transformStore (physics-based movement)\n * - Syncs camera position from the entity's rigid body each frame\n * - Positions an optional viewmodel entity relative to the camera\n */\n\nimport { Vector3, Quaternion, Euler } from 'three';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport { setVelocityIntent } from '../../actions/capabilities/velocity-intents';\nimport type {\n\tFirstPersonMovementComponent,\n\tFirstPersonInputComponent,\n\tFirstPersonStateComponent,\n} from './components';\n\n/**\n * Viewmodel configuration for an entity that follows the camera.\n */\nexport interface ViewmodelConfig {\n\t/** The entity whose visual group should be positioned relative to the camera. */\n\tentity: any;\n\t/** Offset from the eye position in camera-local space (right, down, forward). */\n\toffset: Vector3;\n\t/** Additional rotation applied to the viewmodel in local space (Euler angles in radians). */\n\trotation?: Euler;\n}\n\n/**\n * Entity interface for first-person controller.\n * Entities with this behavior have these components attached.\n */\nexport interface FirstPersonEntity {\n\tuuid: string;\n\tbody: any;\n\ttransformStore: any;\n\tfirstPerson: FirstPersonMovementComponent;\n\t$fps: FirstPersonInputComponent;\n\tfirstPersonState: FirstPersonStateComponent;\n}\n\n// Reusable temporaries (avoid per-frame allocations)\nconst _forward = new Vector3();\nconst _right = new Vector3();\nconst _up = new Vector3(0, 1, 0);\nconst _viewmodelQuat = new Quaternion();\nconst _viewmodelLocalQuat = new Quaternion();\nconst _viewmodelEuler = new Euler();\nconst _offset = new Vector3();\n\n/**\n * First Person Controller Behavior\n *\n * Core movement + look system for first-person cameras.\n * Reads from entity.$fps input component and drives a FirstPersonPerspective.\n */\nexport class FirstPersonControllerBehavior {\n\tprivate world: any;\n\tprivate perspectives = new Map<string, FirstPersonPerspective>();\n\tprivate viewmodels = new Map<string, ViewmodelConfig>();\n\n\tconstructor(world: any) {\n\t\tthis.world = world;\n\t}\n\n\t/**\n\t * Associate a FirstPersonPerspective with an entity (by uuid).\n\t * Called once by the descriptor system when the behavior is initialized.\n\t */\n\tsetPerspective(entityUuid: string, perspective: FirstPersonPerspective): void {\n\t\tthis.perspectives.set(entityUuid, perspective);\n\t}\n\n\thasPerspective(entityUuid: string): boolean {\n\t\treturn this.perspectives.has(entityUuid);\n\t}\n\n\t/**\n\t * Attach a viewmodel (weapon/item) to an entity.\n\t * The viewmodel entity's group will be positioned relative to the camera each frame.\n\t */\n\tsetViewmodel(entityUuid: string, config: ViewmodelConfig): void {\n\t\tthis.viewmodels.set(entityUuid, config);\n\t}\n\n\thasViewmodel(entityUuid: string): boolean {\n\t\treturn this.viewmodels.has(entityUuid);\n\t}\n\n\t/**\n\t * Update one first-person entity.\n\t */\n\tupdateEntity(entity: any, _delta: number): void {\n\t\tconst fpEntity = entity as any;\n\t\tif (!fpEntity.firstPerson || !fpEntity.$fps || !fpEntity.firstPersonState) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst input: FirstPersonInputComponent = fpEntity.$fps;\n\t\tconst movement: FirstPersonMovementComponent = fpEntity.firstPerson;\n\t\tconst state: FirstPersonStateComponent = fpEntity.firstPersonState;\n\t\tconst perspective = this.perspectives.get(fpEntity.uuid);\n\n\t\t// 1. Sync camera position from physics body\n\t\tif (perspective?.initialPosition && fpEntity.body) {\n\t\t\tconst pos = fpEntity.body.translation();\n\t\t\tperspective.initialPosition.set(\n\t\t\t\tpos.x,\n\t\t\t\tpos.y + movement.eyeHeight,\n\t\t\t\tpos.z,\n\t\t\t);\n\t\t}\n\n\t\t// 2. Apply look\n\t\tif (perspective) {\n\t\t\tperspective.look(\n\t\t\t\t-input.lookX * movement.lookSensitivity,\n\t\t\t\t-input.lookY * movement.lookSensitivity,\n\t\t\t);\n\n\t\t\tstate.yaw = perspective.yaw;\n\t\t\tstate.pitch = perspective.pitch;\n\t\t}\n\n\t\t// 3. Compute velocity-based movement and write to transformStore\n\t\tconst speed = input.sprint ? movement.runSpeed : movement.walkSpeed;\n\t\tstate.currentSpeed = speed;\n\n\t\tconst hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\n\t\tif (fpEntity.transformStore) {\n\t\t\tif (hasMovement) {\n\t\t\t\t_forward.set(0, 0, -1).applyAxisAngle(_up, state.yaw);\n\t\t\t\t_right.set(1, 0, 0).applyAxisAngle(_up, state.yaw);\n\n\t\t\t\tconst vx =\n\t\t\t\t\t_right.x * input.moveX * speed +\n\t\t\t\t\t_forward.x * (-input.moveZ) * speed;\n\t\t\t\tconst vz =\n\t\t\t\t\t_right.z * input.moveX * speed +\n\t\t\t\t\t_forward.z * (-input.moveZ) * speed;\n\t\t\t\tsetVelocityIntent(\n\t\t\t\t\tfpEntity.transformStore,\n\t\t\t\t\t'first-person',\n\t\t\t\t\t{ x: vx, z: vz },\n\t\t\t\t\t{ mode: 'replace', priority: 10 },\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tsetVelocityIntent(\n\t\t\t\t\tfpEntity.transformStore,\n\t\t\t\t\t'first-person',\n\t\t\t\t\t{ x: 0, z: 0 },\n\t\t\t\t\t{ mode: 'replace', priority: 10 },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// 4. Position viewmodel\n\t\tconst vm = this.viewmodels.get(fpEntity.uuid);\n\t\tif (vm && perspective?.initialPosition) {\n\t\t\tthis.positionViewmodel(vm, perspective, state);\n\t\t}\n\t}\n\n\t/**\n\t * Update all first-person entities.\n\t */\n\tupdate(delta: number): void {\n\t\tif (!this.world?.collisionMap) return;\n\t\tfor (const [, entity] of this.world.collisionMap) {\n\t\t\tthis.updateEntity(entity, delta);\n\t\t}\n\t}\n\n\t/**\n\t * Position a viewmodel entity relative to the camera's eye position and rotation.\n\t *\n\t * The physics transform system overwrites group.position from the rigid body\n\t * each frame, so we must also move the body to keep them in sync.\n\t */\n\tprivate positionViewmodel(\n\t\tvm: ViewmodelConfig,\n\t\tperspective: FirstPersonPerspective,\n\t\tstate: FirstPersonStateComponent,\n\t): void {\n\t\tconst eyePos = perspective.initialPosition;\n\t\tif (!eyePos) return;\n\n\t\t// Build camera rotation quaternion\n\t\t_viewmodelQuat.setFromEuler(\n\t\t\t_viewmodelEuler.set(state.pitch, state.yaw, 0, 'YXZ'),\n\t\t);\n\n\t\t// Compose with the viewmodel's local rotation (model orientation fix)\n\t\tif (vm.rotation) {\n\t\t\t_viewmodelLocalQuat.setFromEuler(vm.rotation);\n\t\t\t_viewmodelQuat.multiply(_viewmodelLocalQuat);\n\t\t}\n\n\t\t// Transform the local offset into world space (use camera rotation, not the composed one)\n\t\t_offset.copy(vm.offset).applyQuaternion(_viewmodelQuat);\n\n\t\tconst wx = eyePos.x + _offset.x;\n\t\tconst wy = eyePos.y + _offset.y;\n\t\tconst wz = eyePos.z + _offset.z;\n\n\t\tconst entity = vm.entity;\n\n\t\t// Move the physics body so the transform system stays in sync\n\t\tif (entity?.body) {\n\t\t\tentity.body.setTranslation({ x: wx, y: wy, z: wz }, true);\n\t\t\tentity.body.setRotation(\n\t\t\t\t{ x: _viewmodelQuat.x, y: _viewmodelQuat.y, z: _viewmodelQuat.z, w: _viewmodelQuat.w },\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\t// Also set the group directly for immediate visual update\n\t\tif (entity?.group) {\n\t\t\tentity.group.position.set(wx, wy, wz);\n\t\t\tentity.group.quaternion.copy(_viewmodelQuat);\n\t\t}\n\t}\n\n\t/** Cleanup */\n\tdestroy(): void {\n\t\tthis.perspectives.clear();\n\t\tthis.viewmodels.clear();\n\t}\n}\n","/**\n * First Person Controller Behavior Descriptor\n *\n * Type-safe descriptor for the first-person controller behavior system.\n * Provides entity.use() API for FPS movement and camera control.\n */\n\nimport { Vector3, Euler } from 'three';\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport { Vec3Input, VEC3_ZERO, toThreeVector3 } from '../../core/vector';\nimport {\n\tFirstPersonControllerBehavior,\n\ttype FirstPersonEntity,\n\ttype ViewmodelConfig,\n} from './first-person.behavior';\nimport { FirstPersonFSM, FirstPersonState } from './first-person-fsm';\nimport {\n\tcreateFirstPersonMovementComponent,\n\tcreateFirstPersonInputComponent,\n\tcreateFirstPersonStateComponent,\n} from './components';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * First-person controller behavior options (typed for entity.use() autocomplete).\n */\nexport interface FirstPersonControllerOptions {\n\t/** Base walking speed (default: 8) */\n\twalkSpeed?: number;\n\t/** Sprint/run speed (default: 16) */\n\trunSpeed?: number;\n\t/** Look sensitivity multiplier (default: 2) */\n\tlookSensitivity?: number;\n\t/** Eye height offset above entity position (default: 1.7) */\n\teyeHeight?: number;\n\t/** The FirstPersonPerspective to drive (from camera.getPerspective()) */\n\tperspective?: FirstPersonPerspective;\n\t/** Optional viewmodel (weapon/item) to position relative to the camera */\n\tviewmodel?: { entity: any; offset: Vec3Input; rotation?: Euler };\n}\n\nconst defaultOptions: FirstPersonControllerOptions = {\n\twalkSpeed: 8,\n\trunSpeed: 16,\n\tlookSensitivity: 2,\n\teyeHeight: 1.7,\n};\n\nconst FIRST_PERSON_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:first-person-controller',\n);\n\n/**\n * Adapter that wraps FirstPersonControllerBehavior as a BehaviorSystem.\n */\nclass FirstPersonControllerSystem implements BehaviorSystem {\n\tprivate behavior: FirstPersonControllerBehavior;\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate world: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.behavior = new FirstPersonControllerBehavior(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(FIRST_PERSON_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst fpsRef = link.ref as any;\n\n\t\t\tconst options = fpsRef.options as FirstPersonControllerOptions;\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, options);\n\t\t\t\tconst input = gameEntity.$fps;\n\t\t\t\tif (input) {\n\t\t\t\t\tthis.wasmStage.setFirstPersonInput(handle, {\n\t\t\t\t\t\tmoveX: input.moveX ?? 0,\n\t\t\t\t\t\tmoveZ: input.moveZ ?? 0,\n\t\t\t\t\t\tlookYawDelta: input.lookX ?? 0,\n\t\t\t\t\t\tlookPitchDelta: input.lookY ?? 0,\n\t\t\t\t\t\trun: !!input.sprint,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Initialize components (once)\n\t\t\tif (!gameEntity.firstPerson) {\n\t\t\t\tgameEntity.firstPerson = createFirstPersonMovementComponent(options);\n\t\t\t}\n\n\t\t\tif (!gameEntity.$fps) {\n\t\t\t\tgameEntity.$fps = createFirstPersonInputComponent();\n\t\t\t}\n\n\t\t\tif (!gameEntity.firstPersonState) {\n\t\t\t\tgameEntity.firstPersonState = createFirstPersonStateComponent();\n\t\t\t}\n\n\t\t\t// Wire up perspective (once)\n\t\t\tif (options.perspective && !this.behavior.hasPerspective(gameEntity.uuid)) {\n\t\t\t\tthis.behavior.setPerspective(gameEntity.uuid, options.perspective);\n\t\t\t}\n\n\t\t\t// Wire up viewmodel (once)\n\t\t\tif (options.viewmodel && !this.behavior.hasViewmodel(gameEntity.uuid)) {\n\t\t\t\tthis.behavior.setViewmodel(gameEntity.uuid, {\n\t\t\t\t\t...options.viewmodel,\n\t\t\t\t\toffset: toThreeVector3(options.viewmodel.offset, VEC3_ZERO),\n\t\t\t\t} as ViewmodelConfig);\n\t\t\t}\n\n\t\t\t// Create FSM lazily\n\t\t\tif (!fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {\n\t\t\t\tfpsRef.fsm = new FirstPersonFSM({\n\t\t\t\t\tinput: gameEntity.$fps,\n\t\t\t\t\tstate: gameEntity.firstPersonState,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Update FSM\n\t\t\tif (fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {\n\t\t\t\tfpsRef.fsm.update(gameEntity.$fps, gameEntity.firstPersonState);\n\t\t\t}\n\n\t\t\tthis.behavior.updateEntity(gameEntity, delta);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: FirstPersonControllerOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachFirstPerson(handle, {\n\t\t\twalkSpeed: options.walkSpeed ?? defaultOptions.walkSpeed!,\n\t\t\trunSpeed: options.runSpeed ?? defaultOptions.runSpeed!,\n\t\t\teyeHeight: options.eyeHeight ?? defaultOptions.eyeHeight!,\n\t\t\tlookSensitivity: options.lookSensitivity ?? defaultOptions.lookSensitivity!,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.behavior.destroy();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * FirstPersonController - typed descriptor for first-person movement and camera control.\n *\n * Provides complete first-person controller including:\n * - WASD movement relative to camera yaw\n * - Mouse look driving a FirstPersonPerspective\n * - Optional viewmodel positioning (weapon/item following camera)\n * - Walk/run state tracking via FSM\n *\n * @example\n * ```typescript\n * import { FirstPersonController } from \"@zylem/game-lib/behavior\";\n * import { createCamera, Perspectives, FirstPersonPerspective } from \"@zylem/game-lib/core\";\n * import { createActor } from \"@zylem/game-lib/entity\";\n *\n * const fpsCamera = createCamera({ perspective: Perspectives.FirstPerson, ... });\n * const fps = fpsCamera.getPerspective<FirstPersonPerspective>();\n *\n * const player = createActor({ name: 'player', ... });\n * const controller = player.use(FirstPersonController, {\n * perspective: fps,\n * walkSpeed: 8,\n * runSpeed: 16,\n * lookSensitivity: 2,\n * });\n *\n * // In update loop - write input, behavior handles the rest\n * player.onUpdate(({ inputs }) => {\n * player.$fps.moveX = inputs.p1.axes.Horizontal.value;\n * player.$fps.moveZ = inputs.p1.axes.Vertical.value;\n * player.$fps.lookX = inputs.p1.axes.SecondaryHorizontal.value;\n * player.$fps.lookY = inputs.p1.axes.SecondaryVertical.value;\n * player.$fps.sprint = inputs.p1.shoulders.LTrigger.held > 0;\n * });\n * ```\n */\nexport const FirstPersonController = defineBehavior<\n\tFirstPersonControllerOptions,\n\t{\n\t\tgetState: () => FirstPersonState;\n\t\tgetYaw: () => number;\n\t\tgetPitch: () => number;\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => void;\n\t},\n\tFirstPersonEntity\n>({\n\tname: 'first-person-controller',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew FirstPersonControllerSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: (ref) => ({\n\t\tgetState: () => ref.fsm?.getState() ?? FirstPersonState.Idle,\n\t\tgetYaw: () => ref.fsm?.getYaw() ?? 0,\n\t\tgetPitch: () => ref.fsm?.getPitch() ?? 0,\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => {\n\t\t\tif (ref.options) {\n\t\t\t\tref.options.viewmodel = { entity, offset };\n\t\t\t}\n\t\t},\n\t}),\n});\n"],"mappings":"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","names":["FirstPersonState","FirstPersonEvent"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/behaviors/particle-emitter/particle-emitter.descriptor.ts","../src/lib/behaviors/particle-emitter/particle-effect.ts"],"sourcesContent":["import { Group, Object3D, Quaternion, Vector3 } from 'three';\n\nimport { Particles } from './gpu';\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { VEC3_ZERO, type Vec3Input, normalizeVec3, toThreeVector3 } from '../../core/vector';\nfunction getRefGlobals(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\nimport type { ParticleEffectDefinition } from './particle-effect';\n\nexport interface ParticleEmitterBehaviorOptions {\n\teffect: ParticleEffectDefinition;\n\tautoplay: boolean;\n\tlocalOffset?: Vec3Input;\n\tfollowPosition: boolean;\n\tfollowRotation: boolean;\n\tautoDestroy: boolean;\n}\n\nexport interface ParticleEmitterHandle {\n\tplay(): void;\n\tstop(): void;\n\tpause(): void;\n\trestart(): void;\n\tburst(): void;\n\tisPlaying(): boolean;\n\tgetSystem(): Particles | null;\n}\n\ntype DesiredParticleState = 'playing' | 'paused' | 'stopped';\n\ninterface ParticleEmitterControlState {\n\tdesiredState: DesiredParticleState;\n\tpendingRestart: boolean;\n\truntime: ParticleEmitterRuntime | null;\n}\n\ninterface ParticleEmitterRuntime {\n\tsystem: Particles;\n\tanchor: Group;\n\tservice: ParticleRendererService;\n\tinitialPosition: Vector3;\n\tinitialQuaternion: Quaternion;\n\t/** Whether the system has been started at least once in this lifecycle. */\n\tstarted: boolean;\n}\n\ninterface ParticleEmitterHostEntity {\n\tuuid: string;\n\tname?: string;\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\tgroup?: Object3D | null;\n\tmesh?: Object3D | null;\n\toptions?: {\n\t\tposition?: Vec3Input;\n\t};\n\tmarkedForRemoval?: boolean;\n\tnodeDestroy?(params: { me: unknown; globals: unknown }): void;\n\t__zylemParticleSystemEntity?: boolean;\n}\n\nconst PARTICLE_EMITTER_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:particle-emitter',\n);\n\nconst DEFAULT_PARTICLE_EFFECT: ParticleEffectDefinition = {\n\tcreate() {\n\t\tthrow new Error(\n\t\t\t'ParticleEmitterBehavior requires an effect definition created with particleEffect(...).',\n\t\t);\n\t},\n};\n\nconst defaultOptions: ParticleEmitterBehaviorOptions = {\n\teffect: DEFAULT_PARTICLE_EFFECT,\n\tautoplay: true,\n\tlocalOffset: undefined,\n\tfollowPosition: true,\n\tfollowRotation: true,\n\tautoDestroy: false,\n};\n\n/**\n * Ticks the GPU particle systems each frame.\n *\n * The previous backend (three.quarks) required a `BatchedRenderer` Object3D in\n * the scene graph; the WebGPU engine instead exposes `Particles` Object3Ds that\n * self-render and only need `update(delta)` called for CPU-side emission.\n */\nclass ParticleRendererService {\n\tprivate readonly systems = new Set<Particles>();\n\n\tconstructor(private readonly sceneRoot: Object3D) {}\n\n\t/** Scene node that emitter anchors are parented to. */\n\tget root(): Object3D {\n\t\treturn this.sceneRoot;\n\t}\n\n\tregister(system: Particles): void {\n\t\tthis.systems.add(system);\n\t}\n\n\tforget(system: Particles): void {\n\t\tthis.systems.delete(system);\n\t}\n\n\tupdate(delta: number): void {\n\t\tfor (const system of this.systems) {\n\t\t\tsystem.update(delta);\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.systems.clear();\n\t}\n}\n\nfunction getParticleControlState(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): ParticleEmitterControlState {\n\tconst runtimeState = (ref as any).__particleEmitterControlState as\n\t\t| ParticleEmitterControlState\n\t\t| undefined;\n\tif (runtimeState) {\n\t\treturn runtimeState;\n\t}\n\n\tconst nextState: ParticleEmitterControlState = {\n\t\tdesiredState: ref.options.autoplay ? 'playing' : 'stopped',\n\t\tpendingRestart: false,\n\t\truntime: null,\n\t};\n\t(ref as any).__particleEmitterControlState = nextState;\n\treturn nextState;\n}\n\nfunction shouldCreateRuntime(\n\tstate: ParticleEmitterControlState,\n): boolean {\n\treturn state.runtime == null\n\t\t&& (state.desiredState !== 'stopped' || state.pendingRestart);\n}\n\nfunction getLocalOffset(options: ParticleEmitterBehaviorOptions): Vector3 {\n\treturn toThreeVector3(options.localOffset, VEC3_ZERO);\n}\n\nfunction readHostTransform(entity: ParticleEmitterHostEntity): {\n\tposition: Vector3;\n\tquaternion: Quaternion;\n} {\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\treturn {\n\t\t\tposition: new Vector3(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z),\n\t\t\tquaternion: new Quaternion(\n\t\t\t\twasmPose.rotation.x,\n\t\t\t\twasmPose.rotation.y,\n\t\t\t\twasmPose.rotation.z,\n\t\t\t\twasmPose.rotation.w,\n\t\t\t),\n\t\t};\n\t}\n\n\tif (entity.body?.translation) {\n\t\tconst position = entity.body.translation();\n\t\tconst rotation = entity.body.rotation?.() ?? { x: 0, y: 0, z: 0, w: 1 };\n\t\treturn {\n\t\t\tposition: new Vector3(position.x, position.y, position.z),\n\t\t\tquaternion: new Quaternion(rotation.x, rotation.y, rotation.z, rotation.w),\n\t\t};\n\t}\n\n\tconst visualRoot = entity.group ?? entity.mesh;\n\tif (visualRoot) {\n\t\tconst position = new Vector3();\n\t\tconst quaternion = new Quaternion();\n\t\tvisualRoot.getWorldPosition(position);\n\t\tvisualRoot.getWorldQuaternion(quaternion);\n\t\treturn { position, quaternion };\n\t}\n\n\tconst position = normalizeVec3(entity.options?.position, VEC3_ZERO);\n\treturn {\n\t\tposition: new Vector3(position.x, position.y, position.z),\n\t\tquaternion: new Quaternion(),\n\t};\n}\n\nfunction syncRuntimeTransform(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\truntime: ParticleEmitterRuntime,\n): void {\n\tconst current = readHostTransform(entity);\n\tconst options = ref.options;\n\tconst basePosition = options.followPosition\n\t\t? current.position\n\t\t: runtime.initialPosition;\n\tconst baseQuaternion = options.followRotation\n\t\t? current.quaternion\n\t\t: runtime.initialQuaternion;\n\tconst offset = getLocalOffset(options);\n\n\tif (options.followRotation) {\n\t\toffset.applyQuaternion(baseQuaternion);\n\t}\n\n\truntime.anchor.position.copy(basePosition).add(offset);\n\truntime.anchor.quaternion.copy(baseQuaternion);\n}\n\nfunction applyRuntimeState(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): void {\n\tconst state = getParticleControlState(ref);\n\tconst runtime = state.runtime;\n\tif (!runtime) {\n\t\treturn;\n\t}\n\n\tif (state.pendingRestart) {\n\t\truntime.system.restart();\n\t\truntime.started = true;\n\t\tstate.pendingRestart = false;\n\n\t\tif (state.desiredState === 'paused') {\n\t\t\truntime.system.pause();\n\t\t} else if (state.desiredState === 'stopped') {\n\t\t\truntime.system.stop();\n\t\t\truntime.started = false;\n\t\t}\n\t\treturn;\n\t}\n\n\tif (state.desiredState === 'paused') {\n\t\truntime.system.pause();\n\t\treturn;\n\t}\n\n\tif (state.desiredState === 'stopped') {\n\t\truntime.system.stop();\n\t\truntime.started = false;\n\t\treturn;\n\t}\n\n\t// playing\n\tif (!runtime.started) {\n\t\truntime.system.start();\n\t\truntime.started = true;\n\t} else {\n\t\truntime.system.resume();\n\t}\n}\n\nfunction releaseRuntime(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\treason: 'manual' | 'system-destroyed',\n): void {\n\tconst state = getParticleControlState(ref);\n\tconst runtime = state.runtime;\n\tif (!runtime) {\n\t\treturn;\n\t}\n\n\tstate.runtime = null;\n\tstate.pendingRestart = false;\n\n\truntime.service.forget(runtime.system);\n\n\tif (reason === 'manual') {\n\t\truntime.system.dispose();\n\t}\n\n\truntime.anchor.removeFromParent();\n}\n\nfunction handleSystemDestroyed(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): void {\n\treleaseRuntime(ref, 'system-destroyed');\n\tconst state = getParticleControlState(ref);\n\tstate.desiredState = 'stopped';\n\n\tif (\n\t\tref.options.autoDestroy\n\t\t&& entity.__zylemParticleSystemEntity\n\t\t&& !entity.markedForRemoval\n\t) {\n\t\tentity.nodeDestroy?.({ me: entity, globals: getRefGlobals(ref)?.() ?? {} });\n\t}\n}\n\nfunction createRuntime(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\tservice: ParticleRendererService,\n): ParticleEmitterRuntime {\n\tconst system = ref.options.effect.create();\n\tconst anchor = new Group();\n\tconst initialTransform = readHostTransform(entity);\n\tconst runtime: ParticleEmitterRuntime = {\n\t\tsystem,\n\t\tanchor,\n\t\tservice,\n\t\tinitialPosition: initialTransform.position.clone(),\n\t\tinitialQuaternion: initialTransform.quaternion.clone(),\n\t\tstarted: false,\n\t};\n\n\tanchor.name = `${entity.name || entity.uuid}:particle-anchor`;\n\tanchor.add(system);\n\tservice.register(system);\n\tservice.root.add(anchor);\n\n\tsyncRuntimeTransform(entity, ref, runtime);\n\treturn runtime;\n}\n\nfunction createParticleEmitterHandle(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): ParticleEmitterHandle {\n\treturn {\n\t\tplay: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tstop: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'stopped';\n\t\t\tstate.pendingRestart = false;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tpause: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'paused';\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\trestart: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tstate.pendingRestart = true;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tburst: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tstate.pendingRestart = true;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tisPlaying: () => {\n\t\t\tconst runtime = getParticleControlState(ref).runtime;\n\t\t\tif (!runtime) {\n\t\t\t\treturn getParticleControlState(ref).desiredState === 'playing';\n\t\t\t}\n\t\t\treturn runtime.system.running;\n\t\t},\n\t\tgetSystem: () => getParticleControlState(ref).runtime?.system ?? null,\n\t};\n}\n\nclass ParticleEmitterBehaviorSystem implements BehaviorSystem {\n\tprivate rendererService: ParticleRendererService | null = null;\n\n\tconstructor(\n\t\tprivate readonly scene: { scene: Object3D },\n\t\tprivate readonly getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate readonly getGlobals?: () => any,\n\t) {}\n\n\tprivate getRendererService(): ParticleRendererService {\n\t\tif (!this.rendererService) {\n\t\t\tthis.rendererService = new ParticleRendererService(this.scene.scene);\n\t\t}\n\t\treturn this.rendererService;\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(PARTICLE_EMITTER_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet hasRuntime = false;\n\t\tlet rendererService = this.rendererService;\n\n\t\tfor (const link of links) {\n\t\t\tconst entity = link.entity as ParticleEmitterHostEntity;\n\t\t\tconst ref = link.ref as BehaviorRef<ParticleEmitterBehaviorOptions>;\n\t\t\t(ref as any).__getGlobals = this.getGlobals;\n\t\t\tconst state = getParticleControlState(ref);\n\n\t\t\tif (shouldCreateRuntime(state)) {\n\t\t\t\ttry {\n\t\t\t\t\trendererService ??= this.getRendererService();\n\t\t\t\t\tstate.runtime = createRuntime(entity, ref, rendererService);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.desiredState = 'stopped';\n\t\t\t\t\tstate.pendingRestart = false;\n\t\t\t\t\tconsole.error('Failed to create particle runtime:', error);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!state.runtime) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\thasRuntime = true;\n\t\t\tsyncRuntimeTransform(entity, ref, state.runtime);\n\t\t\tapplyRuntimeState(ref);\n\n\t\t\tif (\n\t\t\t\tref.options.autoDestroy\n\t\t\t\t&& state.runtime.started\n\t\t\t\t&& state.desiredState === 'playing'\n\t\t\t\t&& state.runtime.system.isComplete()\n\t\t\t) {\n\t\t\t\thandleSystemDestroyed(entity, ref);\n\t\t\t}\n\t\t}\n\n\t\tif (hasRuntime && rendererService) {\n\t\t\trendererService.update(delta);\n\t\t}\n\t}\n\n\tdetach(link: BehaviorEntityLink): void {\n\t\treleaseRuntime(\n\t\t\tlink.ref as BehaviorRef<ParticleEmitterBehaviorOptions>,\n\t\t\t'manual',\n\t\t);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(PARTICLE_EMITTER_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\treleaseRuntime(\n\t\t\t\t\tlink.ref as BehaviorRef<ParticleEmitterBehaviorOptions>,\n\t\t\t\t\t'manual',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.rendererService?.destroy();\n\t\tthis.rendererService = null;\n\t}\n}\n\nexport const ParticleEmitterBehavior = defineBehavior<\n\tParticleEmitterBehaviorOptions,\n\tParticleEmitterHandle\n>({\n\tname: 'particle-emitter',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ParticleEmitterBehaviorSystem(ctx.scene, ctx.getBehaviorLinks, ctx.getGlobals),\n\tcreateHandle: createParticleEmitterHandle,\n});\n","import { AdditiveBlending, Color, type ColorRepresentation } from 'three';\n\nimport { Particles } from './gpu';\nimport type { ParticleSettings, ParticlesConfig, RenderSettings } from './gpu';\nimport {\n\tparticleEffect,\n\ttype ParticleEffectDefinition,\n\ttype ParticlePresetMaterialOptions,\n} from './preset-builder';\nimport { electricityPresets, firePresets, gasPresets, magicPresets, waterPresets } from './presets';\n\nexport type {\n\tParticleEffectDefinition,\n\tParticleMagicAgency,\n\tParticleMagicAlignment,\n\tParticleMagicModifierInput,\n\tParticleMagicModifierOptions,\n\tParticleMagicOrder,\n\tParticleMagicRealityEffect,\n\tParticleMagicTemperament,\n\tParticlePresetMaterialOptions,\n\tSemanticParticlePresetOptions,\n} from './preset-builder';\n\nexport interface BurstParticlePresetOptions extends ParticlePresetMaterialOptions {\n\tcolor?: ColorRepresentation;\n\tcount?: number;\n\tduration?: number;\n\tlife?: number | readonly [number, number];\n\tsize?: number | readonly [number, number];\n\tspeed?: number | readonly [number, number];\n\t/**\n\t * Kept for API compatibility. Emitter follow behavior is controlled by the\n\t * particle-emitter behavior (followPosition/followRotation), so this flag is\n\t * not used by the GPU engine.\n\t */\n\tworldSpace?: boolean;\n}\n\ninterface BurstDefaults {\n\tduration: number;\n\tlife: [number, number];\n\tspeed: [number, number];\n\tsize: [number, number];\n\tcolor: ColorRepresentation;\n\tcount: number;\n\tintensity: number;\n}\n\nfunction toRange(\n\tvalue: number | readonly [number, number] | undefined,\n\tfallback: [number, number],\n): [number, number] {\n\tif (value === undefined) return fallback;\n\tif (Array.isArray(value)) {\n\t\treturn [value[0] ?? fallback[0], value[1] ?? fallback[1]];\n\t}\n\tconst single = value as number;\n\treturn [single, single];\n}\n\nfunction toHexColor(color: ColorRepresentation): string {\n\treturn `#${new Color(color).getHexString()}`;\n}\n\nfunction makeBurstConfig(\n\toptions: BurstParticlePresetOptions,\n\tdefaults: BurstDefaults,\n): ParticlesConfig {\n\tconst count = Math.max(1, Math.round(options.count ?? defaults.count));\n\tconst color = toHexColor(options.color ?? defaults.color);\n\tconst blending = (options.blending ?? AdditiveBlending) as RenderSettings['blendingMode'];\n\n\tconst particles: Partial<ParticleSettings> & Pick<ParticleSettings, 'count'> = {\n\t\tcount,\n\t\tintensity: options.opacity ?? defaults.intensity,\n\t\tcolors: [\n\t\t\t[\n\t\t\t\t{ color, stop: 0 },\n\t\t\t\t{ color, stop: 1 },\n\t\t\t],\n\t\t],\n\t\tfadeAlpha: [0.05, 0.7],\n\t\tfadeSize: [0.1, 0.85],\n\t};\n\tif (options.texture) {\n\t\tparticles.alphaMapsStart = [options.texture] as unknown as ParticleSettings['alphaMapsStart'];\n\t}\n\n\treturn {\n\t\tparticles,\n\t\temitter: {\n\t\t\tduration: options.duration ?? defaults.duration,\n\t\t\tloop: false,\n\t\t\tspawnMode: 'burst',\n\t\t\trate: count,\n\t\t\tstatic: 0,\n\t\t\tlifetime: toRange(options.life, defaults.life),\n\t\t\tspeed: toRange(options.speed, defaults.speed),\n\t\t\tsize: toRange(options.size, defaults.size),\n\t\t\tdirectionMin: [-1, -1, -1],\n\t\t\tdirectionMax: [1, 1, 1],\n\t\t},\n\t\trender: { blendingMode: blending },\n\t};\n}\n\nexport const particlePresets = {\n\tburst(options: BurstParticlePresetOptions = {}): ParticleEffectDefinition {\n\t\tconst config = makeBurstConfig(options, {\n\t\t\tduration: 0.25,\n\t\t\tlife: [0.3, 0.7],\n\t\t\tspeed: [1.5, 4],\n\t\t\tsize: [0.08, 0.18],\n\t\t\tcolor: '#ffffff',\n\t\t\tcount: 18,\n\t\t\tintensity: 1,\n\t\t});\n\t\treturn particleEffect(() => new Particles(config));\n\t},\n\tsmoke(options: BurstParticlePresetOptions = {}): ParticleEffectDefinition {\n\t\tconst config = makeBurstConfig(options, {\n\t\t\tduration: 1.1,\n\t\t\tlife: [0.8, 1.6],\n\t\t\tspeed: [0.2, 0.8],\n\t\t\tsize: [0.2, 0.5],\n\t\t\tcolor: '#999999',\n\t\t\tcount: 10,\n\t\t\tintensity: 0.85,\n\t\t});\n\t\treturn particleEffect(() => new Particles(config));\n\t},\n\tfire: firePresets,\n\twater: waterPresets,\n\tgas: gasPresets,\n\telectricity: electricityPresets,\n\tmagic: magicPresets,\n} as const;\n\nexport { particleEffect } from './preset-builder';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,SAAS,OAAiB,YAAY,eAAe;AAMrD,SAAS,cACR,KACqB;AACrB,SAAS,IAAY,gBAAgB;AACtC;AAyDA,IAAM,gCAAgC,uBAAO;AAAA,EAC5C;AACD;AAEA,IAAM,0BAAoD;AAAA,EACzD,SAAS;AACR,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACD;AAEA,IAAM,iBAAiD;AAAA,EACtD,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,aAAa;AACd;AASA,IAAM,0BAAN,MAA8B;AAAA,EAG7B,YAA6B,WAAqB;AAArB;AAAA,EAAsB;AAAA,EAAtB;AAAA,EAFZ,UAAU,oBAAI,IAAe;AAAA;AAAA,EAK9C,IAAI,OAAiB;AACpB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,SAAS,QAAyB;AACjC,SAAK,QAAQ,IAAI,MAAM;AAAA,EACxB;AAAA,EAEA,OAAO,QAAyB;AAC/B,SAAK,QAAQ,OAAO,MAAM;AAAA,EAC3B;AAAA,EAEA,OAAO,OAAqB;AAC3B,eAAW,UAAU,KAAK,SAAS;AAClC,aAAO,OAAO,KAAK;AAAA,IACpB;AAAA,EACD;AAAA,EAEA,UAAgB;AACf,SAAK,QAAQ,MAAM;AAAA,EACpB;AACD;AAEA,SAAS,wBACR,KAC8B;AAC9B,QAAM,eAAgB,IAAY;AAGlC,MAAI,cAAc;AACjB,WAAO;AAAA,EACR;AAEA,QAAM,YAAyC;AAAA,IAC9C,cAAc,IAAI,QAAQ,WAAW,YAAY;AAAA,IACjD,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACV;AACA,EAAC,IAAY,gCAAgC;AAC7C,SAAO;AACR;AAEA,SAAS,oBACR,OACU;AACV,SAAO,MAAM,WAAW,SACnB,MAAM,iBAAiB,aAAa,MAAM;AAChD;AAEA,SAAS,eAAe,SAAkD;AACzE,SAAO,eAAe,QAAQ,aAAa,SAAS;AACrD;AAEA,SAAS,kBAAkB,QAGzB;AACD,QAAM,WAAY,OAAe,UAAU;AAC3C,MAAI,YAAa,OAAe,iBAAiB,GAAG;AACnD,WAAO;AAAA,MACN,UAAU,IAAI,QAAQ,SAAS,SAAS,GAAG,SAAS,SAAS,GAAG,SAAS,SAAS,CAAC;AAAA,MACnF,YAAY,IAAI;AAAA,QACf,SAAS,SAAS;AAAA,QAClB,SAAS,SAAS;AAAA,QAClB,SAAS,SAAS;AAAA,QAClB,SAAS,SAAS;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAEA,MAAI,OAAO,MAAM,aAAa;AAC7B,UAAMA,YAAW,OAAO,KAAK,YAAY;AACzC,UAAM,WAAW,OAAO,KAAK,WAAW,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AACtE,WAAO;AAAA,MACN,UAAU,IAAI,QAAQA,UAAS,GAAGA,UAAS,GAAGA,UAAS,CAAC;AAAA,MACxD,YAAY,IAAI,WAAW,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAAA,IAC1E;AAAA,EACD;AAEA,QAAM,aAAa,OAAO,SAAS,OAAO;AAC1C,MAAI,YAAY;AACf,UAAMA,YAAW,IAAI,QAAQ;AAC7B,UAAM,aAAa,IAAI,WAAW;AAClC,eAAW,iBAAiBA,SAAQ;AACpC,eAAW,mBAAmB,UAAU;AACxC,WAAO,EAAE,UAAAA,WAAU,WAAW;AAAA,EAC/B;AAEA,QAAM,WAAW,cAAc,OAAO,SAAS,UAAU,SAAS;AAClE,SAAO;AAAA,IACN,UAAU,IAAI,QAAQ,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAAA,IACxD,YAAY,IAAI,WAAW;AAAA,EAC5B;AACD;AAEA,SAAS,qBACR,QACA,KACA,SACO;AACP,QAAM,UAAU,kBAAkB,MAAM;AACxC,QAAM,UAAU,IAAI;AACpB,QAAM,eAAe,QAAQ,iBAC1B,QAAQ,WACR,QAAQ;AACX,QAAM,iBAAiB,QAAQ,iBAC5B,QAAQ,aACR,QAAQ;AACX,QAAM,SAAS,eAAe,OAAO;AAErC,MAAI,QAAQ,gBAAgB;AAC3B,WAAO,gBAAgB,cAAc;AAAA,EACtC;AAEA,UAAQ,OAAO,SAAS,KAAK,YAAY,EAAE,IAAI,MAAM;AACrD,UAAQ,OAAO,WAAW,KAAK,cAAc;AAC9C;AAEA,SAAS,kBACR,KACO;AACP,QAAM,QAAQ,wBAAwB,GAAG;AACzC,QAAM,UAAU,MAAM;AACtB,MAAI,CAAC,SAAS;AACb;AAAA,EACD;AAEA,MAAI,MAAM,gBAAgB;AACzB,YAAQ,OAAO,QAAQ;AACvB,YAAQ,UAAU;AAClB,UAAM,iBAAiB;AAEvB,QAAI,MAAM,iBAAiB,UAAU;AACpC,cAAQ,OAAO,MAAM;AAAA,IACtB,WAAW,MAAM,iBAAiB,WAAW;AAC5C,cAAQ,OAAO,KAAK;AACpB,cAAQ,UAAU;AAAA,IACnB;AACA;AAAA,EACD;AAEA,MAAI,MAAM,iBAAiB,UAAU;AACpC,YAAQ,OAAO,MAAM;AACrB;AAAA,EACD;AAEA,MAAI,MAAM,iBAAiB,WAAW;AACrC,YAAQ,OAAO,KAAK;AACpB,YAAQ,UAAU;AAClB;AAAA,EACD;AAGA,MAAI,CAAC,QAAQ,SAAS;AACrB,YAAQ,OAAO,MAAM;AACrB,YAAQ,UAAU;AAAA,EACnB,OAAO;AACN,YAAQ,OAAO,OAAO;AAAA,EACvB;AACD;AAEA,SAAS,eACR,KACA,QACO;AACP,QAAM,QAAQ,wBAAwB,GAAG;AACzC,QAAM,UAAU,MAAM;AACtB,MAAI,CAAC,SAAS;AACb;AAAA,EACD;AAEA,QAAM,UAAU;AAChB,QAAM,iBAAiB;AAEvB,UAAQ,QAAQ,OAAO,QAAQ,MAAM;AAErC,MAAI,WAAW,UAAU;AACxB,YAAQ,OAAO,QAAQ;AAAA,EACxB;AAEA,UAAQ,OAAO,iBAAiB;AACjC;AAEA,SAAS,sBACR,QACA,KACO;AACP,iBAAe,KAAK,kBAAkB;AACtC,QAAM,QAAQ,wBAAwB,GAAG;AACzC,QAAM,eAAe;AAErB,MACC,IAAI,QAAQ,eACT,OAAO,+BACP,CAAC,OAAO,kBACV;AACD,WAAO,cAAc,EAAE,IAAI,QAAQ,SAAS,cAAc,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;AAAA,EAC3E;AACD;AAEA,SAAS,cACR,QACA,KACA,SACyB;AACzB,QAAM,SAAS,IAAI,QAAQ,OAAO,OAAO;AACzC,QAAM,SAAS,IAAI,MAAM;AACzB,QAAM,mBAAmB,kBAAkB,MAAM;AACjD,QAAM,UAAkC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB,iBAAiB,SAAS,MAAM;AAAA,IACjD,mBAAmB,iBAAiB,WAAW,MAAM;AAAA,IACrD,SAAS;AAAA,EACV;AAEA,SAAO,OAAO,GAAG,OAAO,QAAQ,OAAO,IAAI;AAC3C,SAAO,IAAI,MAAM;AACjB,UAAQ,SAAS,MAAM;AACvB,UAAQ,KAAK,IAAI,MAAM;AAEvB,uBAAqB,QAAQ,KAAK,OAAO;AACzC,SAAO;AACR;AAEA,SAAS,4BACR,KACwB;AACxB,SAAO;AAAA,IACN,MAAM,MAAM;AACX,YAAM,QAAQ,wBAAwB,GAAG;AACzC,YAAM,eAAe;AACrB,wBAAkB,GAAG;AAAA,IACtB;AAAA,IACA,MAAM,MAAM;AACX,YAAM,QAAQ,wBAAwB,GAAG;AACzC,YAAM,eAAe;AACrB,YAAM,iBAAiB;AACvB,wBAAkB,GAAG;AAAA,IACtB;AAAA,IACA,OAAO,MAAM;AACZ,YAAM,QAAQ,wBAAwB,GAAG;AACzC,YAAM,eAAe;AACrB,wBAAkB,GAAG;AAAA,IACtB;AAAA,IACA,SAAS,MAAM;AACd,YAAM,QAAQ,wBAAwB,GAAG;AACzC,YAAM,eAAe;AACrB,YAAM,iBAAiB;AACvB,wBAAkB,GAAG;AAAA,IACtB;AAAA,IACA,OAAO,MAAM;AACZ,YAAM,QAAQ,wBAAwB,GAAG;AACzC,YAAM,eAAe;AACrB,YAAM,iBAAiB;AACvB,wBAAkB,GAAG;AAAA,IACtB;AAAA,IACA,WAAW,MAAM;AAChB,YAAM,UAAU,wBAAwB,GAAG,EAAE;AAC7C,UAAI,CAAC,SAAS;AACb,eAAO,wBAAwB,GAAG,EAAE,iBAAiB;AAAA,MACtD;AACA,aAAO,QAAQ,OAAO;AAAA,IACvB;AAAA,IACA,WAAW,MAAM,wBAAwB,GAAG,EAAE,SAAS,UAAU;AAAA,EAClE;AACD;AAEA,IAAM,gCAAN,MAA8D;AAAA,EAG7D,YACkB,OACA,kBACA,YAChB;AAHgB;AACA;AACA;AAAA,EACf;AAAA,EAHe;AAAA,EACA;AAAA,EACA;AAAA,EALV,kBAAkD;AAAA,EAQlD,qBAA8C;AACrD,QAAI,CAAC,KAAK,iBAAiB;AAC1B,WAAK,kBAAkB,IAAI,wBAAwB,KAAK,MAAM,KAAK;AAAA,IACpE;AACA,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,OAAO,MAAe,OAAqB;AAC1C,UAAM,QAAQ,KAAK,mBAAmB,6BAA6B;AACnE,QAAI,CAAC,OAAO;AACX;AAAA,IACD;AAEA,QAAI,aAAa;AACjB,QAAI,kBAAkB,KAAK;AAE3B,eAAW,QAAQ,OAAO;AACzB,YAAM,SAAS,KAAK;AACpB,YAAM,MAAM,KAAK;AACjB,MAAC,IAAY,eAAe,KAAK;AACjC,YAAM,QAAQ,wBAAwB,GAAG;AAEzC,UAAI,oBAAoB,KAAK,GAAG;AAC/B,YAAI;AACH,8BAAoB,KAAK,mBAAmB;AAC5C,gBAAM,UAAU,cAAc,QAAQ,KAAK,eAAe;AAAA,QAC3D,SAAS,OAAO;AACf,gBAAM,eAAe;AACrB,gBAAM,iBAAiB;AACvB,kBAAQ,MAAM,sCAAsC,KAAK;AACzD;AAAA,QACD;AAAA,MACD;AAEA,UAAI,CAAC,MAAM,SAAS;AACnB;AAAA,MACD;AAEA,mBAAa;AACb,2BAAqB,QAAQ,KAAK,MAAM,OAAO;AAC/C,wBAAkB,GAAG;AAErB,UACC,IAAI,QAAQ,eACT,MAAM,QAAQ,WACd,MAAM,iBAAiB,aACvB,MAAM,QAAQ,OAAO,WAAW,GAClC;AACD,8BAAsB,QAAQ,GAAG;AAAA,MAClC;AAAA,IACD;AAEA,QAAI,cAAc,iBAAiB;AAClC,sBAAgB,OAAO,KAAK;AAAA,IAC7B;AAAA,EACD;AAAA,EAEA,OAAO,MAAgC;AACtC;AAAA,MACC,KAAK;AAAA,MACL;AAAA,IACD;AAAA,EACD;AAAA,EAEA,QAAQ,MAAqB;AAC5B,UAAM,QAAQ,KAAK,mBAAmB,6BAA6B;AACnE,QAAI,OAAO;AACV,iBAAW,QAAQ,OAAO;AACzB;AAAA,UACC,KAAK;AAAA,UACL;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,kBAAkB;AAAA,EACxB;AACD;AAEO,IAAM,0BAA0B,eAGrC;AAAA,EACD,MAAM;AAAA,EACN;AAAA,EACA,eAAe,CAAC,QACf,IAAI,8BAA8B,IAAI,OAAO,IAAI,kBAAkB,IAAI,UAAU;AAAA,EAClF,cAAc;AACf,CAAC;;;ACpdD,SAAS,kBAAkB,aAAuC;AAiDlE,SAAS,QACR,OACA,UACmB;AACnB,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC;AAAA,EACzD;AACA,QAAM,SAAS;AACf,SAAO,CAAC,QAAQ,MAAM;AACvB;AAEA,SAAS,WAAW,OAAoC;AACvD,SAAO,IAAI,IAAI,MAAM,KAAK,EAAE,aAAa,CAAC;AAC3C;AAEA,SAAS,gBACR,SACA,UACkB;AAClB,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,SAAS,SAAS,KAAK,CAAC;AACrE,QAAM,QAAQ,WAAW,QAAQ,SAAS,SAAS,KAAK;AACxD,QAAM,WAAY,QAAQ,YAAY;AAEtC,QAAM,YAAyE;AAAA,IAC9E;AAAA,IACA,WAAW,QAAQ,WAAW,SAAS;AAAA,IACvC,QAAQ;AAAA,MACP;AAAA,QACC,EAAE,OAAO,MAAM,EAAE;AAAA,QACjB,EAAE,OAAO,MAAM,EAAE;AAAA,MAClB;AAAA,IACD;AAAA,IACA,WAAW,CAAC,MAAM,GAAG;AAAA,IACrB,UAAU,CAAC,KAAK,IAAI;AAAA,EACrB;AACA,MAAI,QAAQ,SAAS;AACpB,cAAU,iBAAiB,CAAC,QAAQ,OAAO;AAAA,EAC5C;AAEA,SAAO;AAAA,IACN;AAAA,IACA,SAAS;AAAA,MACR,UAAU,QAAQ,YAAY,SAAS;AAAA,MACvC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU,QAAQ,QAAQ,MAAM,SAAS,IAAI;AAAA,MAC7C,OAAO,QAAQ,QAAQ,OAAO,SAAS,KAAK;AAAA,MAC5C,MAAM,QAAQ,QAAQ,MAAM,SAAS,IAAI;AAAA,MACzC,cAAc,CAAC,IAAI,IAAI,EAAE;AAAA,MACzB,cAAc,CAAC,GAAG,GAAG,CAAC;AAAA,IACvB;AAAA,IACA,QAAQ,EAAE,cAAc,SAAS;AAAA,EAClC;AACD;AAEO,IAAM,kBAAkB;AAAA,EAC9B,MAAM,UAAsC,CAAC,GAA6B;AACzE,UAAM,SAAS,gBAAgB,SAAS;AAAA,MACvC,UAAU;AAAA,MACV,MAAM,CAAC,KAAK,GAAG;AAAA,MACf,OAAO,CAAC,KAAK,CAAC;AAAA,MACd,MAAM,CAAC,MAAM,IAAI;AAAA,MACjB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,IACZ,CAAC;AACD,WAAO,eAAe,MAAM,IAAI,UAAU,MAAM,CAAC;AAAA,EAClD;AAAA,EACA,MAAM,UAAsC,CAAC,GAA6B;AACzE,UAAM,SAAS,gBAAgB,SAAS;AAAA,MACvC,UAAU;AAAA,MACV,MAAM,CAAC,KAAK,GAAG;AAAA,MACf,OAAO,CAAC,KAAK,GAAG;AAAA,MAChB,MAAM,CAAC,KAAK,GAAG;AAAA,MACf,OAAO;AAAA,MACP,OAAO;AAAA,MACP,WAAW;AAAA,IACZ,CAAC;AACD,WAAO,eAAe,MAAM,IAAI,UAAU,MAAM,CAAC;AAAA,EAClD;AAAA,EACA,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,aAAa;AAAA,EACb,OAAO;AACR;","names":["position"]}
|
package/dist/runtime-pong.d.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { a as BehaviorDescriptor, e as BehaviorRef } from './behavior-system-DYbx-x_-.js';
|
|
2
|
-
|
|
3
|
-
interface RuntimePongBallOptions {
|
|
4
|
-
initialVelocity: readonly [number, number];
|
|
5
|
-
}
|
|
6
|
-
interface RuntimePongBallHandle {
|
|
7
|
-
setRuntimePosition(x: number, y: number, z?: number): void;
|
|
8
|
-
setRuntimeVelocity(x: number, y: number): void;
|
|
9
|
-
getRuntimePosition(): {
|
|
10
|
-
x: number;
|
|
11
|
-
y: number;
|
|
12
|
-
z: number;
|
|
13
|
-
} | null;
|
|
14
|
-
}
|
|
15
|
-
interface RuntimePaddleInput2DOptions {
|
|
16
|
-
player: 'p1' | 'p2';
|
|
17
|
-
speed: number;
|
|
18
|
-
}
|
|
19
|
-
interface RuntimeWorldBoundary2DOptions {
|
|
20
|
-
boundaries: {
|
|
21
|
-
left: number;
|
|
22
|
-
right: number;
|
|
23
|
-
bottom: number;
|
|
24
|
-
top: number;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
interface RuntimeRicochet2DOptions {
|
|
28
|
-
minSpeed: number;
|
|
29
|
-
maxSpeed: number;
|
|
30
|
-
speedMultiplier: number;
|
|
31
|
-
reflectionMode: 'simple' | 'angled';
|
|
32
|
-
maxAngleDeg: number;
|
|
33
|
-
}
|
|
34
|
-
interface RuntimeRicochet2DEvent {
|
|
35
|
-
kind: 'wall' | 'paddle';
|
|
36
|
-
}
|
|
37
|
-
interface RuntimeRicochet2DHandle {
|
|
38
|
-
onRicochet(callback: (event: RuntimeRicochet2DEvent) => void): () => void;
|
|
39
|
-
}
|
|
40
|
-
/** Registers a gameplay2d trigger AABB (sensor); wasm reports overlap via {@link emitRuntimeTriggerRegionEnter}. */
|
|
41
|
-
interface RuntimeTriggerRegion2DOptions {
|
|
42
|
-
triggerId: number;
|
|
43
|
-
halfExtents: readonly [number, number];
|
|
44
|
-
}
|
|
45
|
-
interface RuntimeTriggerRegion2DEvent {
|
|
46
|
-
triggerId: number;
|
|
47
|
-
}
|
|
48
|
-
interface RuntimeTriggerRegion2DHandle {
|
|
49
|
-
onRegionEnter(callback: (event: RuntimeTriggerRegion2DEvent) => void): () => void;
|
|
50
|
-
}
|
|
51
|
-
interface RuntimeGoalZone2DOptions {
|
|
52
|
-
scorer: 'p1' | 'p2';
|
|
53
|
-
}
|
|
54
|
-
interface RuntimeGoalZone2DEvent {
|
|
55
|
-
scorer: 'p1' | 'p2';
|
|
56
|
-
}
|
|
57
|
-
interface RuntimeGoalZone2DHandle {
|
|
58
|
-
onGoal(callback: (event: RuntimeGoalZone2DEvent) => void): () => void;
|
|
59
|
-
}
|
|
60
|
-
declare const RUNTIME_PONG_BALL_BEHAVIOR_KEY: unique symbol;
|
|
61
|
-
declare const RUNTIME_PADDLE_INPUT_2D_BEHAVIOR_KEY: unique symbol;
|
|
62
|
-
declare const RUNTIME_WORLD_BOUNDARY_2D_BEHAVIOR_KEY: unique symbol;
|
|
63
|
-
declare const RUNTIME_RICOCHET_2D_BEHAVIOR_KEY: unique symbol;
|
|
64
|
-
declare const RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY: unique symbol;
|
|
65
|
-
declare const RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY: unique symbol;
|
|
66
|
-
declare const RuntimePongBallBehavior: BehaviorDescriptor<RuntimePongBallOptions, RuntimePongBallHandle, unknown>;
|
|
67
|
-
declare const RuntimePaddleInput2DBehavior: BehaviorDescriptor<RuntimePaddleInput2DOptions, Record<string, never>, unknown>;
|
|
68
|
-
declare const RuntimeWorldBoundary2DBehavior: BehaviorDescriptor<{
|
|
69
|
-
boundaries: {
|
|
70
|
-
left: number;
|
|
71
|
-
right: number;
|
|
72
|
-
bottom: number;
|
|
73
|
-
top: number;
|
|
74
|
-
};
|
|
75
|
-
}, Record<string, never>, unknown>;
|
|
76
|
-
declare const RuntimeRicochet2DBehavior: BehaviorDescriptor<RuntimeRicochet2DOptions, RuntimeRicochet2DHandle, unknown>;
|
|
77
|
-
declare const RuntimeTriggerRegion2DBehavior: BehaviorDescriptor<RuntimeTriggerRegion2DOptions, RuntimeTriggerRegion2DHandle, unknown>;
|
|
78
|
-
declare const RuntimeGoalZone2DBehavior: BehaviorDescriptor<RuntimeGoalZone2DOptions, RuntimeGoalZone2DHandle, unknown>;
|
|
79
|
-
declare function emitRuntimeRicochet(ref: BehaviorRef<RuntimeRicochet2DOptions>, event: RuntimeRicochet2DEvent): void;
|
|
80
|
-
declare function emitRuntimeTriggerRegionEnter(ref: BehaviorRef<RuntimeTriggerRegion2DOptions>, event: RuntimeTriggerRegion2DEvent): void;
|
|
81
|
-
declare function emitRuntimeGoal(ref: BehaviorRef<RuntimeGoalZone2DOptions>, event: RuntimeGoalZone2DEvent): void;
|
|
82
|
-
declare function bindRuntimePongBallHandle(ref: BehaviorRef<RuntimePongBallOptions>, controls: {
|
|
83
|
-
setPosition: (x: number, y: number, z: number) => void;
|
|
84
|
-
setVelocity: (x: number, y: number) => void;
|
|
85
|
-
getPosition: () => {
|
|
86
|
-
x: number;
|
|
87
|
-
y: number;
|
|
88
|
-
z: number;
|
|
89
|
-
} | null;
|
|
90
|
-
}): void;
|
|
91
|
-
|
|
92
|
-
export { RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY, RUNTIME_PADDLE_INPUT_2D_BEHAVIOR_KEY, RUNTIME_PONG_BALL_BEHAVIOR_KEY, RUNTIME_RICOCHET_2D_BEHAVIOR_KEY, RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY, RUNTIME_WORLD_BOUNDARY_2D_BEHAVIOR_KEY, RuntimeGoalZone2DBehavior, type RuntimeGoalZone2DEvent, type RuntimeGoalZone2DHandle, type RuntimeGoalZone2DOptions, RuntimePaddleInput2DBehavior, type RuntimePaddleInput2DOptions, RuntimePongBallBehavior, type RuntimePongBallHandle, type RuntimePongBallOptions, RuntimeRicochet2DBehavior, type RuntimeRicochet2DEvent, type RuntimeRicochet2DHandle, type RuntimeRicochet2DOptions, RuntimeTriggerRegion2DBehavior, type RuntimeTriggerRegion2DEvent, type RuntimeTriggerRegion2DHandle, type RuntimeTriggerRegion2DOptions, RuntimeWorldBoundary2DBehavior, type RuntimeWorldBoundary2DOptions, bindRuntimePongBallHandle, emitRuntimeGoal, emitRuntimeRicochet, emitRuntimeTriggerRegionEnter };
|
package/dist/runtime-pong.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY,
|
|
3
|
-
RUNTIME_PADDLE_INPUT_2D_BEHAVIOR_KEY,
|
|
4
|
-
RUNTIME_PONG_BALL_BEHAVIOR_KEY,
|
|
5
|
-
RUNTIME_RICOCHET_2D_BEHAVIOR_KEY,
|
|
6
|
-
RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY,
|
|
7
|
-
RUNTIME_WORLD_BOUNDARY_2D_BEHAVIOR_KEY,
|
|
8
|
-
RuntimeGoalZone2DBehavior,
|
|
9
|
-
RuntimePaddleInput2DBehavior,
|
|
10
|
-
RuntimePongBallBehavior,
|
|
11
|
-
RuntimeRicochet2DBehavior,
|
|
12
|
-
RuntimeTriggerRegion2DBehavior,
|
|
13
|
-
RuntimeWorldBoundary2DBehavior,
|
|
14
|
-
bindRuntimePongBallHandle,
|
|
15
|
-
emitRuntimeGoal,
|
|
16
|
-
emitRuntimeRicochet,
|
|
17
|
-
emitRuntimeTriggerRegionEnter
|
|
18
|
-
} from "./chunk-2C3Z5GE7.js";
|
|
19
|
-
import "./chunk-EZNCCO4L.js";
|
|
20
|
-
export {
|
|
21
|
-
RUNTIME_GOAL_ZONE_2D_BEHAVIOR_KEY,
|
|
22
|
-
RUNTIME_PADDLE_INPUT_2D_BEHAVIOR_KEY,
|
|
23
|
-
RUNTIME_PONG_BALL_BEHAVIOR_KEY,
|
|
24
|
-
RUNTIME_RICOCHET_2D_BEHAVIOR_KEY,
|
|
25
|
-
RUNTIME_TRIGGER_REGION_2D_BEHAVIOR_KEY,
|
|
26
|
-
RUNTIME_WORLD_BOUNDARY_2D_BEHAVIOR_KEY,
|
|
27
|
-
RuntimeGoalZone2DBehavior,
|
|
28
|
-
RuntimePaddleInput2DBehavior,
|
|
29
|
-
RuntimePongBallBehavior,
|
|
30
|
-
RuntimeRicochet2DBehavior,
|
|
31
|
-
RuntimeTriggerRegion2DBehavior,
|
|
32
|
-
RuntimeWorldBoundary2DBehavior,
|
|
33
|
-
bindRuntimePongBallHandle,
|
|
34
|
-
emitRuntimeGoal,
|
|
35
|
-
emitRuntimeRicochet,
|
|
36
|
-
emitRuntimeTriggerRegionEnter
|
|
37
|
-
};
|
|
38
|
-
//# sourceMappingURL=runtime-pong.js.map
|
|
File without changes
|