@zylem/game-lib 0.6.4 → 0.8.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 (156) hide show
  1. package/README.md +18 -2
  2. package/dist/actions.d.ts +321 -11
  3. package/dist/actions.js +1 -936
  4. package/dist/api/game-lib.api.json +54074 -0
  5. package/dist/api/game-lib.api.md +4544 -0
  6. package/dist/api/game-lib.d.ts +8258 -0
  7. package/dist/api/game-lib.typedoc.json +345421 -0
  8. package/dist/audio.d.ts +13 -0
  9. package/dist/audio.js +1 -0
  10. package/dist/base-node-life-cycle-D2NuN1VB.d.ts +151 -0
  11. package/dist/behavior.d.ts +2 -0
  12. package/dist/behavior.js +1 -0
  13. package/dist/blueprints-TbGY-h53.d.ts +162 -0
  14. package/dist/chunk-4QLJUQSJ.js +1 -0
  15. package/dist/chunk-7FR5JSQ2.js +1 -0
  16. package/dist/chunk-7GYFZKK7.js +1 -0
  17. package/dist/chunk-7WRQ2UAN.js +1 -0
  18. package/dist/chunk-BH53MBAZ.js +1 -0
  19. package/dist/chunk-BIGH6D34.js +0 -0
  20. package/dist/chunk-CM5YRNBJ.js +19 -0
  21. package/dist/chunk-COM6HJ2L.js +1 -0
  22. package/dist/chunk-D2PATZCC.js +1 -0
  23. package/dist/chunk-DFLI7ICU.js +0 -0
  24. package/dist/chunk-E3UBSUPX.js +1 -0
  25. package/dist/chunk-FKIKN7RP.js +24 -0
  26. package/dist/chunk-G4HONLWC.js +1 -0
  27. package/dist/chunk-IKWE2W6L.js +1 -0
  28. package/dist/chunk-IPWUDOV5.js +1 -0
  29. package/dist/chunk-JEHFHUH4.js +0 -0
  30. package/dist/chunk-JNKPTL77.js +1 -0
  31. package/dist/chunk-JQKS42G4.js +1 -0
  32. package/dist/chunk-M3XNO56P.js +1 -0
  33. package/dist/chunk-MSC2BEO5.js +1 -0
  34. package/dist/chunk-ORIDWL3T.js +0 -0
  35. package/dist/chunk-QB3NL7VQ.js +1 -0
  36. package/dist/chunk-QXVH6POE.js +1 -0
  37. package/dist/chunk-RXDTAWI2.js +29 -0
  38. package/dist/chunk-TAUWDQZF.js +9 -0
  39. package/dist/chunk-VS2D4B3W.js +1 -0
  40. package/dist/chunk-WQ3WMMZD.js +1 -0
  41. package/dist/chunk-XK63E4SX.js +1 -0
  42. package/dist/chunk-XNDS4YFR.js +1 -0
  43. package/dist/chunk-XNHVRFAK.js +1 -0
  44. package/dist/chunk-XRP4JJXL.js +1 -0
  45. package/dist/chunk-YHEWKN7N.js +1 -0
  46. package/dist/chunk-ZRT3ZQVH.js +1 -0
  47. package/dist/collision-builder-jF-toPIl.d.ts +38 -0
  48. package/dist/core.d.ts +223 -16
  49. package/dist/core.js +1 -12424
  50. package/dist/debug-state-BPT6jEog.d.ts +17 -0
  51. package/dist/debug.d.ts +76 -0
  52. package/dist/debug.js +1 -0
  53. package/dist/default-controls-0-vCnli7.d.ts +111 -0
  54. package/dist/{entity-vj-HTjzU.d.ts → entity-BdSI8CL3.d.ts} +119 -626
  55. package/dist/{entity-Bq_eNEDI.d.ts → entity-DZbFQ1Wg.d.ts} +4 -4
  56. package/dist/entity-type-map-Bd69SpAS.d.ts +928 -0
  57. package/dist/entity.d.ts +268 -0
  58. package/dist/entity.js +1 -0
  59. package/dist/events.d.ts +181 -0
  60. package/dist/events.js +1 -0
  61. package/dist/game-C1FHVqXl.d.ts +1886 -0
  62. package/dist/game-default-QHROHW2O.js +1 -0
  63. package/dist/game-interfaces-mchNYSZE.d.ts +90 -0
  64. package/dist/globals.d.ts +115 -0
  65. package/dist/globals.js +1 -0
  66. package/dist/graphics.d.ts +53 -0
  67. package/dist/graphics.js +1 -0
  68. package/dist/input-ui.d.ts +35 -0
  69. package/dist/input-ui.js +1 -0
  70. package/dist/input.d.ts +73 -0
  71. package/dist/input.js +1 -0
  72. package/dist/material-9vJ6SZaI.d.ts +126 -0
  73. package/dist/public.d.ts +38 -0
  74. package/dist/public.js +1 -0
  75. package/dist/runtime.d.ts +59 -0
  76. package/dist/runtime.js +1 -0
  77. package/dist/schema/entity.schema.json +244 -0
  78. package/dist/schema/game-config.schema.json +625 -0
  79. package/dist/schema/input-config.schema.json +499 -0
  80. package/dist/schema/stage-config.schema.json +93 -0
  81. package/dist/schema/stage.schema.json +271 -0
  82. package/dist/schema.d.ts +538 -0
  83. package/dist/schema.js +1 -0
  84. package/dist/stage-transition-CmGpV4tc.d.ts +46 -0
  85. package/dist/vector-CiSHbivc.d.ts +133 -0
  86. package/dist/web-components.d.ts +70 -0
  87. package/dist/web-components.js +1 -0
  88. package/dist/zylem-camera-C3bn6BTI.d.ts +575 -0
  89. package/package.json +70 -73
  90. package/dist/actions.js.map +0 -1
  91. package/dist/behavior/jumper-2d.d.ts +0 -114
  92. package/dist/behavior/jumper-2d.js +0 -711
  93. package/dist/behavior/jumper-2d.js.map +0 -1
  94. package/dist/behavior/platformer-3d.d.ts +0 -296
  95. package/dist/behavior/platformer-3d.js +0 -761
  96. package/dist/behavior/platformer-3d.js.map +0 -1
  97. package/dist/behavior/ricochet-2d.d.ts +0 -275
  98. package/dist/behavior/ricochet-2d.js +0 -425
  99. package/dist/behavior/ricochet-2d.js.map +0 -1
  100. package/dist/behavior/ricochet-3d.d.ts +0 -117
  101. package/dist/behavior/ricochet-3d.js +0 -443
  102. package/dist/behavior/ricochet-3d.js.map +0 -1
  103. package/dist/behavior/screen-visibility.d.ts +0 -79
  104. package/dist/behavior/screen-visibility.js +0 -358
  105. package/dist/behavior/screen-visibility.js.map +0 -1
  106. package/dist/behavior/screen-wrap.d.ts +0 -87
  107. package/dist/behavior/screen-wrap.js +0 -246
  108. package/dist/behavior/screen-wrap.js.map +0 -1
  109. package/dist/behavior/shooter-2d.d.ts +0 -79
  110. package/dist/behavior/shooter-2d.js +0 -180
  111. package/dist/behavior/shooter-2d.js.map +0 -1
  112. package/dist/behavior/thruster.d.ts +0 -11
  113. package/dist/behavior/thruster.js +0 -292
  114. package/dist/behavior/thruster.js.map +0 -1
  115. package/dist/behavior/top-down-movement.d.ts +0 -56
  116. package/dist/behavior/top-down-movement.js +0 -125
  117. package/dist/behavior/top-down-movement.js.map +0 -1
  118. package/dist/behavior/world-boundary-2d.d.ts +0 -142
  119. package/dist/behavior/world-boundary-2d.js +0 -235
  120. package/dist/behavior/world-boundary-2d.js.map +0 -1
  121. package/dist/behavior/world-boundary-3d.d.ts +0 -76
  122. package/dist/behavior/world-boundary-3d.js +0 -274
  123. package/dist/behavior/world-boundary-3d.js.map +0 -1
  124. package/dist/behavior-descriptor-BXnVR8Ki.d.ts +0 -159
  125. package/dist/blueprints-DmbK2dki.d.ts +0 -26
  126. package/dist/camera-4XO5gbQH.d.ts +0 -905
  127. package/dist/camera.d.ts +0 -6
  128. package/dist/camera.js +0 -1993
  129. package/dist/camera.js.map +0 -1
  130. package/dist/composition-BASvMKrW.d.ts +0 -218
  131. package/dist/core-CARRaS55.d.ts +0 -541
  132. package/dist/core.js.map +0 -1
  133. package/dist/entities-ChFirVL9.d.ts +0 -410
  134. package/dist/entities.d.ts +0 -9
  135. package/dist/entities.js +0 -4986
  136. package/dist/entities.js.map +0 -1
  137. package/dist/entity-types-DAu8sGJH.d.ts +0 -26
  138. package/dist/global-change-2JvMaz44.d.ts +0 -25
  139. package/dist/main.d.ts +0 -1353
  140. package/dist/main.js +0 -19525
  141. package/dist/main.js.map +0 -1
  142. package/dist/physics-pose-DCc4oE44.d.ts +0 -25
  143. package/dist/physics-protocol-BDD3P5W2.d.ts +0 -200
  144. package/dist/physics-worker.d.ts +0 -21
  145. package/dist/physics-worker.js +0 -306
  146. package/dist/physics-worker.js.map +0 -1
  147. package/dist/physics.d.ts +0 -205
  148. package/dist/physics.js +0 -577
  149. package/dist/physics.js.map +0 -1
  150. package/dist/stage-types-C19IhuzA.d.ts +0 -731
  151. package/dist/stage.d.ts +0 -52
  152. package/dist/stage.js +0 -8479
  153. package/dist/stage.js.map +0 -1
  154. package/dist/sync-state-machine-CZyspBpj.d.ts +0 -16
  155. package/dist/thruster-23lzoPZd.d.ts +0 -180
  156. package/dist/world-DfgxoNMt.d.ts +0 -105
@@ -1,761 +0,0 @@
1
- // src/lib/behaviors/platformer-3d/components.ts
2
- function createPlatformer3DMovementComponent(options = {}) {
3
- return {
4
- walkSpeed: options.walkSpeed ?? 12,
5
- runSpeed: options.runSpeed ?? 24,
6
- jumpForce: options.jumpForce ?? 12,
7
- maxJumps: options.maxJumps ?? 1,
8
- gravity: options.gravity ?? 9.82,
9
- groundRayLength: options.groundRayLength ?? 1,
10
- coyoteTime: options.coyoteTime ?? 0.1,
11
- jumpBufferTime: options.jumpBufferTime ?? 0.1,
12
- jumpCutMultiplier: options.jumpCutMultiplier ?? 0.5,
13
- multiJumpWindowTime: options.multiJumpWindowTime ?? 0.15,
14
- // 150ms default
15
- debugGroundProbe: options.debugGroundProbe ?? false
16
- };
17
- }
18
- function createPlatformer3DInputComponent() {
19
- return {
20
- moveX: 0,
21
- moveZ: 0,
22
- jump: false,
23
- run: false
24
- };
25
- }
26
- function createPlatformer3DStateComponent() {
27
- return {
28
- grounded: false,
29
- jumping: false,
30
- falling: false,
31
- jumpCount: 0,
32
- jumpStartHeight: 0,
33
- currentSpeed: 0,
34
- lastGroundedY: 0,
35
- jumpPressedLastFrame: false,
36
- collisionGrounded: false,
37
- groundedCollisionTime: 0,
38
- timeSinceGrounded: 0,
39
- jumpBuffered: false,
40
- jumpBufferTimer: 0,
41
- jumpHeld: false,
42
- jumpCutApplied: false,
43
- jumpReleasedSinceLastJump: true,
44
- timeSinceJump: 0
45
- };
46
- }
47
-
48
- // src/lib/core/utility/sync-state-machine.ts
49
- import {
50
- StateMachine as BaseStateMachine
51
- } from "typescript-fsm";
52
- import { t } from "typescript-fsm";
53
- var SyncStateMachine = class extends BaseStateMachine {
54
- constructor(init, transitions = [], logger = console) {
55
- super(init, transitions, logger);
56
- }
57
- dispatch(_event, ..._args) {
58
- throw new Error("SyncStateMachine does not support async dispatch.");
59
- }
60
- syncDispatch(event, ...args) {
61
- const found = this.transitions.some((transition) => {
62
- if (transition.fromState !== this._current || transition.event !== event) {
63
- return false;
64
- }
65
- const current = this._current;
66
- this._current = transition.toState;
67
- if (!transition.cb) {
68
- return true;
69
- }
70
- try {
71
- transition.cb(...args);
72
- return true;
73
- } catch (error) {
74
- this._current = current;
75
- this.logger.error("Exception in callback", error);
76
- throw error;
77
- }
78
- });
79
- if (!found) {
80
- const errorMessage = this.formatErr(this._current, event);
81
- this.logger.error(errorMessage);
82
- }
83
- return found;
84
- }
85
- };
86
-
87
- // src/lib/behaviors/platformer-3d/platformer-3d-fsm.ts
88
- var Platformer3DState = /* @__PURE__ */ ((Platformer3DState2) => {
89
- Platformer3DState2["Idle"] = "idle";
90
- Platformer3DState2["Walking"] = "walking";
91
- Platformer3DState2["Running"] = "running";
92
- Platformer3DState2["Jumping"] = "jumping";
93
- Platformer3DState2["Falling"] = "falling";
94
- Platformer3DState2["Landing"] = "landing";
95
- return Platformer3DState2;
96
- })(Platformer3DState || {});
97
- var Platformer3DEvent = /* @__PURE__ */ ((Platformer3DEvent2) => {
98
- Platformer3DEvent2["Walk"] = "walk";
99
- Platformer3DEvent2["Run"] = "run";
100
- Platformer3DEvent2["Jump"] = "jump";
101
- Platformer3DEvent2["Fall"] = "fall";
102
- Platformer3DEvent2["Land"] = "land";
103
- Platformer3DEvent2["Stop"] = "stop";
104
- return Platformer3DEvent2;
105
- })(Platformer3DEvent || {});
106
- var Platformer3DFSM = class {
107
- constructor(ctx) {
108
- this.ctx = ctx;
109
- this.machine = new SyncStateMachine(
110
- "idle" /* Idle */,
111
- [
112
- // Idle transitions
113
- t("idle" /* Idle */, "walk" /* Walk */, "walking" /* Walking */),
114
- t("idle" /* Idle */, "run" /* Run */, "running" /* Running */),
115
- t("idle" /* Idle */, "jump" /* Jump */, "jumping" /* Jumping */),
116
- t("idle" /* Idle */, "fall" /* Fall */, "falling" /* Falling */),
117
- // Walking transitions
118
- t("walking" /* Walking */, "run" /* Run */, "running" /* Running */),
119
- t("walking" /* Walking */, "jump" /* Jump */, "jumping" /* Jumping */),
120
- t("walking" /* Walking */, "stop" /* Stop */, "idle" /* Idle */),
121
- t("walking" /* Walking */, "fall" /* Fall */, "falling" /* Falling */),
122
- // Running transitions
123
- t("running" /* Running */, "walk" /* Walk */, "walking" /* Walking */),
124
- t("running" /* Running */, "jump" /* Jump */, "jumping" /* Jumping */),
125
- t("running" /* Running */, "stop" /* Stop */, "idle" /* Idle */),
126
- t("running" /* Running */, "fall" /* Fall */, "falling" /* Falling */),
127
- // Jumping transitions
128
- t("jumping" /* Jumping */, "fall" /* Fall */, "falling" /* Falling */),
129
- t("jumping" /* Jumping */, "land" /* Land */, "landing" /* Landing */),
130
- t("jumping" /* Jumping */, "jump" /* Jump */, "jumping" /* Jumping */),
131
- // Multi-jump
132
- // Falling transitions
133
- t("falling" /* Falling */, "land" /* Land */, "landing" /* Landing */),
134
- // Landing transitions
135
- t("landing" /* Landing */, "walk" /* Walk */, "walking" /* Walking */),
136
- t("landing" /* Landing */, "run" /* Run */, "running" /* Running */),
137
- t("landing" /* Landing */, "stop" /* Stop */, "idle" /* Idle */),
138
- // Self-transitions (no-ops)
139
- t("idle" /* Idle */, "stop" /* Stop */, "idle" /* Idle */)
140
- ]
141
- );
142
- }
143
- machine;
144
- /**
145
- * Get the current state
146
- */
147
- getState() {
148
- return this.machine.getState();
149
- }
150
- /**
151
- * Dispatch an event to the FSM
152
- */
153
- dispatch(event) {
154
- if (this.machine.can(event)) {
155
- this.machine.syncDispatch(event);
156
- }
157
- }
158
- /**
159
- * Check if grounded
160
- */
161
- isGrounded() {
162
- const state = this.getState();
163
- return state === "idle" /* Idle */ || state === "walking" /* Walking */ || state === "running" /* Running */ || state === "landing" /* Landing */;
164
- }
165
- /**
166
- * Get current jump count from context
167
- */
168
- getJumpCount() {
169
- return this.ctx.state.jumpCount;
170
- }
171
- /**
172
- * Handle collision event to update ground state
173
- */
174
- handleCollision(ctx) {
175
- if (ctx.contact.normal.y > 0.5) {
176
- this.ctx.state.collisionGrounded = true;
177
- this.ctx.state.groundedCollisionTime = performance.now();
178
- }
179
- }
180
- /**
181
- * Update FSM based on current state
182
- */
183
- update(input, state) {
184
- this.ctx.input = input;
185
- this.ctx.state = state;
186
- const currentState = this.getState();
187
- const hasInput = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;
188
- const isRunning = input.run;
189
- if (currentState === "falling" /* Falling */ && state.grounded) {
190
- this.dispatch("land" /* Land */);
191
- }
192
- if (state.grounded) {
193
- if (hasInput) {
194
- if (isRunning) {
195
- this.dispatch("run" /* Run */);
196
- } else {
197
- this.dispatch("walk" /* Walk */);
198
- }
199
- } else {
200
- this.dispatch("stop" /* Stop */);
201
- }
202
- } else {
203
- if (state.falling) {
204
- this.dispatch("fall" /* Fall */);
205
- }
206
- }
207
- if (input.jump && !state.jumpPressedLastFrame) {
208
- this.dispatch("jump" /* Jump */);
209
- }
210
- }
211
- };
212
-
213
- // src/lib/behaviors/shared/ground-probe-3d.ts
214
- import { Ray } from "@dimforge/rapier3d-compat";
215
- import { BufferGeometry, Line, LineBasicMaterial, Vector3 } from "three";
216
-
217
- // src/lib/physics/serialize-descriptors.ts
218
- import { RigidBodyType } from "@dimforge/rapier3d-compat";
219
- function serializeColliderDesc(desc) {
220
- const internal = desc;
221
- const customShapeData = internal.__zylemShapeData;
222
- if (customShapeData?.shape === "trimesh") {
223
- const result2 = {
224
- shape: "trimesh",
225
- dimensions: [],
226
- vertices: [...customShapeData.vertices],
227
- indices: [...customShapeData.indices]
228
- };
229
- const translation = internal.translation;
230
- if (translation && (translation.x !== 0 || translation.y !== 0 || translation.z !== 0)) {
231
- result2.translation = [translation.x, translation.y, translation.z];
232
- }
233
- if (internal.isSensor) {
234
- result2.sensor = true;
235
- }
236
- if (internal.collisionGroups !== void 0 && internal.collisionGroups !== 4294967295) {
237
- result2.collisionGroups = internal.collisionGroups;
238
- }
239
- if (internal.activeCollisionTypes !== void 0) {
240
- result2.activeCollisionTypes = internal.activeCollisionTypes;
241
- }
242
- return result2;
243
- }
244
- const shapeType = internal.shape?.type ?? internal.shapeType ?? 0;
245
- const { shape, dimensions, heightfieldMeta } = extractShapeData(shapeType, internal);
246
- const result = {
247
- shape,
248
- dimensions
249
- };
250
- const t2 = internal.translation;
251
- if (t2 && (t2.x !== 0 || t2.y !== 0 || t2.z !== 0)) {
252
- result.translation = [t2.x, t2.y, t2.z];
253
- }
254
- if (internal.isSensor) {
255
- result.sensor = true;
256
- }
257
- if (internal.collisionGroups !== void 0 && internal.collisionGroups !== 4294967295) {
258
- result.collisionGroups = internal.collisionGroups;
259
- }
260
- if (internal.activeCollisionTypes !== void 0) {
261
- result.activeCollisionTypes = internal.activeCollisionTypes;
262
- }
263
- if (heightfieldMeta) {
264
- result.heightfieldMeta = heightfieldMeta;
265
- }
266
- return result;
267
- }
268
- function extractShapeData(shapeType, internal) {
269
- switch (shapeType) {
270
- case 0:
271
- return {
272
- shape: "ball",
273
- dimensions: [internal.shape?.radius ?? internal.halfExtents?.x ?? 1]
274
- };
275
- case 1:
276
- return {
277
- shape: "cuboid",
278
- dimensions: [
279
- internal.shape?.halfExtents?.x ?? internal.halfExtents?.x ?? 0.5,
280
- internal.shape?.halfExtents?.y ?? internal.halfExtents?.y ?? 0.5,
281
- internal.shape?.halfExtents?.z ?? internal.halfExtents?.z ?? 0.5
282
- ]
283
- };
284
- case 2:
285
- return {
286
- shape: "capsule",
287
- dimensions: [
288
- internal.shape?.halfHeight ?? 0.5,
289
- internal.shape?.radius ?? 0.5
290
- ]
291
- };
292
- case 6:
293
- return {
294
- shape: "cone",
295
- dimensions: [
296
- internal.shape?.halfHeight ?? 1,
297
- internal.shape?.radius ?? 1
298
- ]
299
- };
300
- case 7:
301
- return {
302
- shape: "cylinder",
303
- dimensions: [
304
- internal.shape?.halfHeight ?? 1,
305
- internal.shape?.radius ?? 1
306
- ]
307
- };
308
- case 11: {
309
- const nrows = internal.shape?.nrows ?? 10;
310
- const ncols = internal.shape?.ncols ?? 10;
311
- const heights = internal.shape?.heights;
312
- return {
313
- shape: "heightfield",
314
- dimensions: heights ? Array.from(heights) : [],
315
- heightfieldMeta: { nrows, ncols }
316
- };
317
- }
318
- default:
319
- return { shape: "cuboid", dimensions: [0.5, 0.5, 0.5] };
320
- }
321
- }
322
-
323
- // src/lib/behaviors/shared/ground-probe-3d.ts
324
- var DEFAULT_OFFSETS = [
325
- { x: 0, z: 0 },
326
- { x: 0.4, z: 0.4 },
327
- { x: -0.4, z: 0.4 },
328
- { x: 0.4, z: -0.4 },
329
- { x: -0.4, z: -0.4 }
330
- ];
331
- var GroundProbe3D = class {
332
- constructor(world) {
333
- this.world = world;
334
- }
335
- rays = /* @__PURE__ */ new Map();
336
- debugLines = /* @__PURE__ */ new Map();
337
- probeSupport(entity, options) {
338
- if (!this.world?.world || !entity.body) return null;
339
- const mode = options.mode ?? "any";
340
- const offsets = mode === "center" ? (options.offsets ?? DEFAULT_OFFSETS).slice(0, 1) : options.offsets ?? DEFAULT_OFFSETS;
341
- const translation = entity.body.translation();
342
- const rays = this.getOrCreateRays(entity.uuid, offsets.length);
343
- const originYOffset = options.originYOffset ?? 0;
344
- let support = null;
345
- for (let index = 0; index < offsets.length; index++) {
346
- const offset = offsets[index];
347
- const ray = rays[index];
348
- ray.origin = {
349
- x: translation.x + offset.x,
350
- y: translation.y + originYOffset,
351
- z: translation.z + offset.z
352
- };
353
- ray.dir = { x: 0, y: -1, z: 0 };
354
- const hit = this.world.world.castRay(
355
- ray,
356
- options.rayLength,
357
- true,
358
- void 0,
359
- void 0,
360
- void 0,
361
- entity.body
362
- );
363
- if (!hit) continue;
364
- const nextSupport = {
365
- toi: hit.toi,
366
- point: {
367
- x: ray.origin.x + ray.dir.x * hit.toi,
368
- y: ray.origin.y + ray.dir.y * hit.toi,
369
- z: ray.origin.z + ray.dir.z * hit.toi
370
- },
371
- origin: {
372
- x: ray.origin.x,
373
- y: ray.origin.y,
374
- z: ray.origin.z
375
- },
376
- rayIndex: index,
377
- colliderUuid: hit.collider?._parent?.userData?.uuid
378
- };
379
- if (mode === "center") {
380
- support = nextSupport;
381
- break;
382
- }
383
- if (!support || nextSupport.toi < support.toi) {
384
- support = nextSupport;
385
- }
386
- }
387
- if (options.debug && options.scene) {
388
- this.updateDebugLines(
389
- entity.uuid,
390
- rays,
391
- Boolean(support),
392
- options.rayLength,
393
- options.scene
394
- );
395
- } else {
396
- this.disposeDebugLines(entity.uuid);
397
- }
398
- return support;
399
- }
400
- detect(entity, options) {
401
- return this.probeSupport(entity, options) != null;
402
- }
403
- destroyEntity(uuid) {
404
- this.rays.delete(uuid);
405
- this.disposeDebugLines(uuid);
406
- }
407
- destroy() {
408
- this.rays.clear();
409
- for (const uuid of this.debugLines.keys()) {
410
- this.disposeDebugLines(uuid);
411
- }
412
- this.debugLines.clear();
413
- }
414
- getOrCreateRays(uuid, count) {
415
- let rays = this.rays.get(uuid);
416
- if (!rays || rays.length !== count) {
417
- rays = Array.from(
418
- { length: count },
419
- () => new Ray({ x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 })
420
- );
421
- this.rays.set(uuid, rays);
422
- }
423
- return rays;
424
- }
425
- updateDebugLines(uuid, rays, hasGround, length, scene) {
426
- let lines = this.debugLines.get(uuid);
427
- if (!lines) {
428
- lines = rays.map(() => {
429
- const geometry = new BufferGeometry().setFromPoints([
430
- new Vector3(),
431
- new Vector3()
432
- ]);
433
- const material = new LineBasicMaterial({ color: 16711680 });
434
- const line = new Line(geometry, material);
435
- scene.add(line);
436
- return line;
437
- });
438
- this.debugLines.set(uuid, lines);
439
- }
440
- rays.forEach((ray, index) => {
441
- const line = lines[index];
442
- const start = new Vector3(ray.origin.x, ray.origin.y, ray.origin.z);
443
- const end = new Vector3(
444
- ray.origin.x + ray.dir.x * length,
445
- ray.origin.y + ray.dir.y * length,
446
- ray.origin.z + ray.dir.z * length
447
- );
448
- line.visible = true;
449
- line.geometry.setFromPoints([start, end]);
450
- line.material.color.setHex(
451
- hasGround ? 65280 : 16711680
452
- );
453
- });
454
- }
455
- disposeDebugLines(uuid) {
456
- const lines = this.debugLines.get(uuid);
457
- if (!lines) return;
458
- for (const line of lines) {
459
- line.removeFromParent();
460
- line.geometry.dispose();
461
- line.material.dispose();
462
- }
463
- this.debugLines.delete(uuid);
464
- }
465
- };
466
- function getGroundAnchorOffsetY(entity) {
467
- const runtimeColliderDesc = entity?.colliderDesc;
468
- if (runtimeColliderDesc) {
469
- const serialized = serializeColliderDesc(runtimeColliderDesc);
470
- const centerY2 = serialized.translation?.[1] ?? 0;
471
- if (serialized.shape === "capsule" && serialized.dimensions.length >= 2) {
472
- const halfCylinder = serialized.dimensions[0] ?? 0;
473
- const radius = serialized.dimensions[1] ?? 0;
474
- return halfCylinder + radius - centerY2;
475
- }
476
- if (serialized.shape === "cuboid" && serialized.dimensions.length >= 2) {
477
- const halfHeight = serialized.dimensions[1] ?? 0;
478
- return halfHeight - centerY2;
479
- }
480
- }
481
- const collisionSize = entity?.options?.collision?.size ?? entity?.options?.collisionSize ?? entity?.options?.size;
482
- const height = collisionSize?.y ?? 0;
483
- if (height <= 0) {
484
- return 0;
485
- }
486
- const collisionPosition = entity?.options?.collision?.position ?? entity?.options?.collisionPosition;
487
- const centerY = collisionPosition?.y ?? height / 2;
488
- return height / 2 - centerY;
489
- }
490
-
491
- // src/lib/behaviors/platformer-3d/platformer-3d.behavior.ts
492
- var Platformer3DBehavior = class {
493
- world;
494
- scene;
495
- groundProbe;
496
- constructor(world, scene) {
497
- this.world = world;
498
- this.scene = scene;
499
- this.groundProbe = new GroundProbe3D(world);
500
- }
501
- /**
502
- * Apply horizontal movement based on input
503
- */
504
- applyMovement(entity, delta) {
505
- const input = entity.$platformer;
506
- const movement = entity.platformer;
507
- const state = entity.platformerState;
508
- const speed = input.run ? movement.runSpeed : movement.walkSpeed;
509
- state.currentSpeed = speed;
510
- const moveX = input.moveX * speed;
511
- const moveZ = input.moveZ * speed;
512
- const currentVel = entity.body.linvel();
513
- entity.transformStore.velocity.x = moveX;
514
- entity.transformStore.velocity.y = currentVel.y;
515
- entity.transformStore.velocity.z = moveZ;
516
- entity.transformStore.dirty.velocity = true;
517
- }
518
- /**
519
- * Handle jump logic with multi-jump support
520
- */
521
- /**
522
- * Handle jump logic with multi-jump, coyote time, and buffering
523
- */
524
- handleJump(entity, delta) {
525
- const input = entity.$platformer;
526
- const movement = entity.platformer;
527
- const state = entity.platformerState;
528
- if (state.jumping || state.falling) {
529
- state.timeSinceJump += delta;
530
- }
531
- if (!input.jump && state.jumpHeld) {
532
- state.jumpReleasedSinceLastJump = true;
533
- }
534
- if (input.jump && !state.jumpPressedLastFrame) {
535
- state.jumpBuffered = true;
536
- state.jumpBufferTimer = movement.jumpBufferTime;
537
- }
538
- state.jumpPressedLastFrame = input.jump;
539
- state.jumpHeld = input.jump;
540
- if (state.jumpBuffered) {
541
- state.jumpBufferTimer -= delta;
542
- if (state.jumpBufferTimer <= 0) {
543
- state.jumpBuffered = false;
544
- }
545
- }
546
- const minTimeBeforeCut = 0.1;
547
- const canApplyCut = state.timeSinceJump >= minTimeBeforeCut;
548
- if (!input.jump && state.jumping && !state.jumpCutApplied && canApplyCut) {
549
- const velocity = entity.body.linvel();
550
- entity.transformStore.velocity.y = velocity.y * movement.jumpCutMultiplier;
551
- entity.transformStore.dirty.velocity = true;
552
- state.jumpCutApplied = true;
553
- }
554
- if (!state.jumpBuffered) return;
555
- const inCoyoteWindow = !state.grounded && state.timeSinceGrounded <= movement.coyoteTime;
556
- const isFirstJump = state.grounded || inCoyoteWindow && state.jumpCount === 0;
557
- const hasJumpsRemaining = state.jumpCount < movement.maxJumps;
558
- const buttonReleased = state.jumpReleasedSinceLastJump;
559
- const inMultiJumpWindow = state.timeSinceJump >= movement.multiJumpWindowTime;
560
- const canMultiJump = !state.grounded && hasJumpsRemaining && buttonReleased && inMultiJumpWindow;
561
- if (isFirstJump || canMultiJump) {
562
- state.jumpBuffered = false;
563
- state.jumpCount++;
564
- state.jumpReleasedSinceLastJump = false;
565
- state.timeSinceJump = 0;
566
- state.jumpStartHeight = entity.body.translation().y;
567
- state.jumping = true;
568
- state.falling = false;
569
- state.jumpCutApplied = false;
570
- entity.transformStore.velocity.y = movement.jumpForce;
571
- entity.transformStore.dirty.velocity = true;
572
- }
573
- }
574
- /**
575
- * Apply gravity when not grounded
576
- */
577
- applyGravity(entity, delta) {
578
- const movement = entity.platformer;
579
- const state = entity.platformerState;
580
- if (state.grounded) return;
581
- if (state.jumping && state.timeSinceJump < 0.01) {
582
- return;
583
- }
584
- const currentVel = entity.body.linvel();
585
- const newYVelocity = currentVel.y - movement.gravity * delta;
586
- entity.transformStore.velocity.y = newYVelocity;
587
- entity.transformStore.dirty.velocity = true;
588
- }
589
- /**
590
- * Update entity state based on physics
591
- */
592
- updateState(entity, delta) {
593
- const state = entity.platformerState;
594
- const wasGrounded = state.grounded;
595
- const velocity = entity.body.linvel();
596
- let isGrounded = false;
597
- const isAirborne = state.jumping || state.falling;
598
- if (isAirborne) {
599
- const probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(entity);
600
- const nearGround = this.groundProbe.detect(entity, {
601
- rayLength: entity.platformer.groundRayLength,
602
- mode: "any",
603
- debug: entity.platformer.debugGroundProbe,
604
- scene: this.scene,
605
- originYOffset: probeOriginYOffset
606
- });
607
- const canLand = state.falling && !state.jumping;
608
- const hasLanded = Math.abs(velocity.y) < 0.5;
609
- isGrounded = nearGround && canLand && hasLanded;
610
- } else {
611
- const probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(entity);
612
- const nearGround = this.groundProbe.detect(entity, {
613
- rayLength: entity.platformer.groundRayLength,
614
- mode: "any",
615
- debug: entity.platformer.debugGroundProbe,
616
- scene: this.scene,
617
- originYOffset: probeOriginYOffset
618
- });
619
- const notFallingFast = velocity.y > -2;
620
- isGrounded = nearGround && notFallingFast;
621
- }
622
- state.grounded = isGrounded;
623
- if (state.grounded) {
624
- state.timeSinceGrounded = 0;
625
- state.lastGroundedY = entity.body.translation().y;
626
- } else {
627
- state.timeSinceGrounded += delta;
628
- }
629
- if (!wasGrounded && state.grounded) {
630
- state.jumpCount = 0;
631
- state.jumping = false;
632
- state.falling = false;
633
- state.jumpCutApplied = false;
634
- }
635
- if (velocity.y < -0.1 && !state.grounded) {
636
- if (state.jumping && velocity.y < 0) {
637
- state.jumping = false;
638
- state.falling = true;
639
- } else if (!state.jumping) {
640
- state.falling = true;
641
- }
642
- }
643
- }
644
- /**
645
- * Update one platformer entity.
646
- */
647
- updateEntity(entity, delta) {
648
- if (!entity.platformer || !entity.$platformer || !entity.platformerState) {
649
- return;
650
- }
651
- const platformerEntity = entity;
652
- this.updateState(platformerEntity, delta);
653
- this.applyMovement(platformerEntity, delta);
654
- this.handleJump(platformerEntity, delta);
655
- this.applyGravity(platformerEntity, delta);
656
- }
657
- /**
658
- * Update all platformer entities.
659
- */
660
- update(delta) {
661
- if (!this.world?.collisionMap) return;
662
- for (const [, entity] of this.world.collisionMap) {
663
- this.updateEntity(entity, delta);
664
- }
665
- }
666
- /**
667
- * Cleanup
668
- */
669
- destroy() {
670
- this.groundProbe.destroy();
671
- }
672
- };
673
-
674
- // src/lib/behaviors/behavior-descriptor.ts
675
- function defineBehavior(config) {
676
- return {
677
- key: /* @__PURE__ */ Symbol.for(`zylem:behavior:${config.name}`),
678
- defaultOptions: config.defaultOptions,
679
- systemFactory: config.systemFactory,
680
- createHandle: config.createHandle
681
- };
682
- }
683
-
684
- // src/lib/behaviors/platformer-3d/platformer-3d.descriptor.ts
685
- var defaultOptions = {
686
- walkSpeed: 12,
687
- runSpeed: 24,
688
- jumpForce: 12,
689
- maxJumps: 1,
690
- gravity: 9.82,
691
- groundRayLength: 1,
692
- debugGroundProbe: false
693
- };
694
- var PLATFORMER_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:platformer-3d");
695
- var Platformer3DBehaviorSystem = class {
696
- constructor(world, scene, getBehaviorLinks) {
697
- this.world = world;
698
- this.scene = scene;
699
- this.getBehaviorLinks = getBehaviorLinks;
700
- this.movementBehavior = new Platformer3DBehavior(world, scene);
701
- }
702
- movementBehavior;
703
- update(_ecs, delta) {
704
- const links = this.getBehaviorLinks?.(PLATFORMER_BEHAVIOR_KEY);
705
- if (!links) return;
706
- for (const link of links) {
707
- const gameEntity = link.entity;
708
- const platformerRef = link.ref;
709
- if (!gameEntity.body) continue;
710
- const options = platformerRef.options;
711
- if (!gameEntity.platformer) {
712
- gameEntity.platformer = createPlatformer3DMovementComponent(options);
713
- }
714
- if (!gameEntity.$platformer) {
715
- gameEntity.$platformer = createPlatformer3DInputComponent();
716
- }
717
- if (!gameEntity.platformerState) {
718
- gameEntity.platformerState = createPlatformer3DStateComponent();
719
- }
720
- if (!platformerRef.fsm && gameEntity.$platformer && gameEntity.platformerState) {
721
- platformerRef.fsm = new Platformer3DFSM({
722
- input: gameEntity.$platformer,
723
- state: gameEntity.platformerState
724
- });
725
- }
726
- if (platformerRef.fsm && gameEntity.$platformer && gameEntity.platformerState) {
727
- platformerRef.fsm.update(gameEntity.$platformer, gameEntity.platformerState);
728
- }
729
- this.movementBehavior.updateEntity(gameEntity, delta);
730
- }
731
- }
732
- destroy(_ecs) {
733
- this.movementBehavior.destroy();
734
- }
735
- };
736
- var Platformer3DBehavior2 = defineBehavior({
737
- name: "platformer-3d",
738
- defaultOptions,
739
- systemFactory: (ctx) => new Platformer3DBehaviorSystem(
740
- ctx.world,
741
- ctx.scene,
742
- ctx.getBehaviorLinks
743
- ),
744
- createHandle: (ref) => ({
745
- getState: () => ref.fsm?.getState() ?? "idle" /* Idle */,
746
- isGrounded: () => ref.fsm?.isGrounded() ?? false,
747
- getJumpCount: () => ref.fsm?.getJumpCount() ?? 0,
748
- onPlatformCollision: (ctx) => ref.fsm?.handleCollision(ctx)
749
- })
750
- });
751
- export {
752
- Platformer3DBehavior2 as Platformer3DBehavior,
753
- Platformer3DEvent,
754
- Platformer3DFSM,
755
- Platformer3DBehavior as Platformer3DMovementBehavior,
756
- Platformer3DState,
757
- createPlatformer3DInputComponent,
758
- createPlatformer3DMovementComponent,
759
- createPlatformer3DStateComponent
760
- };
761
- //# sourceMappingURL=platformer-3d.js.map