@zylem/game-lib 0.6.4 → 0.7.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.
Files changed (122) hide show
  1. package/README.md +3 -1
  2. package/dist/actions.d.ts +255 -8
  3. package/dist/actions.js +1 -936
  4. package/dist/audio.d.ts +13 -0
  5. package/dist/audio.js +1 -0
  6. package/dist/base-node-life-cycle-CnJ-7zX-.d.ts +143 -0
  7. package/dist/behavior.d.ts +3 -0
  8. package/dist/behavior.js +1 -0
  9. package/dist/chunk-4QLJUQSJ.js +1 -0
  10. package/dist/chunk-73VZQZUL.js +1 -0
  11. package/dist/chunk-A34ZG3L4.js +1 -0
  12. package/dist/chunk-CDPY4VOQ.js +1 -0
  13. package/dist/chunk-DR6XXZE7.js +19 -0
  14. package/dist/chunk-FM5TBEPO.js +1 -0
  15. package/dist/chunk-G2IIMSUH.js +1 -0
  16. package/dist/chunk-MSC2BEO5.js +1 -0
  17. package/dist/chunk-NIH5CONO.js +1 -0
  18. package/dist/chunk-ONWXGBWB.js +1 -0
  19. package/dist/chunk-QEDQDR27.js +1 -0
  20. package/dist/chunk-QXVH6POE.js +1 -0
  21. package/dist/chunk-RXDTAWI2.js +29 -0
  22. package/dist/chunk-WKHW2QO2.js +1 -0
  23. package/dist/chunk-XRP4JJXL.js +1 -0
  24. package/dist/chunk-YHEWKN7N.js +1 -0
  25. package/dist/chunk-YHKXQ2ZN.js +1 -0
  26. package/dist/core.d.ts +206 -14
  27. package/dist/core.js +24 -12424
  28. package/dist/debug.d.ts +24 -0
  29. package/dist/debug.js +1 -0
  30. package/dist/default-controls-BGc61yYl.d.ts +111 -0
  31. package/dist/{entity-vj-HTjzU.d.ts → entity-DNkYKfdp.d.ts} +452 -578
  32. package/dist/entity-type-map-C94h2TDW.d.ts +781 -0
  33. package/dist/entity.d.ts +265 -0
  34. package/dist/entity.js +1 -0
  35. package/dist/events.d.ts +172 -0
  36. package/dist/events.js +1 -0
  37. package/dist/game-Cuj5gy7U.d.ts +1590 -0
  38. package/dist/game-default-PZLLHYL7.js +1 -0
  39. package/dist/game-interfaces-tfpM5NBk.d.ts +90 -0
  40. package/dist/globals.d.ts +104 -0
  41. package/dist/globals.js +1 -0
  42. package/dist/graphics.d.ts +83 -0
  43. package/dist/graphics.js +1 -0
  44. package/dist/input-ui.d.ts +34 -0
  45. package/dist/input-ui.js +1 -0
  46. package/dist/input.d.ts +72 -0
  47. package/dist/input.js +1 -0
  48. package/dist/material-Wz83vTTp.d.ts +151 -0
  49. package/dist/runtime.d.ts +433 -0
  50. package/dist/runtime.js +1 -0
  51. package/dist/web-components.d.ts +67 -0
  52. package/dist/web-components.js +9 -0
  53. package/dist/world-C9zdyl5d.d.ts +103 -0
  54. package/dist/{camera-4XO5gbQH.d.ts → zylem-stage-runtime-Cs-UDEVU.d.ts} +201 -329
  55. package/package.json +52 -63
  56. package/dist/actions.js.map +0 -1
  57. package/dist/behavior/jumper-2d.d.ts +0 -114
  58. package/dist/behavior/jumper-2d.js +0 -711
  59. package/dist/behavior/jumper-2d.js.map +0 -1
  60. package/dist/behavior/platformer-3d.d.ts +0 -296
  61. package/dist/behavior/platformer-3d.js +0 -761
  62. package/dist/behavior/platformer-3d.js.map +0 -1
  63. package/dist/behavior/ricochet-2d.d.ts +0 -275
  64. package/dist/behavior/ricochet-2d.js +0 -425
  65. package/dist/behavior/ricochet-2d.js.map +0 -1
  66. package/dist/behavior/ricochet-3d.d.ts +0 -117
  67. package/dist/behavior/ricochet-3d.js +0 -443
  68. package/dist/behavior/ricochet-3d.js.map +0 -1
  69. package/dist/behavior/screen-visibility.d.ts +0 -79
  70. package/dist/behavior/screen-visibility.js +0 -358
  71. package/dist/behavior/screen-visibility.js.map +0 -1
  72. package/dist/behavior/screen-wrap.d.ts +0 -87
  73. package/dist/behavior/screen-wrap.js +0 -246
  74. package/dist/behavior/screen-wrap.js.map +0 -1
  75. package/dist/behavior/shooter-2d.d.ts +0 -79
  76. package/dist/behavior/shooter-2d.js +0 -180
  77. package/dist/behavior/shooter-2d.js.map +0 -1
  78. package/dist/behavior/thruster.d.ts +0 -11
  79. package/dist/behavior/thruster.js +0 -292
  80. package/dist/behavior/thruster.js.map +0 -1
  81. package/dist/behavior/top-down-movement.d.ts +0 -56
  82. package/dist/behavior/top-down-movement.js +0 -125
  83. package/dist/behavior/top-down-movement.js.map +0 -1
  84. package/dist/behavior/world-boundary-2d.d.ts +0 -142
  85. package/dist/behavior/world-boundary-2d.js +0 -235
  86. package/dist/behavior/world-boundary-2d.js.map +0 -1
  87. package/dist/behavior/world-boundary-3d.d.ts +0 -76
  88. package/dist/behavior/world-boundary-3d.js +0 -274
  89. package/dist/behavior/world-boundary-3d.js.map +0 -1
  90. package/dist/behavior-descriptor-BXnVR8Ki.d.ts +0 -159
  91. package/dist/blueprints-DmbK2dki.d.ts +0 -26
  92. package/dist/camera.d.ts +0 -6
  93. package/dist/camera.js +0 -1993
  94. package/dist/camera.js.map +0 -1
  95. package/dist/composition-BASvMKrW.d.ts +0 -218
  96. package/dist/core-CARRaS55.d.ts +0 -541
  97. package/dist/core.js.map +0 -1
  98. package/dist/entities-ChFirVL9.d.ts +0 -410
  99. package/dist/entities.d.ts +0 -9
  100. package/dist/entities.js +0 -4986
  101. package/dist/entities.js.map +0 -1
  102. package/dist/entity-Bq_eNEDI.d.ts +0 -28
  103. package/dist/entity-types-DAu8sGJH.d.ts +0 -26
  104. package/dist/global-change-2JvMaz44.d.ts +0 -25
  105. package/dist/main.d.ts +0 -1353
  106. package/dist/main.js +0 -19525
  107. package/dist/main.js.map +0 -1
  108. package/dist/physics-pose-DCc4oE44.d.ts +0 -25
  109. package/dist/physics-protocol-BDD3P5W2.d.ts +0 -200
  110. package/dist/physics-worker.d.ts +0 -21
  111. package/dist/physics-worker.js +0 -306
  112. package/dist/physics-worker.js.map +0 -1
  113. package/dist/physics.d.ts +0 -205
  114. package/dist/physics.js +0 -577
  115. package/dist/physics.js.map +0 -1
  116. package/dist/stage-types-C19IhuzA.d.ts +0 -731
  117. package/dist/stage.d.ts +0 -52
  118. package/dist/stage.js +0 -8479
  119. package/dist/stage.js.map +0 -1
  120. package/dist/sync-state-machine-CZyspBpj.d.ts +0 -16
  121. package/dist/thruster-23lzoPZd.d.ts +0 -180
  122. package/dist/world-DfgxoNMt.d.ts +0 -105
@@ -1,711 +0,0 @@
1
- // src/lib/behaviors/jumper-2d/components.ts
2
- function createJumpConfig2D(options = {}) {
3
- return {
4
- jumpHeight: options.jumpHeight ?? 2.5,
5
- gravity: options.gravity ?? 20,
6
- maxFallSpeed: options.maxFallSpeed,
7
- maxJumps: options.maxJumps ?? 1,
8
- resetJumpsOnGround: options.resetJumpsOnGround ?? true,
9
- coyoteTimeMs: options.coyoteTimeMs ?? 100,
10
- jumpBufferMs: options.jumpBufferMs ?? 80,
11
- minTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,
12
- variableJump: options.variableJump
13
- };
14
- }
15
- function createJumpInput2D() {
16
- return {
17
- jumpPressed: false,
18
- jumpHeld: false,
19
- jumpReleased: false,
20
- fastFall: false
21
- };
22
- }
23
- function createJumpState2D() {
24
- return {
25
- jumpsUsed: 0,
26
- lastJumpTimeMs: 0,
27
- bufferedJumpMs: 0,
28
- coyoteMs: 0,
29
- isJumping: false,
30
- jumpHoldMs: 0,
31
- jumpCutApplied: false
32
- };
33
- }
34
-
35
- // src/lib/behaviors/jumper-2d/jumper-2d.behavior.ts
36
- function jumpVelocityFromHeight(gravity, height) {
37
- return Math.sqrt(2 * gravity * height);
38
- }
39
- var Jumper2DTickEvent = /* @__PURE__ */ ((Jumper2DTickEvent3) => {
40
- Jumper2DTickEvent3["None"] = "none";
41
- Jumper2DTickEvent3["Jump"] = "jump";
42
- Jumper2DTickEvent3["Fall"] = "fall";
43
- Jumper2DTickEvent3["Land"] = "land";
44
- return Jumper2DTickEvent3;
45
- })(Jumper2DTickEvent || {});
46
- var Jumper2DBehavior = class {
47
- tick(config, input, ctx, state) {
48
- const dtMs = ctx.dt * 1e3;
49
- const now = performance.now();
50
- let event = "none" /* None */;
51
- let jumpedThisFrame = false;
52
- if (ctx.isGrounded) {
53
- state.coyoteMs = config.coyoteTimeMs;
54
- if (config.resetJumpsOnGround) {
55
- state.jumpsUsed = 0;
56
- }
57
- if (state.isJumping) {
58
- state.isJumping = false;
59
- state.jumpCutApplied = false;
60
- event = "land" /* Land */;
61
- }
62
- } else {
63
- state.coyoteMs = Math.max(0, state.coyoteMs - dtMs);
64
- }
65
- if (input.jumpPressed) {
66
- state.bufferedJumpMs = config.jumpBufferMs;
67
- } else {
68
- state.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);
69
- }
70
- if (state.isJumping && input.jumpHeld) {
71
- state.jumpHoldMs += dtMs;
72
- }
73
- const wantsJump = state.bufferedJumpMs > 0;
74
- const isFirstJump = ctx.isGrounded || state.coyoteMs > 0 && state.jumpsUsed === 0;
75
- const hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;
76
- const canJump = isFirstJump || hasAirJumps;
77
- const cooldownOk = config.minTimeBetweenJumpsMs == null || now - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;
78
- if (wantsJump && canJump && cooldownOk) {
79
- ctx.setVerticalVelocity(jumpVelocityFromHeight(config.gravity, config.jumpHeight));
80
- jumpedThisFrame = true;
81
- state.jumpsUsed++;
82
- state.lastJumpTimeMs = now;
83
- state.bufferedJumpMs = 0;
84
- state.coyoteMs = 0;
85
- state.isJumping = true;
86
- state.jumpHoldMs = 0;
87
- state.jumpCutApplied = false;
88
- event = "jump" /* Jump */;
89
- }
90
- if (!ctx.isGrounded || jumpedThisFrame) {
91
- let gravityMul = 1;
92
- const isFalling = ctx.velocityY < 0;
93
- if (isFalling) {
94
- gravityMul = input.fastFall ? 1.75 : 1;
95
- if (event !== "land" /* Land */) {
96
- event = "fall" /* Fall */;
97
- }
98
- } else if (state.isJumping) {
99
- const variableJump = config.variableJump;
100
- if (variableJump?.enabled && !state.jumpCutApplied) {
101
- const holdExpired = variableJump.maxHoldMs != null && state.jumpHoldMs >= variableJump.maxHoldMs;
102
- if (!input.jumpHeld || holdExpired) {
103
- gravityMul = variableJump.cutGravityMultiplier;
104
- state.jumpCutApplied = true;
105
- }
106
- }
107
- }
108
- let newVelocityY = ctx.velocityY - config.gravity * gravityMul * ctx.dt;
109
- if (config.maxFallSpeed != null) {
110
- newVelocityY = Math.max(-config.maxFallSpeed, newVelocityY);
111
- }
112
- ctx.setVerticalVelocity(newVelocityY);
113
- } else {
114
- ctx.setVerticalVelocity(0);
115
- }
116
- return { event };
117
- }
118
- };
119
-
120
- // src/lib/core/utility/sync-state-machine.ts
121
- import {
122
- StateMachine as BaseStateMachine
123
- } from "typescript-fsm";
124
- import { t } from "typescript-fsm";
125
- var SyncStateMachine = class extends BaseStateMachine {
126
- constructor(init, transitions = [], logger = console) {
127
- super(init, transitions, logger);
128
- }
129
- dispatch(_event, ..._args) {
130
- throw new Error("SyncStateMachine does not support async dispatch.");
131
- }
132
- syncDispatch(event, ...args) {
133
- const found = this.transitions.some((transition) => {
134
- if (transition.fromState !== this._current || transition.event !== event) {
135
- return false;
136
- }
137
- const current = this._current;
138
- this._current = transition.toState;
139
- if (!transition.cb) {
140
- return true;
141
- }
142
- try {
143
- transition.cb(...args);
144
- return true;
145
- } catch (error) {
146
- this._current = current;
147
- this.logger.error("Exception in callback", error);
148
- throw error;
149
- }
150
- });
151
- if (!found) {
152
- const errorMessage = this.formatErr(this._current, event);
153
- this.logger.error(errorMessage);
154
- }
155
- return found;
156
- }
157
- };
158
-
159
- // src/lib/behaviors/jumper-2d/jumper-2d-fsm.ts
160
- var Jumper2DState = /* @__PURE__ */ ((Jumper2DState2) => {
161
- Jumper2DState2["Grounded"] = "grounded";
162
- Jumper2DState2["Jumping"] = "jumping";
163
- Jumper2DState2["Falling"] = "falling";
164
- return Jumper2DState2;
165
- })(Jumper2DState || {});
166
- var Jumper2DEvent = /* @__PURE__ */ ((Jumper2DEvent2) => {
167
- Jumper2DEvent2["Jump"] = "jump";
168
- Jumper2DEvent2["Fall"] = "fall";
169
- Jumper2DEvent2["Land"] = "land";
170
- return Jumper2DEvent2;
171
- })(Jumper2DEvent || {});
172
- var Jumper2DFSM = class {
173
- constructor(ctx) {
174
- this.ctx = ctx;
175
- this.machine = new SyncStateMachine(
176
- "grounded" /* Grounded */,
177
- [
178
- t("grounded" /* Grounded */, "jump" /* Jump */, "jumping" /* Jumping */),
179
- t("grounded" /* Grounded */, "fall" /* Fall */, "falling" /* Falling */),
180
- t("grounded" /* Grounded */, "land" /* Land */, "grounded" /* Grounded */),
181
- t("jumping" /* Jumping */, "fall" /* Fall */, "falling" /* Falling */),
182
- t("jumping" /* Jumping */, "land" /* Land */, "grounded" /* Grounded */),
183
- t("jumping" /* Jumping */, "jump" /* Jump */, "jumping" /* Jumping */),
184
- t("falling" /* Falling */, "land" /* Land */, "grounded" /* Grounded */),
185
- t("falling" /* Falling */, "jump" /* Jump */, "jumping" /* Jumping */),
186
- t("falling" /* Falling */, "fall" /* Fall */, "falling" /* Falling */)
187
- ]
188
- );
189
- }
190
- machine;
191
- getState() {
192
- return this.machine.getState();
193
- }
194
- dispatch(event) {
195
- if (this.machine.can(event)) {
196
- this.machine.syncDispatch(event);
197
- }
198
- }
199
- isJumping() {
200
- return this.getState() === "jumping" /* Jumping */;
201
- }
202
- isGrounded() {
203
- return this.getState() === "grounded" /* Grounded */;
204
- }
205
- getJumpsUsed() {
206
- return this.ctx.state.jumpsUsed;
207
- }
208
- applyTickEvent(tickEvent, isGrounded) {
209
- switch (tickEvent) {
210
- case "jump":
211
- this.dispatch("jump" /* Jump */);
212
- break;
213
- case "fall":
214
- this.dispatch("fall" /* Fall */);
215
- break;
216
- case "land":
217
- this.dispatch("land" /* Land */);
218
- break;
219
- default:
220
- if (!isGrounded && this.getState() === "grounded" /* Grounded */) {
221
- this.dispatch("fall" /* Fall */);
222
- }
223
- if (isGrounded && this.getState() !== "grounded" /* Grounded */) {
224
- this.dispatch("land" /* Land */);
225
- }
226
- break;
227
- }
228
- }
229
- };
230
-
231
- // src/lib/behaviors/behavior-descriptor.ts
232
- function defineBehavior(config) {
233
- return {
234
- key: /* @__PURE__ */ Symbol.for(`zylem:behavior:${config.name}`),
235
- defaultOptions: config.defaultOptions,
236
- systemFactory: config.systemFactory,
237
- createHandle: config.createHandle
238
- };
239
- }
240
-
241
- // src/lib/actions/capabilities/velocity-intents.ts
242
- function setVelocityIntent(store, sourceId, vector, options = {}) {
243
- const prev = store.velocityChannels[sourceId];
244
- const mode = options.mode ?? prev?.mode ?? "replace";
245
- const priority = options.priority ?? prev?.priority ?? 0;
246
- const isAdditiveMerge = mode === "add" && prev?.mode === "add";
247
- const x = vector.x == null ? prev?.x : isAdditiveMerge ? (prev?.x ?? 0) + vector.x : vector.x;
248
- const y = vector.y == null ? prev?.y : isAdditiveMerge ? (prev?.y ?? 0) + vector.y : vector.y;
249
- const z = vector.z == null ? prev?.z : isAdditiveMerge ? (prev?.z ?? 0) + vector.z : vector.z;
250
- store.velocityChannels[sourceId] = {
251
- x,
252
- y,
253
- z,
254
- mode,
255
- priority
256
- };
257
- store.dirty.velocityChannels = true;
258
- }
259
-
260
- // src/lib/behaviors/shared/ground-probe-3d.ts
261
- import { Ray } from "@dimforge/rapier3d-compat";
262
- import { BufferGeometry, Line, LineBasicMaterial, Vector3 } from "three";
263
-
264
- // src/lib/physics/serialize-descriptors.ts
265
- import { RigidBodyType } from "@dimforge/rapier3d-compat";
266
- function serializeColliderDesc(desc) {
267
- const internal = desc;
268
- const customShapeData = internal.__zylemShapeData;
269
- if (customShapeData?.shape === "trimesh") {
270
- const result2 = {
271
- shape: "trimesh",
272
- dimensions: [],
273
- vertices: [...customShapeData.vertices],
274
- indices: [...customShapeData.indices]
275
- };
276
- const translation = internal.translation;
277
- if (translation && (translation.x !== 0 || translation.y !== 0 || translation.z !== 0)) {
278
- result2.translation = [translation.x, translation.y, translation.z];
279
- }
280
- if (internal.isSensor) {
281
- result2.sensor = true;
282
- }
283
- if (internal.collisionGroups !== void 0 && internal.collisionGroups !== 4294967295) {
284
- result2.collisionGroups = internal.collisionGroups;
285
- }
286
- if (internal.activeCollisionTypes !== void 0) {
287
- result2.activeCollisionTypes = internal.activeCollisionTypes;
288
- }
289
- return result2;
290
- }
291
- const shapeType = internal.shape?.type ?? internal.shapeType ?? 0;
292
- const { shape, dimensions, heightfieldMeta } = extractShapeData(shapeType, internal);
293
- const result = {
294
- shape,
295
- dimensions
296
- };
297
- const t2 = internal.translation;
298
- if (t2 && (t2.x !== 0 || t2.y !== 0 || t2.z !== 0)) {
299
- result.translation = [t2.x, t2.y, t2.z];
300
- }
301
- if (internal.isSensor) {
302
- result.sensor = true;
303
- }
304
- if (internal.collisionGroups !== void 0 && internal.collisionGroups !== 4294967295) {
305
- result.collisionGroups = internal.collisionGroups;
306
- }
307
- if (internal.activeCollisionTypes !== void 0) {
308
- result.activeCollisionTypes = internal.activeCollisionTypes;
309
- }
310
- if (heightfieldMeta) {
311
- result.heightfieldMeta = heightfieldMeta;
312
- }
313
- return result;
314
- }
315
- function extractShapeData(shapeType, internal) {
316
- switch (shapeType) {
317
- case 0:
318
- return {
319
- shape: "ball",
320
- dimensions: [internal.shape?.radius ?? internal.halfExtents?.x ?? 1]
321
- };
322
- case 1:
323
- return {
324
- shape: "cuboid",
325
- dimensions: [
326
- internal.shape?.halfExtents?.x ?? internal.halfExtents?.x ?? 0.5,
327
- internal.shape?.halfExtents?.y ?? internal.halfExtents?.y ?? 0.5,
328
- internal.shape?.halfExtents?.z ?? internal.halfExtents?.z ?? 0.5
329
- ]
330
- };
331
- case 2:
332
- return {
333
- shape: "capsule",
334
- dimensions: [
335
- internal.shape?.halfHeight ?? 0.5,
336
- internal.shape?.radius ?? 0.5
337
- ]
338
- };
339
- case 6:
340
- return {
341
- shape: "cone",
342
- dimensions: [
343
- internal.shape?.halfHeight ?? 1,
344
- internal.shape?.radius ?? 1
345
- ]
346
- };
347
- case 7:
348
- return {
349
- shape: "cylinder",
350
- dimensions: [
351
- internal.shape?.halfHeight ?? 1,
352
- internal.shape?.radius ?? 1
353
- ]
354
- };
355
- case 11: {
356
- const nrows = internal.shape?.nrows ?? 10;
357
- const ncols = internal.shape?.ncols ?? 10;
358
- const heights = internal.shape?.heights;
359
- return {
360
- shape: "heightfield",
361
- dimensions: heights ? Array.from(heights) : [],
362
- heightfieldMeta: { nrows, ncols }
363
- };
364
- }
365
- default:
366
- return { shape: "cuboid", dimensions: [0.5, 0.5, 0.5] };
367
- }
368
- }
369
-
370
- // src/lib/behaviors/shared/ground-probe-3d.ts
371
- var GROUND_SNAP_EPSILON = 1e-3;
372
- var DEFAULT_OFFSETS = [
373
- { x: 0, z: 0 },
374
- { x: 0.4, z: 0.4 },
375
- { x: -0.4, z: 0.4 },
376
- { x: 0.4, z: -0.4 },
377
- { x: -0.4, z: -0.4 }
378
- ];
379
- var GroundProbe3D = class {
380
- constructor(world) {
381
- this.world = world;
382
- }
383
- rays = /* @__PURE__ */ new Map();
384
- debugLines = /* @__PURE__ */ new Map();
385
- probeSupport(entity, options) {
386
- if (!this.world?.world || !entity.body) return null;
387
- const mode = options.mode ?? "any";
388
- const offsets = mode === "center" ? (options.offsets ?? DEFAULT_OFFSETS).slice(0, 1) : options.offsets ?? DEFAULT_OFFSETS;
389
- const translation = entity.body.translation();
390
- const rays = this.getOrCreateRays(entity.uuid, offsets.length);
391
- const originYOffset = options.originYOffset ?? 0;
392
- let support = null;
393
- for (let index = 0; index < offsets.length; index++) {
394
- const offset = offsets[index];
395
- const ray = rays[index];
396
- ray.origin = {
397
- x: translation.x + offset.x,
398
- y: translation.y + originYOffset,
399
- z: translation.z + offset.z
400
- };
401
- ray.dir = { x: 0, y: -1, z: 0 };
402
- const hit = this.world.world.castRay(
403
- ray,
404
- options.rayLength,
405
- true,
406
- void 0,
407
- void 0,
408
- void 0,
409
- entity.body
410
- );
411
- if (!hit) continue;
412
- const nextSupport = {
413
- toi: hit.toi,
414
- point: {
415
- x: ray.origin.x + ray.dir.x * hit.toi,
416
- y: ray.origin.y + ray.dir.y * hit.toi,
417
- z: ray.origin.z + ray.dir.z * hit.toi
418
- },
419
- origin: {
420
- x: ray.origin.x,
421
- y: ray.origin.y,
422
- z: ray.origin.z
423
- },
424
- rayIndex: index,
425
- colliderUuid: hit.collider?._parent?.userData?.uuid
426
- };
427
- if (mode === "center") {
428
- support = nextSupport;
429
- break;
430
- }
431
- if (!support || nextSupport.toi < support.toi) {
432
- support = nextSupport;
433
- }
434
- }
435
- if (options.debug && options.scene) {
436
- this.updateDebugLines(
437
- entity.uuid,
438
- rays,
439
- Boolean(support),
440
- options.rayLength,
441
- options.scene
442
- );
443
- } else {
444
- this.disposeDebugLines(entity.uuid);
445
- }
446
- return support;
447
- }
448
- detect(entity, options) {
449
- return this.probeSupport(entity, options) != null;
450
- }
451
- destroyEntity(uuid) {
452
- this.rays.delete(uuid);
453
- this.disposeDebugLines(uuid);
454
- }
455
- destroy() {
456
- this.rays.clear();
457
- for (const uuid of this.debugLines.keys()) {
458
- this.disposeDebugLines(uuid);
459
- }
460
- this.debugLines.clear();
461
- }
462
- getOrCreateRays(uuid, count) {
463
- let rays = this.rays.get(uuid);
464
- if (!rays || rays.length !== count) {
465
- rays = Array.from(
466
- { length: count },
467
- () => new Ray({ x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 })
468
- );
469
- this.rays.set(uuid, rays);
470
- }
471
- return rays;
472
- }
473
- updateDebugLines(uuid, rays, hasGround, length, scene) {
474
- let lines = this.debugLines.get(uuid);
475
- if (!lines) {
476
- lines = rays.map(() => {
477
- const geometry = new BufferGeometry().setFromPoints([
478
- new Vector3(),
479
- new Vector3()
480
- ]);
481
- const material = new LineBasicMaterial({ color: 16711680 });
482
- const line = new Line(geometry, material);
483
- scene.add(line);
484
- return line;
485
- });
486
- this.debugLines.set(uuid, lines);
487
- }
488
- rays.forEach((ray, index) => {
489
- const line = lines[index];
490
- const start = new Vector3(ray.origin.x, ray.origin.y, ray.origin.z);
491
- const end = new Vector3(
492
- ray.origin.x + ray.dir.x * length,
493
- ray.origin.y + ray.dir.y * length,
494
- ray.origin.z + ray.dir.z * length
495
- );
496
- line.visible = true;
497
- line.geometry.setFromPoints([start, end]);
498
- line.material.color.setHex(
499
- hasGround ? 65280 : 16711680
500
- );
501
- });
502
- }
503
- disposeDebugLines(uuid) {
504
- const lines = this.debugLines.get(uuid);
505
- if (!lines) return;
506
- for (const line of lines) {
507
- line.removeFromParent();
508
- line.geometry.dispose();
509
- line.material.dispose();
510
- }
511
- this.debugLines.delete(uuid);
512
- }
513
- };
514
- function getGroundAnchorOffsetY(entity) {
515
- const runtimeColliderDesc = entity?.colliderDesc;
516
- if (runtimeColliderDesc) {
517
- const serialized = serializeColliderDesc(runtimeColliderDesc);
518
- const centerY2 = serialized.translation?.[1] ?? 0;
519
- if (serialized.shape === "capsule" && serialized.dimensions.length >= 2) {
520
- const halfCylinder = serialized.dimensions[0] ?? 0;
521
- const radius = serialized.dimensions[1] ?? 0;
522
- return halfCylinder + radius - centerY2;
523
- }
524
- if (serialized.shape === "cuboid" && serialized.dimensions.length >= 2) {
525
- const halfHeight = serialized.dimensions[1] ?? 0;
526
- return halfHeight - centerY2;
527
- }
528
- }
529
- const collisionSize = entity?.options?.collision?.size ?? entity?.options?.collisionSize ?? entity?.options?.size;
530
- const height = collisionSize?.y ?? 0;
531
- if (height <= 0) {
532
- return 0;
533
- }
534
- const collisionPosition = entity?.options?.collision?.position ?? entity?.options?.collisionPosition;
535
- const centerY = collisionPosition?.y ?? height / 2;
536
- return height / 2 - centerY;
537
- }
538
- function getGroundSnapTargetY(entity, support, epsilon = GROUND_SNAP_EPSILON) {
539
- return support.point.y + getGroundAnchorOffsetY(entity) + epsilon;
540
- }
541
-
542
- // src/lib/behaviors/jumper-2d/jumper-2d.descriptor.ts
543
- var defaultOptions = {
544
- jumpHeight: 2.5,
545
- gravity: 20,
546
- maxJumps: 1,
547
- resetJumpsOnGround: true,
548
- coyoteTimeMs: 100,
549
- jumpBufferMs: 80,
550
- groundRayLength: 1,
551
- debugGroundProbe: false
552
- };
553
- var JUMPER_2D_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:jumper-2d");
554
- var JUMPER_2D_OFFSETS = [
555
- { x: 0, z: 0 },
556
- { x: 0.35, z: 0 },
557
- { x: -0.35, z: 0 }
558
- ];
559
- function isJumper2DGrounded(params) {
560
- if (params.velocityY > 0) {
561
- return false;
562
- }
563
- if (params.snapToGroundDistance != null) {
564
- return params.supportToi != null && params.supportToi <= params.snapToGroundDistance;
565
- }
566
- return params.nearGround === true;
567
- }
568
- function shouldSnapJumper2DToGround(support, options, velocityY) {
569
- return support != null && options.snapToGroundDistance != null && velocityY <= 0 && support.toi <= options.snapToGroundDistance;
570
- }
571
- var Jumper2DBehaviorSystem = class {
572
- constructor(world, scene, getBehaviorLinks) {
573
- this.world = world;
574
- this.scene = scene;
575
- this.getBehaviorLinks = getBehaviorLinks;
576
- this.groundProbe = new GroundProbe3D(world);
577
- }
578
- behavior = new Jumper2DBehavior();
579
- groundProbe;
580
- initializedEntities = /* @__PURE__ */ new Set();
581
- timeSinceGroundedMs = /* @__PURE__ */ new Map();
582
- wasJumpHeld = /* @__PURE__ */ new Map();
583
- update(_ecs, delta) {
584
- const links = this.getBehaviorLinks?.(JUMPER_2D_BEHAVIOR_KEY);
585
- if (!links) return;
586
- for (const link of links) {
587
- const gameEntity = link.entity;
588
- const jumperRef = link.ref;
589
- if (!gameEntity.body) continue;
590
- const options = jumperRef.options;
591
- if (!gameEntity.jumper2d) {
592
- gameEntity.jumper2d = createJumpConfig2D(options);
593
- }
594
- if (!gameEntity.$jumper2d) {
595
- gameEntity.$jumper2d = createJumpInput2D();
596
- }
597
- if (!gameEntity.jumper2dState) {
598
- gameEntity.jumper2dState = createJumpState2D();
599
- }
600
- if (!this.initializedEntities.has(gameEntity.uuid)) {
601
- this.initializedEntities.add(gameEntity.uuid);
602
- gameEntity.body.setGravityScale(0, true);
603
- }
604
- if (!jumperRef.fsm && gameEntity.jumper2dState) {
605
- jumperRef.fsm = new Jumper2DFSM({
606
- state: gameEntity.jumper2dState
607
- });
608
- }
609
- const rayLength = options.groundRayLength ?? 1;
610
- const bodyVelocity = gameEntity.body.linvel();
611
- const probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);
612
- const support = this.groundProbe.probeSupport(gameEntity, {
613
- rayLength,
614
- offsets: JUMPER_2D_OFFSETS,
615
- mode: "any",
616
- debug: options.debugGroundProbe ?? false,
617
- scene: this.scene,
618
- originYOffset: probeOriginYOffset
619
- });
620
- const nearGround = support != null;
621
- const isGrounded = isJumper2DGrounded({
622
- nearGround,
623
- velocityY: bodyVelocity.y,
624
- supportToi: support?.toi ?? null,
625
- snapToGroundDistance: options.snapToGroundDistance
626
- });
627
- if (shouldSnapJumper2DToGround(support, options, bodyVelocity.y)) {
628
- const currentPosition = gameEntity.body.translation();
629
- gameEntity.body.setTranslation(
630
- {
631
- x: currentPosition.x,
632
- y: getGroundSnapTargetY(gameEntity, support),
633
- z: currentPosition.z
634
- },
635
- true
636
- );
637
- }
638
- let timeSinceGroundedMs = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;
639
- if (isGrounded) {
640
- timeSinceGroundedMs = 0;
641
- } else {
642
- timeSinceGroundedMs += delta * 1e3;
643
- }
644
- this.timeSinceGroundedMs.set(gameEntity.uuid, timeSinceGroundedMs);
645
- const config = gameEntity.jumper2d;
646
- const input = gameEntity.$jumper2d;
647
- const state = gameEntity.jumper2dState;
648
- const previousHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;
649
- const held = input.jumpHeld === true;
650
- const effectiveInput = {
651
- ...input,
652
- jumpPressed: input.jumpPressed || held && !previousHeld,
653
- jumpReleased: input.jumpReleased || !held && previousHeld
654
- };
655
- const store = gameEntity.transformStore;
656
- const ctx = {
657
- dt: delta,
658
- velocityY: bodyVelocity.y,
659
- isGrounded,
660
- timeSinceGroundedMs,
661
- setVerticalVelocity: (y) => {
662
- setVelocityIntent(
663
- store,
664
- "jumper-2d",
665
- { y },
666
- { mode: "replace", priority: 20 }
667
- );
668
- ctx.velocityY = y;
669
- }
670
- };
671
- const result = this.behavior.tick(config, effectiveInput, ctx, state);
672
- this.wasJumpHeld.set(gameEntity.uuid, held);
673
- if (jumperRef.fsm) {
674
- jumperRef.fsm.applyTickEvent(result.event, isGrounded);
675
- }
676
- }
677
- }
678
- destroy(_ecs) {
679
- this.groundProbe.destroy();
680
- this.initializedEntities.clear();
681
- this.timeSinceGroundedMs.clear();
682
- this.wasJumpHeld.clear();
683
- }
684
- };
685
- var Jumper2D = defineBehavior({
686
- name: "jumper-2d",
687
- defaultOptions,
688
- systemFactory: (ctx) => new Jumper2DBehaviorSystem(ctx.world, ctx.scene, ctx.getBehaviorLinks),
689
- createHandle: (ref) => ({
690
- getState: () => ref.fsm?.getState() ?? "grounded" /* Grounded */,
691
- isJumping: () => ref.fsm?.isJumping() ?? false,
692
- getJumpsUsed: () => ref.fsm?.getJumpsUsed() ?? 0,
693
- getJumpsRemaining: () => {
694
- const maxJumps = ref.options.maxJumps ?? 1;
695
- const used = ref.fsm?.getJumpsUsed() ?? 0;
696
- return maxJumps - used;
697
- }
698
- })
699
- });
700
- export {
701
- Jumper2D,
702
- Jumper2DBehavior,
703
- Jumper2DEvent,
704
- Jumper2DFSM,
705
- Jumper2DState,
706
- Jumper2DTickEvent,
707
- createJumpConfig2D,
708
- createJumpInput2D,
709
- createJumpState2D
710
- };
711
- //# sourceMappingURL=jumper-2d.js.map