@zylem/behaviors 0.4.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +13 -1
  2. package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CldqNUgr.d.ts} +334 -19
  3. package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
  4. package/dist/chunk-2PAHQZZD.js.map +1 -0
  5. package/dist/chunk-4CEW64HO.js +210 -0
  6. package/dist/chunk-4CEW64HO.js.map +1 -0
  7. package/dist/chunk-4LLK2FJI.js +344 -0
  8. package/dist/chunk-4LLK2FJI.js.map +1 -0
  9. package/dist/chunk-4MZ57HPD.js +323 -0
  10. package/dist/chunk-4MZ57HPD.js.map +1 -0
  11. package/dist/chunk-52FJIDGL.js +30 -0
  12. package/dist/chunk-52FJIDGL.js.map +1 -0
  13. package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
  14. package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
  15. package/dist/chunk-5WRI5ZAA.js +31 -0
  16. package/dist/chunk-5WRI5ZAA.js.map +1 -0
  17. package/dist/{chunk-ZRQWSURL.js → chunk-5XPPLTC7.js} +2 -2
  18. package/dist/chunk-5XPPLTC7.js.map +1 -0
  19. package/dist/{chunk-VMQHNJJI.js → chunk-7DGXUAPV.js} +17 -23
  20. package/dist/chunk-7DGXUAPV.js.map +1 -0
  21. package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
  22. package/dist/{chunk-QDCJLJUV.js → chunk-7W3KY55G.js} +22 -13
  23. package/dist/chunk-7W3KY55G.js.map +1 -0
  24. package/dist/chunk-AS3HR7AS.js +188 -0
  25. package/dist/chunk-AS3HR7AS.js.map +1 -0
  26. package/dist/chunk-BAXJ7XHJ.js +155 -0
  27. package/dist/chunk-BAXJ7XHJ.js.map +1 -0
  28. package/dist/chunk-DZ4LLQON.js +867 -0
  29. package/dist/chunk-DZ4LLQON.js.map +1 -0
  30. package/dist/{chunk-4L36OPY2.js → chunk-G2KUXVU6.js} +81 -135
  31. package/dist/chunk-G2KUXVU6.js.map +1 -0
  32. package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
  33. package/dist/chunk-JVADRLWX.js.map +1 -0
  34. package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
  35. package/dist/chunk-LZIHSJZR.js +191 -0
  36. package/dist/chunk-LZIHSJZR.js.map +1 -0
  37. package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
  38. package/dist/chunk-M3QDKKDF.js.map +1 -0
  39. package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
  40. package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
  41. package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
  42. package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
  43. package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
  44. package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
  45. package/dist/chunk-PLIXVF7B.js.map +1 -0
  46. package/dist/{chunk-27UPCP5B.js → chunk-QS3VXWVO.js} +22 -13
  47. package/dist/chunk-QS3VXWVO.js.map +1 -0
  48. package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
  49. package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
  50. package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
  51. package/dist/chunk-TBUKJKY6.js.map +1 -0
  52. package/dist/{chunk-Z72F2ENM.js → chunk-WU6XXL3D.js} +17 -26
  53. package/dist/chunk-WU6XXL3D.js.map +1 -0
  54. package/dist/{chunk-A4CA35DQ.js → chunk-Y4PHT2HG.js} +25 -45
  55. package/dist/chunk-Y4PHT2HG.js.map +1 -0
  56. package/dist/components-BmievOxF.d.ts +30 -0
  57. package/dist/cooldown.d.ts +2 -2
  58. package/dist/cooldown.js +2 -1
  59. package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
  60. package/dist/coordinators/boundary-ricochet-3d.js +1 -0
  61. package/dist/coordinators/boundary-ricochet.d.ts +4 -4
  62. package/dist/coordinators/boundary-ricochet.js +3 -2
  63. package/dist/coordinators/first-person-shooter.js +1 -0
  64. package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
  65. package/dist/coordinators/multidirectional-space-shooter.js +5 -3
  66. package/dist/coordinators/top-down-shooter.d.ts +3 -3
  67. package/dist/coordinators/top-down-shooter.js +5 -3
  68. package/dist/core.d.ts +298 -8
  69. package/dist/core.js +502 -14
  70. package/dist/core.js.map +1 -1
  71. package/dist/destructible-3d.d.ts +32 -4
  72. package/dist/destructible-3d.js +2 -1
  73. package/dist/destructible-prebake.js +1 -0
  74. package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
  75. package/dist/first-person.d.ts +27 -38
  76. package/dist/first-person.js +8 -8
  77. package/dist/index.d.ts +14 -15
  78. package/dist/index.js +38 -53
  79. package/dist/jumper-2d.d.ts +3 -17
  80. package/dist/jumper-2d.js +4 -9
  81. package/dist/jumper-3d.d.ts +5 -39
  82. package/dist/jumper-3d.js +5 -10
  83. package/dist/{moveable-Cl9h-_w7.d.ts → moveable-rdIvWiak.d.ts} +21 -4
  84. package/dist/particle-emitter/presets.js +1 -0
  85. package/dist/particle-emitter.d.ts +3 -3
  86. package/dist/particle-emitter.js +3 -2
  87. package/dist/platformer-2d.d.ts +21 -82
  88. package/dist/platformer-2d.js +4 -5
  89. package/dist/platformer-3d.d.ts +21 -78
  90. package/dist/platformer-3d.js +4 -5
  91. package/dist/ricochet-2d.d.ts +3 -3
  92. package/dist/ricochet-2d.js +4 -3
  93. package/dist/ricochet-3d.d.ts +3 -3
  94. package/dist/ricochet-3d.js +4 -3
  95. package/dist/runtime-2d.d.ts +2 -2
  96. package/dist/runtime-2d.js +1 -0
  97. package/dist/runtime-2d.js.map +1 -1
  98. package/dist/screen-visibility.d.ts +2 -2
  99. package/dist/screen-visibility.js +1 -0
  100. package/dist/screen-wrap.d.ts +2 -2
  101. package/dist/screen-wrap.js +4 -3
  102. package/dist/shooter-2d.d.ts +3 -3
  103. package/dist/shooter-2d.js +4 -3
  104. package/dist/thruster.d.ts +5 -34
  105. package/dist/thruster.js +4 -6
  106. package/dist/top-down-movement.d.ts +9 -27
  107. package/dist/top-down-movement.js +6 -6
  108. package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
  109. package/dist/world-boundary-2d.d.ts +2 -2
  110. package/dist/world-boundary-2d.js +5 -4
  111. package/dist/world-boundary-3d.d.ts +2 -2
  112. package/dist/world-boundary-3d.js +4 -3
  113. package/package.json +4 -5
  114. package/dist/chunk-27UPCP5B.js.map +0 -1
  115. package/dist/chunk-4L36OPY2.js.map +0 -1
  116. package/dist/chunk-4URF65BR.js +0 -44
  117. package/dist/chunk-4URF65BR.js.map +0 -1
  118. package/dist/chunk-5XZWTFGF.js.map +0 -1
  119. package/dist/chunk-67XLJ26X.js +0 -536
  120. package/dist/chunk-67XLJ26X.js.map +0 -1
  121. package/dist/chunk-75FJIUIG.js +0 -240
  122. package/dist/chunk-75FJIUIG.js.map +0 -1
  123. package/dist/chunk-A4CA35DQ.js.map +0 -1
  124. package/dist/chunk-BXP4K7RF.js.map +0 -1
  125. package/dist/chunk-F72WX4MH.js +0 -422
  126. package/dist/chunk-F72WX4MH.js.map +0 -1
  127. package/dist/chunk-GFARAJV2.js.map +0 -1
  128. package/dist/chunk-JXMF4NUI.js +0 -309
  129. package/dist/chunk-JXMF4NUI.js.map +0 -1
  130. package/dist/chunk-OTLSUYQQ.js +0 -29
  131. package/dist/chunk-OTLSUYQQ.js.map +0 -1
  132. package/dist/chunk-Q75LKHDF.js +0 -56
  133. package/dist/chunk-Q75LKHDF.js.map +0 -1
  134. package/dist/chunk-QDCJLJUV.js.map +0 -1
  135. package/dist/chunk-RDHSHEZM.js +0 -479
  136. package/dist/chunk-RDHSHEZM.js.map +0 -1
  137. package/dist/chunk-UIG7MWS2.js +0 -518
  138. package/dist/chunk-UIG7MWS2.js.map +0 -1
  139. package/dist/chunk-UL6Q5HDP.js.map +0 -1
  140. package/dist/chunk-VMQHNJJI.js.map +0 -1
  141. package/dist/chunk-WWVD5DR5.js.map +0 -1
  142. package/dist/chunk-Z72F2ENM.js.map +0 -1
  143. package/dist/chunk-ZRQWSURL.js.map +0 -1
  144. package/dist/components-BWG1GkZA.d.ts +0 -20
  145. package/dist/use-behavior-B85d5u7-.d.ts +0 -13
  146. /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
  147. /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
  148. /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
@@ -1,422 +0,0 @@
1
- import {
2
- GroundProbe3D,
3
- getGroundAnchorOffsetY,
4
- getGroundSnapTargetY
5
- } from "./chunk-JXMF4NUI.js";
6
- import {
7
- setVelocityIntent
8
- } from "./chunk-OTLSUYQQ.js";
9
- import {
10
- SyncStateMachine,
11
- t
12
- } from "./chunk-4URF65BR.js";
13
- import {
14
- STAGE_INPUT_BUTTON_JUMP,
15
- readBehaviorSnapshot
16
- } from "./chunk-Q75LKHDF.js";
17
- import {
18
- defineBehavior
19
- } from "./chunk-EZNCCO4L.js";
20
-
21
- // src/lib/behaviors/jumper-2d/components.ts
22
- function createJumpConfig2D(options = {}) {
23
- return {
24
- jumpHeight: options.jumpHeight ?? 2.5,
25
- gravity: options.gravity ?? 20,
26
- maxFallSpeed: options.maxFallSpeed,
27
- maxJumps: options.maxJumps ?? 1,
28
- resetJumpsOnGround: options.resetJumpsOnGround ?? true,
29
- coyoteTimeMs: options.coyoteTimeMs ?? 100,
30
- jumpBufferMs: options.jumpBufferMs ?? 80,
31
- minTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,
32
- variableJump: options.variableJump
33
- };
34
- }
35
- function createJumpInput2D() {
36
- return {
37
- jumpPressed: false,
38
- jumpHeld: false,
39
- jumpReleased: false,
40
- fastFall: false
41
- };
42
- }
43
- function createJumpState2D() {
44
- return {
45
- jumpsUsed: 0,
46
- lastJumpTimeMs: 0,
47
- bufferedJumpMs: 0,
48
- coyoteMs: 0,
49
- isJumping: false,
50
- jumpHoldMs: 0,
51
- jumpCutApplied: false
52
- };
53
- }
54
-
55
- // src/lib/behaviors/jumper-2d/jumper-2d.system.ts
56
- function jumpVelocityFromHeight(gravity, height) {
57
- return Math.sqrt(2 * gravity * height);
58
- }
59
- var Jumper2DTickEvent = /* @__PURE__ */ ((Jumper2DTickEvent3) => {
60
- Jumper2DTickEvent3["None"] = "none";
61
- Jumper2DTickEvent3["Jump"] = "jump";
62
- Jumper2DTickEvent3["Fall"] = "fall";
63
- Jumper2DTickEvent3["Land"] = "land";
64
- return Jumper2DTickEvent3;
65
- })(Jumper2DTickEvent || {});
66
- var Jumper2DSystem = class {
67
- tick(config, input, ctx, state) {
68
- const dtMs = ctx.dt * 1e3;
69
- const now = performance.now();
70
- let event = "none" /* None */;
71
- let jumpedThisFrame = false;
72
- if (ctx.isGrounded) {
73
- state.coyoteMs = config.coyoteTimeMs;
74
- if (config.resetJumpsOnGround) {
75
- state.jumpsUsed = 0;
76
- }
77
- if (state.isJumping) {
78
- state.isJumping = false;
79
- state.jumpCutApplied = false;
80
- event = "land" /* Land */;
81
- }
82
- } else {
83
- state.coyoteMs = Math.max(0, state.coyoteMs - dtMs);
84
- }
85
- if (input.jumpPressed) {
86
- state.bufferedJumpMs = config.jumpBufferMs;
87
- } else {
88
- state.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);
89
- }
90
- if (state.isJumping && input.jumpHeld) {
91
- state.jumpHoldMs += dtMs;
92
- }
93
- const wantsJump = state.bufferedJumpMs > 0;
94
- const isFirstJump = ctx.isGrounded || state.coyoteMs > 0 && state.jumpsUsed === 0;
95
- const hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;
96
- const canJump = isFirstJump || hasAirJumps;
97
- const cooldownOk = config.minTimeBetweenJumpsMs == null || now - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;
98
- if (wantsJump && canJump && cooldownOk) {
99
- ctx.setVerticalVelocity(jumpVelocityFromHeight(config.gravity, config.jumpHeight));
100
- jumpedThisFrame = true;
101
- state.jumpsUsed++;
102
- state.lastJumpTimeMs = now;
103
- state.bufferedJumpMs = 0;
104
- state.coyoteMs = 0;
105
- state.isJumping = true;
106
- state.jumpHoldMs = 0;
107
- state.jumpCutApplied = false;
108
- event = "jump" /* Jump */;
109
- }
110
- if (!ctx.isGrounded || jumpedThisFrame) {
111
- let gravityMul = 1;
112
- const isFalling = ctx.velocityY < 0;
113
- if (isFalling) {
114
- gravityMul = input.fastFall ? 1.75 : 1;
115
- if (event !== "land" /* Land */) {
116
- event = "fall" /* Fall */;
117
- }
118
- } else if (state.isJumping) {
119
- const variableJump = config.variableJump;
120
- if (variableJump?.enabled && !state.jumpCutApplied) {
121
- const holdExpired = variableJump.maxHoldMs != null && state.jumpHoldMs >= variableJump.maxHoldMs;
122
- if (!input.jumpHeld || holdExpired) {
123
- gravityMul = variableJump.cutGravityMultiplier;
124
- state.jumpCutApplied = true;
125
- }
126
- }
127
- }
128
- let newVelocityY = ctx.velocityY - config.gravity * gravityMul * ctx.dt;
129
- if (config.maxFallSpeed != null) {
130
- newVelocityY = Math.max(-config.maxFallSpeed, newVelocityY);
131
- }
132
- ctx.setVerticalVelocity(newVelocityY);
133
- } else {
134
- ctx.setVerticalVelocity(0);
135
- }
136
- return { event };
137
- }
138
- };
139
-
140
- // src/lib/behaviors/jumper-2d/jumper-2d-fsm.ts
141
- var Jumper2DState = /* @__PURE__ */ ((Jumper2DState2) => {
142
- Jumper2DState2["Grounded"] = "grounded";
143
- Jumper2DState2["Jumping"] = "jumping";
144
- Jumper2DState2["Falling"] = "falling";
145
- return Jumper2DState2;
146
- })(Jumper2DState || {});
147
- var Jumper2DEvent = /* @__PURE__ */ ((Jumper2DEvent2) => {
148
- Jumper2DEvent2["Jump"] = "jump";
149
- Jumper2DEvent2["Fall"] = "fall";
150
- Jumper2DEvent2["Land"] = "land";
151
- return Jumper2DEvent2;
152
- })(Jumper2DEvent || {});
153
- var Jumper2DFSM = class {
154
- constructor(ctx) {
155
- this.ctx = ctx;
156
- this.machine = new SyncStateMachine(
157
- "grounded" /* Grounded */,
158
- [
159
- t("grounded" /* Grounded */, "jump" /* Jump */, "jumping" /* Jumping */),
160
- t("grounded" /* Grounded */, "fall" /* Fall */, "falling" /* Falling */),
161
- t("grounded" /* Grounded */, "land" /* Land */, "grounded" /* Grounded */),
162
- t("jumping" /* Jumping */, "fall" /* Fall */, "falling" /* Falling */),
163
- t("jumping" /* Jumping */, "land" /* Land */, "grounded" /* Grounded */),
164
- t("jumping" /* Jumping */, "jump" /* Jump */, "jumping" /* Jumping */),
165
- t("falling" /* Falling */, "land" /* Land */, "grounded" /* Grounded */),
166
- t("falling" /* Falling */, "jump" /* Jump */, "jumping" /* Jumping */),
167
- t("falling" /* Falling */, "fall" /* Fall */, "falling" /* Falling */)
168
- ]
169
- );
170
- }
171
- ctx;
172
- machine;
173
- getState() {
174
- return this.machine.getState();
175
- }
176
- dispatch(event) {
177
- if (this.machine.can(event)) {
178
- this.machine.syncDispatch(event);
179
- }
180
- }
181
- isJumping() {
182
- return this.getState() === "jumping" /* Jumping */;
183
- }
184
- isGrounded() {
185
- return this.getState() === "grounded" /* Grounded */;
186
- }
187
- getJumpsUsed() {
188
- return this.ctx.state.jumpsUsed;
189
- }
190
- applyTickEvent(tickEvent, isGrounded) {
191
- switch (tickEvent) {
192
- case "jump":
193
- this.dispatch("jump" /* Jump */);
194
- break;
195
- case "fall":
196
- this.dispatch("fall" /* Fall */);
197
- break;
198
- case "land":
199
- this.dispatch("land" /* Land */);
200
- break;
201
- default:
202
- if (!isGrounded && this.getState() === "grounded" /* Grounded */) {
203
- this.dispatch("fall" /* Fall */);
204
- }
205
- if (isGrounded && this.getState() !== "grounded" /* Grounded */) {
206
- this.dispatch("land" /* Land */);
207
- }
208
- break;
209
- }
210
- }
211
- };
212
-
213
- // src/lib/behaviors/jumper-2d/jumper-2d.descriptor.ts
214
- var defaultOptions = {
215
- jumpHeight: 2.5,
216
- gravity: 20,
217
- maxJumps: 1,
218
- resetJumpsOnGround: true,
219
- coyoteTimeMs: 100,
220
- jumpBufferMs: 80,
221
- groundRayLength: 1,
222
- debugGroundProbe: false
223
- };
224
- var JUMPER_2D_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:jumper-2d");
225
- function isJumper2DGrounded(params) {
226
- if (params.velocityY > 0) {
227
- return false;
228
- }
229
- if (params.snapToGroundDistance != null) {
230
- return params.supportToi != null && params.supportToi <= params.snapToGroundDistance;
231
- }
232
- return params.nearGround === true;
233
- }
234
- function shouldSnapJumper2DToGround(support, options, velocityY) {
235
- return support != null && options.snapToGroundDistance != null && velocityY <= 0 && support.toi <= options.snapToGroundDistance;
236
- }
237
- var Jumper2DBehaviorSystem = class {
238
- constructor(world, scene, wasmStage, getBehaviorLinks) {
239
- this.scene = scene;
240
- this.wasmStage = wasmStage;
241
- this.getBehaviorLinks = getBehaviorLinks;
242
- this.groundProbe = new GroundProbe3D(world);
243
- }
244
- scene;
245
- wasmStage;
246
- getBehaviorLinks;
247
- behavior = new Jumper2DSystem();
248
- groundProbe;
249
- initializedEntities = /* @__PURE__ */ new Set();
250
- timeSinceGroundedMs = /* @__PURE__ */ new Map();
251
- wasJumpHeld = /* @__PURE__ */ new Map();
252
- attachedRuntimeSlots = /* @__PURE__ */ new Set();
253
- /** Reused per-entity per-frame instead of spreading a fresh input object. */
254
- effectiveInput = createJumpInput2D();
255
- update(_ecs, delta) {
256
- const links = this.getBehaviorLinks?.(JUMPER_2D_BEHAVIOR_KEY);
257
- if (!links) return;
258
- for (const link of links) {
259
- const gameEntity = link.entity;
260
- const jumperRef = link.ref;
261
- const options = jumperRef.options;
262
- const handle = gameEntity.runtimeHandle ?? -1;
263
- if (this.wasmStage && handle >= 0) {
264
- this.ensureWasmAttached(handle, options);
265
- jumperRef.__wasmStage = this.wasmStage;
266
- jumperRef.__entity = gameEntity;
267
- const input2 = gameEntity.$jumper2d;
268
- const jumpPressed = !!(input2?.jumpPressed || input2?.jumpHeld);
269
- this.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);
270
- continue;
271
- }
272
- if (!gameEntity.body) continue;
273
- if (!gameEntity.jumper2d) {
274
- gameEntity.jumper2d = createJumpConfig2D(options);
275
- }
276
- if (!gameEntity.$jumper2d) {
277
- gameEntity.$jumper2d = createJumpInput2D();
278
- }
279
- if (!gameEntity.jumper2dState) {
280
- gameEntity.jumper2dState = createJumpState2D();
281
- }
282
- if (!this.initializedEntities.has(gameEntity.uuid)) {
283
- this.initializedEntities.add(gameEntity.uuid);
284
- gameEntity.body.setGravityScale(0, true);
285
- }
286
- if (!jumperRef.fsm && gameEntity.jumper2dState) {
287
- jumperRef.fsm = new Jumper2DFSM({
288
- state: gameEntity.jumper2dState
289
- });
290
- }
291
- const rayLength = options.groundRayLength ?? 1;
292
- const bodyVelocity = gameEntity.body.linvel();
293
- const probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);
294
- const support = this.groundProbe.probeSupport(gameEntity, {
295
- rayLength,
296
- mode: "any",
297
- debug: options.debugGroundProbe ?? false,
298
- scene: this.scene,
299
- originYOffset: probeOriginYOffset
300
- });
301
- const nearGround = support != null;
302
- const isGrounded = isJumper2DGrounded({
303
- nearGround,
304
- velocityY: bodyVelocity.y,
305
- supportToi: support?.toi ?? null,
306
- snapToGroundDistance: options.snapToGroundDistance
307
- });
308
- if (shouldSnapJumper2DToGround(support, options, bodyVelocity.y)) {
309
- const currentPosition = gameEntity.body.translation();
310
- gameEntity.body.setTranslation(
311
- {
312
- x: currentPosition.x,
313
- y: getGroundSnapTargetY(gameEntity, support),
314
- z: currentPosition.z
315
- },
316
- true
317
- );
318
- }
319
- let timeSinceGroundedMs = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;
320
- if (isGrounded) {
321
- timeSinceGroundedMs = 0;
322
- } else {
323
- timeSinceGroundedMs += delta * 1e3;
324
- }
325
- this.timeSinceGroundedMs.set(gameEntity.uuid, timeSinceGroundedMs);
326
- const config = gameEntity.jumper2d;
327
- const input = gameEntity.$jumper2d;
328
- const state = gameEntity.jumper2dState;
329
- const previousHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;
330
- const held = input.jumpHeld === true;
331
- const effectiveInput = this.effectiveInput;
332
- effectiveInput.jumpPressed = input.jumpPressed || held && !previousHeld;
333
- effectiveInput.jumpHeld = held;
334
- effectiveInput.jumpReleased = input.jumpReleased || !held && previousHeld;
335
- effectiveInput.fastFall = input.fastFall;
336
- const store = gameEntity.transformStore;
337
- const ctx = {
338
- dt: delta,
339
- velocityY: bodyVelocity.y,
340
- isGrounded,
341
- timeSinceGroundedMs,
342
- setVerticalVelocity: (y) => {
343
- setVelocityIntent(
344
- store,
345
- "jumper-2d",
346
- { y },
347
- { mode: "replace", priority: 20 }
348
- );
349
- ctx.velocityY = y;
350
- }
351
- };
352
- const result = this.behavior.tick(config, effectiveInput, ctx, state);
353
- this.wasJumpHeld.set(gameEntity.uuid, held);
354
- if (jumperRef.fsm) {
355
- jumperRef.fsm.applyTickEvent(result.event, isGrounded);
356
- }
357
- }
358
- }
359
- ensureWasmAttached(handle, options) {
360
- if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
361
- const jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));
362
- this.wasmStage.attachJumper2D(handle, {
363
- jumpForce,
364
- maxJumps: options.maxJumps ?? 1,
365
- jumpBufferTime: (options.jumpBufferMs ?? 80) / 1e3,
366
- coyoteTime: (options.coyoteTimeMs ?? 100) / 1e3,
367
- gravity: options.gravity ?? 20
368
- });
369
- this.attachedRuntimeSlots.add(handle);
370
- }
371
- destroy(_ecs) {
372
- this.groundProbe.destroy();
373
- this.initializedEntities.clear();
374
- this.timeSinceGroundedMs.clear();
375
- this.wasJumpHeld.clear();
376
- this.attachedRuntimeSlots.clear();
377
- }
378
- };
379
- var Jumper2DBehavior = defineBehavior({
380
- name: "jumper-2d",
381
- defaultOptions,
382
- systemFactory: (ctx) => new Jumper2DBehaviorSystem(ctx.world, ctx.scene, ctx.wasmStage ?? null, ctx.getBehaviorLinks),
383
- // On the wasm fast path the handle reads the runtime snapshot buffer
384
- // (previous-step values); the TS FSM only backs the no-wasm fallback.
385
- createHandle: (ref) => {
386
- const jumpsUsed = () => {
387
- const snapshot = readBehaviorSnapshot(ref);
388
- if (snapshot) return snapshot.jumpCount;
389
- return ref.fsm?.getJumpsUsed() ?? 0;
390
- };
391
- return {
392
- getState: () => {
393
- const snapshot = readBehaviorSnapshot(ref);
394
- if (snapshot) {
395
- if (snapshot.grounded) return "grounded" /* Grounded */;
396
- return snapshot.verticalVelocity > 0 ? "jumping" /* Jumping */ : "falling" /* Falling */;
397
- }
398
- return ref.fsm?.getState() ?? "grounded" /* Grounded */;
399
- },
400
- isJumping: () => {
401
- const snapshot = readBehaviorSnapshot(ref);
402
- if (snapshot) return !snapshot.grounded && snapshot.verticalVelocity > 0;
403
- return ref.fsm?.isJumping() ?? false;
404
- },
405
- getJumpsUsed: jumpsUsed,
406
- getJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed()
407
- };
408
- }
409
- });
410
-
411
- export {
412
- createJumpConfig2D,
413
- createJumpInput2D,
414
- createJumpState2D,
415
- Jumper2DTickEvent,
416
- Jumper2DSystem,
417
- Jumper2DState,
418
- Jumper2DEvent,
419
- Jumper2DFSM,
420
- Jumper2DBehavior
421
- };
422
- //# sourceMappingURL=chunk-F72WX4MH.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/jumper-2d/components.ts","../src/lib/behaviors/jumper-2d/jumper-2d.system.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 Jumper2DSystem {\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 '../../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\tJumper2DSystem,\n\tJumper2DTickEvent,\n} from './jumper-2d.system';\nimport { Jumper2DFSM, Jumper2DState } from './jumper-2d-fsm';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\treadBehaviorSnapshot,\n\ttype WasmStageRuntime,\n} 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');\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: import('@dimforge/rapier3d-compat').RigidBody | null;\n\ttransformStore: import('../../capabilities/transform-store').TransformState;\n\tjumper2d: JumpConfig2D;\n\t$jumper2d: JumpInput2D;\n\tjumper2dState: JumpState2D;\n}\n\nclass Jumper2DBehaviorSystem implements BehaviorSystem {\n\tprivate behavior = new Jumper2DSystem();\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\t/** Reused per-entity per-frame instead of spreading a fresh input object. */\n\tprivate effectiveInput: JumpInput2D = createJumpInput2D();\n\n\tconstructor(\n\t\tworld: import('../../collision/world').ZylemWorld | null,\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\tjumperRef.__wasmStage = this.wasmStage;\n\t\t\t\tjumperRef.__entity = gameEntity;\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.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, 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\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 = this.effectiveInput;\n\t\t\teffectiveInput.jumpPressed = input.jumpPressed || (held && !previousHeld);\n\t\t\teffectiveInput.jumpHeld = held;\n\t\t\teffectiveInput.jumpReleased = input.jumpReleased || (!held && previousHeld);\n\t\t\teffectiveInput.fastFall = input.fastFall;\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 Jumper2DBehavior = 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\t// On the wasm fast path the handle reads the runtime snapshot buffer\n\t// (previous-step values); the TS FSM only backs the no-wasm fallback.\n\tcreateHandle: (ref) => {\n\t\tconst jumpsUsed = () => {\n\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\tif (snapshot) return snapshot.jumpCount;\n\t\t\treturn (ref.fsm as Jumper2DFSM | undefined)?.getJumpsUsed() ?? 0;\n\t\t};\n\t\treturn {\n\t\t\tgetState: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (snapshot) {\n\t\t\t\t\tif (snapshot.grounded) return Jumper2DState.Grounded;\n\t\t\t\t\treturn snapshot.verticalVelocity > 0\n\t\t\t\t\t\t? Jumper2DState.Jumping\n\t\t\t\t\t\t: Jumper2DState.Falling;\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t(ref.fsm as Jumper2DFSM | undefined)?.getState() ??\n\t\t\t\t\tJumper2DState.Grounded\n\t\t\t\t);\n\t\t\t},\n\t\t\tisJumping: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (snapshot) return !snapshot.grounded && snapshot.verticalVelocity > 0;\n\t\t\t\treturn (ref.fsm as Jumper2DFSM | undefined)?.isJumping() ?? false;\n\t\t\t},\n\t\t\tgetJumpsUsed: jumpsUsed,\n\t\t\tgetJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed(),\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/screen-wrap/screen-wrap-fsm.ts","../src/lib/behaviors/screen-wrap/screen-wrap.descriptor.ts"],"sourcesContent":["/**\n * ScreenWrapFSM\n * \n * State machine for screen wrap behavior.\n * Reports position relative to bounds edges.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapState {\n\tCenter = 'center',\n\tNearEdgeLeft = 'near-edge-left',\n\tNearEdgeRight = 'near-edge-right',\n\tNearEdgeTop = 'near-edge-top',\n\tNearEdgeBottom = 'near-edge-bottom',\n\tWrapped = 'wrapped',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapEvent {\n\tEnterCenter = 'enter-center',\n\tApproachLeft = 'approach-left',\n\tApproachRight = 'approach-right',\n\tApproachTop = 'approach-top',\n\tApproachBottom = 'approach-bottom',\n\tWrap = 'wrap',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ScreenWrapFSM\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ScreenWrapFSM {\n\tmachine: SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>;\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>(\n\t\t\tScreenWrapState.Center,\n\t\t\t[\n\t\t\t\t// From Center\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t\t\n\t\t\t\t// From NearEdge to Wrapped\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\n\t\t\t\t// From NearEdge back to Center\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped back to Center\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped to NearEdge (landed near opposite edge)\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t]\n\t\t);\n\t}\n\n\tgetState(): ScreenWrapState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: ScreenWrapEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM based on entity position relative to bounds\n\t */\n\tupdate(position: { x: number; y: number }, bounds: {\n\t\tminX: number; maxX: number; minY: number; maxY: number;\n\t\tedgeThreshold: number;\n\t}, wrapped: boolean): void {\n\t\tconst { x, y } = position;\n\t\tconst { minX, maxX, minY, maxY, edgeThreshold } = bounds;\n\n\t\tif (wrapped) {\n\t\t\tthis.dispatch(ScreenWrapEvent.Wrap);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if near edges\n\t\tconst nearLeft = x < minX + edgeThreshold;\n\t\tconst nearRight = x > maxX - edgeThreshold;\n\t\tconst nearBottom = y < minY + edgeThreshold;\n\t\tconst nearTop = y > maxY - edgeThreshold;\n\n\t\tif (nearLeft) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachLeft);\n\t\t} else if (nearRight) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachRight);\n\t\t} else if (nearTop) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachTop);\n\t\t} else if (nearBottom) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachBottom);\n\t\t} else {\n\t\t\tthis.dispatch(ScreenWrapEvent.EnterCenter);\n\t\t}\n\t}\n}\n","/**\n * ScreenWrapBehavior\n * \n * When an entity exits the defined 2D bounds, it wraps around to the opposite edge.\n * Asteroids-style screen wrapping with FSM for edge detection.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { ScreenWrapFSM } from './screen-wrap-fsm';\nimport { createBounds2DRect, wrapPoint2D } from '../shared/bounds-2d';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Screen wrap options (typed for entity.use() autocomplete)\n */\nexport interface ScreenWrapOptions {\n\t/** Width of the wrapping area (default: 20) */\n\twidth: number;\n\t/** Height of the wrapping area (default: 15) */\n\theight: number;\n\t/** Center X position (default: 0) */\n\tcenterX: number;\n\t/** Center Y position (default: 0) */\n\tcenterY: number;\n\t/** Distance from edge to trigger NearEdge state (default: 2) */\n\tedgeThreshold: number;\n}\n\nconst defaultOptions: ScreenWrapOptions = {\n\twidth: 20,\n\theight: 15,\n\tcenterX: 0,\n\tcenterY: 0,\n\tedgeThreshold: 2,\n};\n\nconst SCREEN_WRAP_BEHAVIOR_KEY = Symbol.for('zylem:behavior:screen-wrap');\n\n/**\n * ScreenWrapSystem - Wraps entities around 2D bounds\n *\n * Mirrors the Rust `screen_wrap` Stage behavior: when `wasmStage` is present\n * and the entity has a `runtimeHandle`, the wasm runtime owns the wrap and\n * this system only mirrors the queried state into the local FSM. Otherwise\n * the legacy TS path runs against the Rapier `RigidBody` translation.\n */\nclass ScreenWrapSystem 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?.(SCREEN_WRAP_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst wrapRef = link.ref as any;\n\t\t\tconst options = wrapRef.options as ScreenWrapOptions;\n\n\t\t\tif (!wrapRef.fsm) {\n\t\t\t\twrapRef.fsm = new ScreenWrapFSM();\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\t\tconst pose = this.wasmStage.getPose(handle);\n\t\t\t\tconst query = this.wasmStage.queryScreenWrap(handle);\n\t\t\t\tif (pose && query) {\n\t\t\t\t\tconst bounds = createBounds2DRect(options);\n\t\t\t\t\twrapRef.fsm.update(\n\t\t\t\t\t\t{ x: pose.position[0], y: pose.position[1] },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tminX: bounds.minX,\n\t\t\t\t\t\t\tmaxX: bounds.maxX,\n\t\t\t\t\t\t\tminY: bounds.minY,\n\t\t\t\t\t\t\tmaxY: bounds.maxY,\n\t\t\t\t\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tquery.lastWrappedAxes !== 0,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!gameEntity.body) continue;\n\t\t\tconst wrapped = this.wrapEntity(gameEntity, options);\n\t\t\tconst pos = gameEntity.body.translation();\n\t\t\tconst bounds = createBounds2DRect(options);\n\t\t\twrapRef.fsm.update(\n\t\t\t\t{ x: pos.x, y: pos.y },\n\t\t\t\t{\n\t\t\t\t\tminX: bounds.minX,\n\t\t\t\t\tmaxX: bounds.maxX,\n\t\t\t\t\tminY: bounds.minY,\n\t\t\t\t\tmaxY: bounds.maxY,\n\t\t\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t\t\t},\n\t\t\t\twrapped,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ScreenWrapOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachScreenWrap(handle, {\n\t\t\twidth: options.width,\n\t\t\theight: options.height,\n\t\t\tcenterX: options.centerX,\n\t\t\tcenterY: options.centerY,\n\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tprivate wrapEntity(entity: any, options: ScreenWrapOptions): boolean {\n\t\tconst body = entity.body;\n\t\tif (!body) return false;\n\n\t\tconst pos = body.translation();\n\t\tconst bounds = createBounds2DRect(options);\n\t\tconst result = wrapPoint2D({ x: pos.x, y: pos.y }, bounds);\n\n\t\tif (result.wrapped) {\n\t\t\tbody.setTranslation({ x: result.x, y: result.y, z: pos.z }, true);\n\t\t}\n\n\t\treturn result.wrapped;\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * ScreenWrapBehavior - Wraps entities around 2D bounds\n * \n * @example\n * ```typescript\n * import { ScreenWrapBehavior } from \"@zylem/game-lib/behavior\";\n * \n * const ship = createSprite({ ... });\n * const wrapRef = ship.use(ScreenWrapBehavior, { width: 20, height: 15 });\n * \n * // Access FSM to observe edge state\n * const fsm = wrapRef.getFSM();\n * console.log(fsm?.getState()); // 'center', 'near-edge-left', 'wrapped', etc.\n * ```\n */\nexport const ScreenWrapBehavior = defineBehavior({\n\tname: 'screen-wrap',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ScreenWrapSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":"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","names":["ScreenWrapState","ScreenWrapEvent","bounds"]}