@zylem/behaviors 0.2.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 (175) hide show
  1. package/README.md +26 -0
  2. package/dist/behavior-system-DYbx-x_-.d.ts +307 -0
  3. package/dist/chunk-2C3Z5GE7.js +176 -0
  4. package/dist/chunk-2C3Z5GE7.js.map +1 -0
  5. package/dist/chunk-2CLT36VB.js +241 -0
  6. package/dist/chunk-2CLT36VB.js.map +1 -0
  7. package/dist/chunk-3PYGRHAL.js +35 -0
  8. package/dist/chunk-3PYGRHAL.js.map +1 -0
  9. package/dist/chunk-4I6E6DGV.js +212 -0
  10. package/dist/chunk-4I6E6DGV.js.map +1 -0
  11. package/dist/chunk-4URF65BR.js +44 -0
  12. package/dist/chunk-4URF65BR.js.map +1 -0
  13. package/dist/chunk-6C6NXNEW.js +38 -0
  14. package/dist/chunk-6C6NXNEW.js.map +1 -0
  15. package/dist/chunk-ARJWUNRE.js +431 -0
  16. package/dist/chunk-ARJWUNRE.js.map +1 -0
  17. package/dist/chunk-BXP4K7RF.js +1205 -0
  18. package/dist/chunk-BXP4K7RF.js.map +1 -0
  19. package/dist/chunk-DYLH6K7B.js +44 -0
  20. package/dist/chunk-DYLH6K7B.js.map +1 -0
  21. package/dist/chunk-EIWQM6U3.js +27 -0
  22. package/dist/chunk-EIWQM6U3.js.map +1 -0
  23. package/dist/chunk-EZNCCO4L.js +14 -0
  24. package/dist/chunk-EZNCCO4L.js.map +1 -0
  25. package/dist/chunk-F3KRX2V4.js +457 -0
  26. package/dist/chunk-F3KRX2V4.js.map +1 -0
  27. package/dist/chunk-FPTWVCPN.js +53 -0
  28. package/dist/chunk-FPTWVCPN.js.map +1 -0
  29. package/dist/chunk-GCNRXAKH.js +37 -0
  30. package/dist/chunk-GCNRXAKH.js.map +1 -0
  31. package/dist/chunk-GYURWCIQ.js +1985 -0
  32. package/dist/chunk-GYURWCIQ.js.map +1 -0
  33. package/dist/chunk-HZMY3TT4.js +244 -0
  34. package/dist/chunk-HZMY3TT4.js.map +1 -0
  35. package/dist/chunk-ID5QJYF5.js +50 -0
  36. package/dist/chunk-ID5QJYF5.js.map +1 -0
  37. package/dist/chunk-JAN34G6S.js +552 -0
  38. package/dist/chunk-JAN34G6S.js.map +1 -0
  39. package/dist/chunk-K3UNLQ7W.js +118 -0
  40. package/dist/chunk-K3UNLQ7W.js.map +1 -0
  41. package/dist/chunk-KDY5N6J4.js +82 -0
  42. package/dist/chunk-KDY5N6J4.js.map +1 -0
  43. package/dist/chunk-KOZUNIIE.js +413 -0
  44. package/dist/chunk-KOZUNIIE.js.map +1 -0
  45. package/dist/chunk-KS72RZHX.js +30 -0
  46. package/dist/chunk-KS72RZHX.js.map +1 -0
  47. package/dist/chunk-LD5SMIB3.js +32 -0
  48. package/dist/chunk-LD5SMIB3.js.map +1 -0
  49. package/dist/chunk-OHCPV2NT.js +86 -0
  50. package/dist/chunk-OHCPV2NT.js.map +1 -0
  51. package/dist/chunk-OYWFPIHF.js +115 -0
  52. package/dist/chunk-OYWFPIHF.js.map +1 -0
  53. package/dist/chunk-POZER3MQ.js +407 -0
  54. package/dist/chunk-POZER3MQ.js.map +1 -0
  55. package/dist/chunk-RTRVBEIB.js +56 -0
  56. package/dist/chunk-RTRVBEIB.js.map +1 -0
  57. package/dist/chunk-RTVRUNYR.js +29 -0
  58. package/dist/chunk-RTVRUNYR.js.map +1 -0
  59. package/dist/chunk-SS7ELMJ7.js +406 -0
  60. package/dist/chunk-SS7ELMJ7.js.map +1 -0
  61. package/dist/chunk-STCCNLPC.js +160 -0
  62. package/dist/chunk-STCCNLPC.js.map +1 -0
  63. package/dist/chunk-SVLNF434.js +261 -0
  64. package/dist/chunk-SVLNF434.js.map +1 -0
  65. package/dist/chunk-UYFOLI2X.js +24 -0
  66. package/dist/chunk-UYFOLI2X.js.map +1 -0
  67. package/dist/chunk-VAN4WW3F.js +67 -0
  68. package/dist/chunk-VAN4WW3F.js.map +1 -0
  69. package/dist/chunk-WOMHL23C.js +369 -0
  70. package/dist/chunk-WOMHL23C.js.map +1 -0
  71. package/dist/chunk-WWVD5DR5.js +120 -0
  72. package/dist/chunk-WWVD5DR5.js.map +1 -0
  73. package/dist/chunk-XG2YMCJW.js +201 -0
  74. package/dist/chunk-XG2YMCJW.js.map +1 -0
  75. package/dist/chunk-XIJNE67Y.js +210 -0
  76. package/dist/chunk-XIJNE67Y.js.map +1 -0
  77. package/dist/chunk-Y6UJOUE5.js +44 -0
  78. package/dist/chunk-Y6UJOUE5.js.map +1 -0
  79. package/dist/chunk-YUO6SKJD.js +348 -0
  80. package/dist/chunk-YUO6SKJD.js.map +1 -0
  81. package/dist/components--hjBMTnz.d.ts +120 -0
  82. package/dist/components-B29WHGQN.d.ts +39 -0
  83. package/dist/components-BWG1GkZA.d.ts +20 -0
  84. package/dist/components-XCpL6IYt.d.ts +18 -0
  85. package/dist/components-qWwOsvwh.d.ts +43 -0
  86. package/dist/cooldown.d.ts +116 -0
  87. package/dist/cooldown.js +20 -0
  88. package/dist/cooldown.js.map +1 -0
  89. package/dist/coordinators/boundary-ricochet-3d.d.ts +19 -0
  90. package/dist/coordinators/boundary-ricochet-3d.js +8 -0
  91. package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
  92. package/dist/coordinators/boundary-ricochet.d.ts +34 -0
  93. package/dist/coordinators/boundary-ricochet.js +8 -0
  94. package/dist/coordinators/boundary-ricochet.js.map +1 -0
  95. package/dist/coordinators/first-person-shooter.d.ts +35 -0
  96. package/dist/coordinators/first-person-shooter.js +9 -0
  97. package/dist/coordinators/first-person-shooter.js.map +1 -0
  98. package/dist/coordinators/multidirectional-space-shooter.d.ts +27 -0
  99. package/dist/coordinators/multidirectional-space-shooter.js +10 -0
  100. package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
  101. package/dist/coordinators/top-down-shooter.d.ts +27 -0
  102. package/dist/coordinators/top-down-shooter.js +10 -0
  103. package/dist/coordinators/top-down-shooter.js.map +1 -0
  104. package/dist/core.d.ts +25 -0
  105. package/dist/core.js +327 -0
  106. package/dist/core.js.map +1 -0
  107. package/dist/destructible-3d.d.ts +42 -0
  108. package/dist/destructible-3d.js +13 -0
  109. package/dist/destructible-3d.js.map +1 -0
  110. package/dist/destructible-prebake.d.ts +28 -0
  111. package/dist/destructible-prebake.js +23 -0
  112. package/dist/destructible-prebake.js.map +1 -0
  113. package/dist/entity-types-CmtQ-IBp.d.ts +15 -0
  114. package/dist/first-person-perspective-C9Mptl0-.d.ts +23 -0
  115. package/dist/first-person.d.ts +204 -0
  116. package/dist/first-person.js +27 -0
  117. package/dist/first-person.js.map +1 -0
  118. package/dist/index.d.ts +40 -0
  119. package/dist/index.js +263 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/jumper-2d.d.ts +113 -0
  122. package/dist/jumper-2d.js +27 -0
  123. package/dist/jumper-2d.js.map +1 -0
  124. package/dist/jumper-3d.d.ts +164 -0
  125. package/dist/jumper-3d.js +29 -0
  126. package/dist/jumper-3d.js.map +1 -0
  127. package/dist/moveable-BCRpjAQb.d.ts +176 -0
  128. package/dist/particle-emitter/presets.d.ts +46 -0
  129. package/dist/particle-emitter/presets.js +15 -0
  130. package/dist/particle-emitter/presets.js.map +1 -0
  131. package/dist/particle-emitter.d.ts +78 -0
  132. package/dist/particle-emitter.js +15 -0
  133. package/dist/particle-emitter.js.map +1 -0
  134. package/dist/payload-BQzu-oY_.d.ts +89 -0
  135. package/dist/platformer-3d.d.ts +347 -0
  136. package/dist/platformer-3d.js +23 -0
  137. package/dist/platformer-3d.js.map +1 -0
  138. package/dist/ricochet-2d.d.ts +274 -0
  139. package/dist/ricochet-2d.js +16 -0
  140. package/dist/ricochet-2d.js.map +1 -0
  141. package/dist/ricochet-3d.d.ts +116 -0
  142. package/dist/ricochet-3d.js +16 -0
  143. package/dist/ricochet-3d.js.map +1 -0
  144. package/dist/runtime-2d.d.ts +2 -0
  145. package/dist/runtime-2d.js +32 -0
  146. package/dist/runtime-2d.js.map +1 -0
  147. package/dist/runtime-pong.d.ts +92 -0
  148. package/dist/runtime-pong.js +38 -0
  149. package/dist/runtime-pong.js.map +1 -0
  150. package/dist/screen-visibility.d.ts +74 -0
  151. package/dist/screen-visibility.js +10 -0
  152. package/dist/screen-visibility.js.map +1 -0
  153. package/dist/screen-wrap.d.ts +86 -0
  154. package/dist/screen-wrap.js +16 -0
  155. package/dist/screen-wrap.js.map +1 -0
  156. package/dist/shooter-2d.d.ts +77 -0
  157. package/dist/shooter-2d.js +12 -0
  158. package/dist/shooter-2d.js.map +1 -0
  159. package/dist/spark-DDlIg1nM.d.ts +148 -0
  160. package/dist/sync-state-machine-CZyspBpj.d.ts +16 -0
  161. package/dist/thruster.d.ts +132 -0
  162. package/dist/thruster.js +26 -0
  163. package/dist/thruster.js.map +1 -0
  164. package/dist/top-down-movement.d.ts +40 -0
  165. package/dist/top-down-movement.js +20 -0
  166. package/dist/top-down-movement.js.map +1 -0
  167. package/dist/use-behavior-D_82jAL3.d.ts +13 -0
  168. package/dist/vector-Bm65-FOG.d.ts +45 -0
  169. package/dist/world-boundary-2d.d.ts +141 -0
  170. package/dist/world-boundary-2d.js +21 -0
  171. package/dist/world-boundary-2d.js.map +1 -0
  172. package/dist/world-boundary-3d.d.ts +75 -0
  173. package/dist/world-boundary-3d.js +21 -0
  174. package/dist/world-boundary-3d.js.map +1 -0
  175. package/package.json +161 -0
@@ -0,0 +1,431 @@
1
+ import {
2
+ StageRicochetDim,
3
+ StageRicochetReflection
4
+ } from "./chunk-Y6UJOUE5.js";
5
+ import {
6
+ SyncStateMachine,
7
+ t
8
+ } from "./chunk-4URF65BR.js";
9
+ import {
10
+ defineBehavior
11
+ } from "./chunk-EZNCCO4L.js";
12
+
13
+ // src/lib/behaviors/ricochet-3d/ricochet-3d-fsm.ts
14
+ var Ricochet3DState = /* @__PURE__ */ ((Ricochet3DState2) => {
15
+ Ricochet3DState2["Idle"] = "idle";
16
+ Ricochet3DState2["Ricocheting"] = "ricocheting";
17
+ return Ricochet3DState2;
18
+ })(Ricochet3DState || {});
19
+ var Ricochet3DEvent = /* @__PURE__ */ ((Ricochet3DEvent2) => {
20
+ Ricochet3DEvent2["StartRicochet"] = "start-ricochet";
21
+ Ricochet3DEvent2["EndRicochet"] = "end-ricochet";
22
+ return Ricochet3DEvent2;
23
+ })(Ricochet3DEvent || {});
24
+ function clamp(value, min, max) {
25
+ return Math.max(min, Math.min(max, value));
26
+ }
27
+ function length3(x, y, z) {
28
+ return Math.sqrt(x * x + y * y + z * z);
29
+ }
30
+ var Ricochet3DFSM = class {
31
+ machine;
32
+ lastResult = null;
33
+ lastUpdatedAtMs = null;
34
+ currentTimeMs = 0;
35
+ listeners = /* @__PURE__ */ new Set();
36
+ constructor() {
37
+ this.machine = new SyncStateMachine(
38
+ "idle" /* Idle */,
39
+ [
40
+ t("idle" /* Idle */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */),
41
+ t("ricocheting" /* Ricocheting */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
42
+ t("idle" /* Idle */, "end-ricochet" /* EndRicochet */, "idle" /* Idle */),
43
+ t("ricocheting" /* Ricocheting */, "start-ricochet" /* StartRicochet */, "ricocheting" /* Ricocheting */)
44
+ ]
45
+ );
46
+ }
47
+ addListener(callback) {
48
+ this.listeners.add(callback);
49
+ return () => this.listeners.delete(callback);
50
+ }
51
+ getState() {
52
+ return this.machine.getState();
53
+ }
54
+ getLastResult() {
55
+ return this.lastResult;
56
+ }
57
+ getLastUpdatedAtMs() {
58
+ return this.lastUpdatedAtMs;
59
+ }
60
+ setCurrentTimeMs(timeMs) {
61
+ this.currentTimeMs = timeMs;
62
+ }
63
+ isOnCooldown(cooldownMs = 50) {
64
+ if (this.lastUpdatedAtMs === null) return false;
65
+ return this.currentTimeMs - this.lastUpdatedAtMs < cooldownMs;
66
+ }
67
+ resetCooldown() {
68
+ this.lastUpdatedAtMs = null;
69
+ }
70
+ computeRicochet(ctx, options = {}) {
71
+ const {
72
+ minSpeed = 2,
73
+ maxSpeed = 20,
74
+ speedMultiplier = 1.05,
75
+ reflectionMode = "angled",
76
+ maxAngleDeg = 45
77
+ } = options;
78
+ const {
79
+ selfVelocity,
80
+ selfPosition,
81
+ otherPosition,
82
+ otherSize
83
+ } = this.extractDataFromEntities(ctx);
84
+ if (!selfVelocity) {
85
+ this.dispatch("end-ricochet" /* EndRicochet */);
86
+ return null;
87
+ }
88
+ const speed = length3(selfVelocity.x, selfVelocity.y, selfVelocity.z);
89
+ if (speed === 0) {
90
+ this.dispatch("end-ricochet" /* EndRicochet */);
91
+ return null;
92
+ }
93
+ const normal = ctx.contact.normal ?? this.computeNormalFromPositions(selfPosition, otherPosition);
94
+ if (!normal) {
95
+ this.dispatch("end-ricochet" /* EndRicochet */);
96
+ return null;
97
+ }
98
+ const unitNormal = this.normalizeVector(normal);
99
+ let reflected = this.computeBasicReflection(selfVelocity, unitNormal);
100
+ if (reflectionMode === "angled") {
101
+ reflected = this.computeAngledDeflection(
102
+ reflected,
103
+ selfVelocity,
104
+ unitNormal,
105
+ speed,
106
+ maxAngleDeg,
107
+ speedMultiplier,
108
+ selfPosition,
109
+ otherPosition,
110
+ otherSize,
111
+ ctx.contact.position
112
+ );
113
+ } else {
114
+ reflected = {
115
+ x: reflected.x * speedMultiplier,
116
+ y: reflected.y * speedMultiplier,
117
+ z: reflected.z * speedMultiplier
118
+ };
119
+ }
120
+ reflected = this.applySpeedClamp(reflected, minSpeed, maxSpeed);
121
+ const result = {
122
+ velocity: reflected,
123
+ speed: length3(reflected.x, reflected.y, reflected.z),
124
+ normal: unitNormal
125
+ };
126
+ this.lastResult = result;
127
+ this.lastUpdatedAtMs = this.currentTimeMs;
128
+ this.dispatch("start-ricochet" /* StartRicochet */);
129
+ this.emitToListeners(result);
130
+ return result;
131
+ }
132
+ clearRicochet() {
133
+ this.dispatch("end-ricochet" /* EndRicochet */);
134
+ }
135
+ emitToListeners(result) {
136
+ for (const callback of this.listeners) {
137
+ try {
138
+ callback(result);
139
+ } catch (error) {
140
+ console.error("[Ricochet3DFSM] Listener error:", error);
141
+ }
142
+ }
143
+ }
144
+ extractDataFromEntities(ctx) {
145
+ let selfVelocity = ctx.selfVelocity;
146
+ let selfPosition = ctx.selfPosition;
147
+ let otherPosition = ctx.otherPosition;
148
+ let otherSize = ctx.otherSize;
149
+ if (ctx.entity?.body) {
150
+ const velocity = ctx.entity.body.linvel();
151
+ selfVelocity = selfVelocity ?? { x: velocity.x, y: velocity.y, z: velocity.z };
152
+ const position = ctx.entity.body.translation();
153
+ selfPosition = selfPosition ?? { x: position.x, y: position.y, z: position.z };
154
+ }
155
+ if (ctx.otherEntity?.body) {
156
+ const position = ctx.otherEntity.body.translation();
157
+ otherPosition = otherPosition ?? { x: position.x, y: position.y, z: position.z };
158
+ }
159
+ if (ctx.otherEntity && "size" in ctx.otherEntity) {
160
+ const size = ctx.otherEntity.size;
161
+ if (size && typeof size.x === "number") {
162
+ otherSize = otherSize ?? { x: size.x, y: size.y, z: size.z };
163
+ }
164
+ }
165
+ return { selfVelocity, selfPosition, otherPosition, otherSize };
166
+ }
167
+ computeNormalFromPositions(selfPosition, otherPosition) {
168
+ if (!selfPosition || !otherPosition) return null;
169
+ const delta = {
170
+ x: selfPosition.x - otherPosition.x,
171
+ y: selfPosition.y - otherPosition.y,
172
+ z: selfPosition.z - otherPosition.z
173
+ };
174
+ const absX = Math.abs(delta.x);
175
+ const absY = Math.abs(delta.y);
176
+ const absZ = Math.abs(delta.z);
177
+ if (absX >= absY && absX >= absZ) {
178
+ return { x: delta.x >= 0 ? 1 : -1, y: 0, z: 0 };
179
+ }
180
+ if (absY >= absX && absY >= absZ) {
181
+ return { x: 0, y: delta.y >= 0 ? 1 : -1, z: 0 };
182
+ }
183
+ return { x: 0, y: 0, z: delta.z >= 0 ? 1 : -1 };
184
+ }
185
+ normalizeVector(vector) {
186
+ const magnitude = length3(vector.x, vector.y, vector.z);
187
+ if (magnitude <= 1e-6) {
188
+ return { x: 0, y: 1, z: 0 };
189
+ }
190
+ return {
191
+ x: vector.x / magnitude,
192
+ y: vector.y / magnitude,
193
+ z: vector.z / magnitude
194
+ };
195
+ }
196
+ dot(a, b) {
197
+ return a.x * b.x + a.y * b.y + a.z * b.z;
198
+ }
199
+ computeBasicReflection(velocity, normal) {
200
+ const dotProduct = this.dot(velocity, normal);
201
+ return {
202
+ x: velocity.x - 2 * dotProduct * normal.x,
203
+ y: velocity.y - 2 * dotProduct * normal.y,
204
+ z: velocity.z - 2 * dotProduct * normal.z
205
+ };
206
+ }
207
+ computeAngledDeflection(reflected, incoming, normal, speed, maxAngleDeg, speedMultiplier, selfPosition, otherPosition, otherSize, contactPosition) {
208
+ const baseDirection = this.normalizeVector(reflected);
209
+ const tangentVector = this.computeHitOffsetVector(
210
+ incoming,
211
+ normal,
212
+ selfPosition,
213
+ otherPosition,
214
+ otherSize,
215
+ contactPosition
216
+ );
217
+ const offsetStrength = clamp(
218
+ length3(tangentVector.x, tangentVector.y, tangentVector.z),
219
+ 0,
220
+ 1
221
+ );
222
+ if (offsetStrength === 0) {
223
+ return {
224
+ x: baseDirection.x * speed * speedMultiplier,
225
+ y: baseDirection.y * speed * speedMultiplier,
226
+ z: baseDirection.z * speed * speedMultiplier
227
+ };
228
+ }
229
+ const tangentDirection = this.normalizeVector(tangentVector);
230
+ const angle = offsetStrength * (maxAngleDeg * Math.PI / 180);
231
+ const cosAngle = Math.cos(angle);
232
+ const sinAngle = Math.sin(angle);
233
+ const direction = this.normalizeVector({
234
+ x: baseDirection.x * cosAngle + tangentDirection.x * sinAngle,
235
+ y: baseDirection.y * cosAngle + tangentDirection.y * sinAngle,
236
+ z: baseDirection.z * cosAngle + tangentDirection.z * sinAngle
237
+ });
238
+ const newSpeed = speed * speedMultiplier;
239
+ return {
240
+ x: direction.x * newSpeed,
241
+ y: direction.y * newSpeed,
242
+ z: direction.z * newSpeed
243
+ };
244
+ }
245
+ computeHitOffsetVector(velocity, normal, selfPosition, otherPosition, otherSize, contactPosition) {
246
+ if (otherPosition && otherSize) {
247
+ const faceAxis = this.getDominantAxis(normal);
248
+ if (faceAxis === "x") {
249
+ return {
250
+ x: 0,
251
+ y: ((selfPosition?.y ?? contactPosition?.y ?? otherPosition.y) - otherPosition.y) / Math.max(otherSize.y / 2, 1e-6),
252
+ z: ((selfPosition?.z ?? contactPosition?.z ?? otherPosition.z) - otherPosition.z) / Math.max(otherSize.z / 2, 1e-6)
253
+ };
254
+ }
255
+ if (faceAxis === "y") {
256
+ return {
257
+ x: ((selfPosition?.x ?? contactPosition?.x ?? otherPosition.x) - otherPosition.x) / Math.max(otherSize.x / 2, 1e-6),
258
+ y: 0,
259
+ z: ((selfPosition?.z ?? contactPosition?.z ?? otherPosition.z) - otherPosition.z) / Math.max(otherSize.z / 2, 1e-6)
260
+ };
261
+ }
262
+ return {
263
+ x: ((selfPosition?.x ?? contactPosition?.x ?? otherPosition.x) - otherPosition.x) / Math.max(otherSize.x / 2, 1e-6),
264
+ y: ((selfPosition?.y ?? contactPosition?.y ?? otherPosition.y) - otherPosition.y) / Math.max(otherSize.y / 2, 1e-6),
265
+ z: 0
266
+ };
267
+ }
268
+ const tangent = {
269
+ x: velocity.x - this.dot(velocity, normal) * normal.x,
270
+ y: velocity.y - this.dot(velocity, normal) * normal.y,
271
+ z: velocity.z - this.dot(velocity, normal) * normal.z
272
+ };
273
+ const tangentLength = length3(tangent.x, tangent.y, tangent.z);
274
+ if (tangentLength <= 1e-6) {
275
+ return { x: 0, y: 0, z: 0 };
276
+ }
277
+ return {
278
+ x: tangent.x / tangentLength,
279
+ y: tangent.y / tangentLength,
280
+ z: tangent.z / tangentLength
281
+ };
282
+ }
283
+ getDominantAxis(vector) {
284
+ const absX = Math.abs(vector.x);
285
+ const absY = Math.abs(vector.y);
286
+ const absZ = Math.abs(vector.z);
287
+ if (absX >= absY && absX >= absZ) return "x";
288
+ if (absY >= absX && absY >= absZ) return "y";
289
+ return "z";
290
+ }
291
+ applySpeedClamp(velocity, minSpeed, maxSpeed) {
292
+ const currentSpeed = length3(velocity.x, velocity.y, velocity.z);
293
+ if (currentSpeed === 0) return velocity;
294
+ const targetSpeed = clamp(currentSpeed, minSpeed, maxSpeed);
295
+ const scale = targetSpeed / currentSpeed;
296
+ return {
297
+ x: velocity.x * scale,
298
+ y: velocity.y * scale,
299
+ z: velocity.z * scale
300
+ };
301
+ }
302
+ dispatch(event) {
303
+ if (this.machine.can(event)) {
304
+ this.machine.syncDispatch(event);
305
+ }
306
+ }
307
+ };
308
+
309
+ // src/lib/behaviors/ricochet-3d/ricochet-3d.descriptor.ts
310
+ var defaultOptions = {
311
+ minSpeed: 2,
312
+ maxSpeed: 20,
313
+ speedMultiplier: 1.05,
314
+ reflectionMode: "angled",
315
+ maxAngleDeg: 45
316
+ };
317
+ var RICOCHET_3D_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:ricochet-3d");
318
+ function createRicochet3DHandle(ref) {
319
+ return {
320
+ getRicochet: (ctx) => {
321
+ const fsm = ref.fsm;
322
+ if (!fsm) return null;
323
+ return fsm.computeRicochet(ctx, ref.options);
324
+ },
325
+ applyRicochet: (ctx) => {
326
+ const fsm = ref.fsm;
327
+ if (!fsm || fsm.isOnCooldown()) return false;
328
+ const result = fsm.computeRicochet(ctx, ref.options);
329
+ if (!result) return false;
330
+ const entity = ctx.entity;
331
+ if (entity?.transformStore) {
332
+ entity.transformStore.velocity.x = result.velocity.x;
333
+ entity.transformStore.velocity.y = result.velocity.y;
334
+ entity.transformStore.velocity.z = result.velocity.z;
335
+ entity.transformStore.dirty.velocity = true;
336
+ }
337
+ return true;
338
+ },
339
+ getLastResult: () => {
340
+ const fsm = ref.fsm;
341
+ return fsm?.getLastResult() ?? null;
342
+ },
343
+ onRicochet: (callback) => {
344
+ const fsm = ref.fsm;
345
+ if (!fsm) {
346
+ if (!ref.pendingListeners) {
347
+ ref.pendingListeners = [];
348
+ }
349
+ ref.pendingListeners.push(callback);
350
+ return () => {
351
+ const pending = ref.pendingListeners;
352
+ const index = pending.indexOf(callback);
353
+ if (index >= 0) pending.splice(index, 1);
354
+ };
355
+ }
356
+ return fsm.addListener(callback);
357
+ }
358
+ };
359
+ }
360
+ var Ricochet3DSystem = class {
361
+ constructor(world, wasmStage, getBehaviorLinks) {
362
+ this.world = world;
363
+ this.wasmStage = wasmStage;
364
+ this.getBehaviorLinks = getBehaviorLinks;
365
+ }
366
+ world;
367
+ wasmStage;
368
+ getBehaviorLinks;
369
+ elapsedMs = 0;
370
+ attachedRuntimeSlots = /* @__PURE__ */ new Set();
371
+ update(_ecs, delta) {
372
+ this.elapsedMs += delta * 1e3;
373
+ const links = this.getBehaviorLinks?.(RICOCHET_3D_BEHAVIOR_KEY);
374
+ if (!links) return;
375
+ for (const link of links) {
376
+ const ref = link.ref;
377
+ const gameEntity = link.entity;
378
+ if (!ref.fsm) {
379
+ ref.fsm = new Ricochet3DFSM();
380
+ const pending = ref.pendingListeners;
381
+ if (pending) {
382
+ for (const callback of pending) {
383
+ ref.fsm.addListener(callback);
384
+ }
385
+ ref.pendingListeners = [];
386
+ }
387
+ }
388
+ ref.fsm.setCurrentTimeMs(this.elapsedMs);
389
+ const handle = gameEntity?.runtimeHandle ?? -1;
390
+ if (this.wasmStage && handle >= 0) {
391
+ this.ensureWasmAttached(handle, ref.options);
392
+ }
393
+ }
394
+ }
395
+ ensureWasmAttached(handle, options) {
396
+ if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
397
+ const reflectionMode = options.reflectionMode === "simple" ? StageRicochetReflection.Mirror : StageRicochetReflection.Angled;
398
+ this.wasmStage.attachRicochet(handle, StageRicochetDim.Three, {
399
+ minSpeed: options.minSpeed,
400
+ maxSpeed: options.maxSpeed,
401
+ speedMultiplier: options.speedMultiplier,
402
+ maxAngleDeg: options.maxAngleDeg,
403
+ reflectionMode
404
+ });
405
+ this.attachedRuntimeSlots.add(handle);
406
+ }
407
+ destroy(_ecs) {
408
+ const links = this.getBehaviorLinks?.(RICOCHET_3D_BEHAVIOR_KEY);
409
+ if (links) {
410
+ for (const link of links) {
411
+ const ref = link.ref;
412
+ ref.fsm?.resetCooldown();
413
+ }
414
+ }
415
+ this.attachedRuntimeSlots.clear();
416
+ }
417
+ };
418
+ var Ricochet3DBehavior = defineBehavior({
419
+ name: "ricochet-3d",
420
+ defaultOptions,
421
+ systemFactory: (ctx) => new Ricochet3DSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),
422
+ createHandle: createRicochet3DHandle
423
+ });
424
+
425
+ export {
426
+ Ricochet3DState,
427
+ Ricochet3DEvent,
428
+ Ricochet3DFSM,
429
+ Ricochet3DBehavior
430
+ };
431
+ //# sourceMappingURL=chunk-ARJWUNRE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/ricochet-3d/ricochet-3d-fsm.ts","../src/lib/behaviors/ricochet-3d/ricochet-3d.descriptor.ts"],"sourcesContent":["import { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport { BaseEntityInterface } from '../../types/entity-types';\n\nexport interface Ricochet3DResult {\n\tvelocity: { x: number; y: number; z: number };\n\tspeed: number;\n\tnormal: { x: number; y: number; z: number };\n}\n\nexport interface Ricochet3DCollisionContext {\n\tentity?: BaseEntityInterface;\n\totherEntity?: BaseEntityInterface;\n\tselfVelocity?: { x: number; y: number; z: number };\n\tcontact: {\n\t\tnormal?: { x: number; y: number; z: number };\n\t\tposition?: { x: number; y: number; z: number };\n\t};\n\tselfPosition?: { x: number; y: number; z: number };\n\totherPosition?: { x: number; y: number; z: number };\n\totherSize?: { x: number; y: number; z: number };\n}\n\nexport enum Ricochet3DState {\n\tIdle = 'idle',\n\tRicocheting = 'ricocheting',\n}\n\nexport enum Ricochet3DEvent {\n\tStartRicochet = 'start-ricochet',\n\tEndRicochet = 'end-ricochet',\n}\n\nexport type Ricochet3DCallback = (result: Ricochet3DResult) => void;\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction length3(x: number, y: number, z: number): number {\n\treturn Math.sqrt(x * x + y * y + z * z);\n}\n\nexport class Ricochet3DFSM {\n\tpublic readonly machine: SyncStateMachine<Ricochet3DState, Ricochet3DEvent, never>;\n\n\tprivate lastResult: Ricochet3DResult | null = null;\n\tprivate lastUpdatedAtMs: number | null = null;\n\tprivate currentTimeMs = 0;\n\tprivate listeners = new Set<Ricochet3DCallback>();\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<Ricochet3DState, Ricochet3DEvent, never>(\n\t\t\tRicochet3DState.Idle,\n\t\t\t[\n\t\t\t\tt(Ricochet3DState.Idle, Ricochet3DEvent.StartRicochet, Ricochet3DState.Ricocheting),\n\t\t\t\tt(Ricochet3DState.Ricocheting, Ricochet3DEvent.EndRicochet, Ricochet3DState.Idle),\n\t\t\t\tt(Ricochet3DState.Idle, Ricochet3DEvent.EndRicochet, Ricochet3DState.Idle),\n\t\t\t\tt(Ricochet3DState.Ricocheting, Ricochet3DEvent.StartRicochet, Ricochet3DState.Ricocheting),\n\t\t\t],\n\t\t);\n\t}\n\n\taddListener(callback: Ricochet3DCallback): () => void {\n\t\tthis.listeners.add(callback);\n\t\treturn () => this.listeners.delete(callback);\n\t}\n\n\tgetState(): Ricochet3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tgetLastResult(): Ricochet3DResult | null {\n\t\treturn this.lastResult;\n\t}\n\n\tgetLastUpdatedAtMs(): number | null {\n\t\treturn this.lastUpdatedAtMs;\n\t}\n\n\tsetCurrentTimeMs(timeMs: number): void {\n\t\tthis.currentTimeMs = timeMs;\n\t}\n\n\tisOnCooldown(cooldownMs: number = 50): boolean {\n\t\tif (this.lastUpdatedAtMs === null) return false;\n\t\treturn (this.currentTimeMs - this.lastUpdatedAtMs) < cooldownMs;\n\t}\n\n\tresetCooldown(): void {\n\t\tthis.lastUpdatedAtMs = null;\n\t}\n\n\tcomputeRicochet(\n\t\tctx: Ricochet3DCollisionContext,\n\t\toptions: {\n\t\t\tminSpeed?: number;\n\t\t\tmaxSpeed?: number;\n\t\t\tspeedMultiplier?: number;\n\t\t\treflectionMode?: 'simple' | 'angled';\n\t\t\tmaxAngleDeg?: number;\n\t\t} = {},\n\t): Ricochet3DResult | null {\n\t\tconst {\n\t\t\tminSpeed = 2,\n\t\t\tmaxSpeed = 20,\n\t\t\tspeedMultiplier = 1.05,\n\t\t\treflectionMode = 'angled',\n\t\t\tmaxAngleDeg = 45,\n\t\t} = options;\n\n\t\tconst {\n\t\t\tselfVelocity,\n\t\t\tselfPosition,\n\t\t\totherPosition,\n\t\t\totherSize,\n\t\t} = this.extractDataFromEntities(ctx);\n\n\t\tif (!selfVelocity) {\n\t\t\tthis.dispatch(Ricochet3DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst speed = length3(selfVelocity.x, selfVelocity.y, selfVelocity.z);\n\t\tif (speed === 0) {\n\t\t\tthis.dispatch(Ricochet3DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst normal = ctx.contact.normal ?? this.computeNormalFromPositions(selfPosition, otherPosition);\n\t\tif (!normal) {\n\t\t\tthis.dispatch(Ricochet3DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst unitNormal = this.normalizeVector(normal);\n\t\tlet reflected = this.computeBasicReflection(selfVelocity, unitNormal);\n\n\t\tif (reflectionMode === 'angled') {\n\t\t\treflected = this.computeAngledDeflection(\n\t\t\t\treflected,\n\t\t\t\tselfVelocity,\n\t\t\t\tunitNormal,\n\t\t\t\tspeed,\n\t\t\t\tmaxAngleDeg,\n\t\t\t\tspeedMultiplier,\n\t\t\t\tselfPosition,\n\t\t\t\totherPosition,\n\t\t\t\totherSize,\n\t\t\t\tctx.contact.position,\n\t\t\t);\n\t\t} else {\n\t\t\treflected = {\n\t\t\t\tx: reflected.x * speedMultiplier,\n\t\t\t\ty: reflected.y * speedMultiplier,\n\t\t\t\tz: reflected.z * speedMultiplier,\n\t\t\t};\n\t\t}\n\n\t\treflected = this.applySpeedClamp(reflected, minSpeed, maxSpeed);\n\n\t\tconst result: Ricochet3DResult = {\n\t\t\tvelocity: reflected,\n\t\t\tspeed: length3(reflected.x, reflected.y, reflected.z),\n\t\t\tnormal: unitNormal,\n\t\t};\n\n\t\tthis.lastResult = result;\n\t\tthis.lastUpdatedAtMs = this.currentTimeMs;\n\t\tthis.dispatch(Ricochet3DEvent.StartRicochet);\n\t\tthis.emitToListeners(result);\n\t\treturn result;\n\t}\n\n\tclearRicochet(): void {\n\t\tthis.dispatch(Ricochet3DEvent.EndRicochet);\n\t}\n\n\tprivate emitToListeners(result: Ricochet3DResult): void {\n\t\tfor (const callback of this.listeners) {\n\t\t\ttry {\n\t\t\t\tcallback(result);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Ricochet3DFSM] Listener error:', error);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate extractDataFromEntities(ctx: Ricochet3DCollisionContext) {\n\t\tlet selfVelocity = ctx.selfVelocity;\n\t\tlet selfPosition = ctx.selfPosition;\n\t\tlet otherPosition = ctx.otherPosition;\n\t\tlet otherSize = ctx.otherSize;\n\n\t\tif (ctx.entity?.body) {\n\t\t\tconst velocity = ctx.entity.body.linvel();\n\t\t\tselfVelocity = selfVelocity ?? { x: velocity.x, y: velocity.y, z: velocity.z };\n\t\t\tconst position = ctx.entity.body.translation();\n\t\t\tselfPosition = selfPosition ?? { x: position.x, y: position.y, z: position.z };\n\t\t}\n\n\t\tif (ctx.otherEntity?.body) {\n\t\t\tconst position = ctx.otherEntity.body.translation();\n\t\t\totherPosition = otherPosition ?? { x: position.x, y: position.y, z: position.z };\n\t\t}\n\n\t\tif (ctx.otherEntity && 'size' in ctx.otherEntity) {\n\t\t\tconst size = (ctx.otherEntity as any).size;\n\t\t\tif (size && typeof size.x === 'number') {\n\t\t\t\totherSize = otherSize ?? { x: size.x, y: size.y, z: size.z };\n\t\t\t}\n\t\t}\n\n\t\treturn { selfVelocity, selfPosition, otherPosition, otherSize };\n\t}\n\n\tprivate computeNormalFromPositions(\n\t\tselfPosition?: { x: number; y: number; z: number },\n\t\totherPosition?: { x: number; y: number; z: number },\n\t): { x: number; y: number; z: number } | null {\n\t\tif (!selfPosition || !otherPosition) return null;\n\n\t\tconst delta = {\n\t\t\tx: selfPosition.x - otherPosition.x,\n\t\t\ty: selfPosition.y - otherPosition.y,\n\t\t\tz: selfPosition.z - otherPosition.z,\n\t\t};\n\t\tconst absX = Math.abs(delta.x);\n\t\tconst absY = Math.abs(delta.y);\n\t\tconst absZ = Math.abs(delta.z);\n\n\t\tif (absX >= absY && absX >= absZ) {\n\t\t\treturn { x: delta.x >= 0 ? 1 : -1, y: 0, z: 0 };\n\t\t}\n\t\tif (absY >= absX && absY >= absZ) {\n\t\t\treturn { x: 0, y: delta.y >= 0 ? 1 : -1, z: 0 };\n\t\t}\n\t\treturn { x: 0, y: 0, z: delta.z >= 0 ? 1 : -1 };\n\t}\n\n\tprivate normalizeVector(vector: { x: number; y: number; z: number }) {\n\t\tconst magnitude = length3(vector.x, vector.y, vector.z);\n\t\tif (magnitude <= 1e-6) {\n\t\t\treturn { x: 0, y: 1, z: 0 };\n\t\t}\n\t\treturn {\n\t\t\tx: vector.x / magnitude,\n\t\t\ty: vector.y / magnitude,\n\t\t\tz: vector.z / magnitude,\n\t\t};\n\t}\n\n\tprivate dot(\n\t\ta: { x: number; y: number; z: number },\n\t\tb: { x: number; y: number; z: number },\n\t): number {\n\t\treturn a.x * b.x + a.y * b.y + a.z * b.z;\n\t}\n\n\tprivate computeBasicReflection(\n\t\tvelocity: { x: number; y: number; z: number },\n\t\tnormal: { x: number; y: number; z: number },\n\t): { x: number; y: number; z: number } {\n\t\tconst dotProduct = this.dot(velocity, normal);\n\t\treturn {\n\t\t\tx: velocity.x - 2 * dotProduct * normal.x,\n\t\t\ty: velocity.y - 2 * dotProduct * normal.y,\n\t\t\tz: velocity.z - 2 * dotProduct * normal.z,\n\t\t};\n\t}\n\n\tprivate computeAngledDeflection(\n\t\treflected: { x: number; y: number; z: number },\n\t\tincoming: { x: number; y: number; z: number },\n\t\tnormal: { x: number; y: number; z: number },\n\t\tspeed: number,\n\t\tmaxAngleDeg: number,\n\t\tspeedMultiplier: number,\n\t\tselfPosition?: { x: number; y: number; z: number },\n\t\totherPosition?: { x: number; y: number; z: number },\n\t\totherSize?: { x: number; y: number; z: number },\n\t\tcontactPosition?: { x: number; y: number; z: number },\n\t): { x: number; y: number; z: number } {\n\t\tconst baseDirection = this.normalizeVector(reflected);\n\t\tconst tangentVector = this.computeHitOffsetVector(\n\t\t\tincoming,\n\t\t\tnormal,\n\t\t\tselfPosition,\n\t\t\totherPosition,\n\t\t\totherSize,\n\t\t\tcontactPosition,\n\t\t);\n\n\t\tconst offsetStrength = clamp(\n\t\t\tlength3(tangentVector.x, tangentVector.y, tangentVector.z),\n\t\t\t0,\n\t\t\t1,\n\t\t);\n\t\tif (offsetStrength === 0) {\n\t\t\treturn {\n\t\t\t\tx: baseDirection.x * speed * speedMultiplier,\n\t\t\t\ty: baseDirection.y * speed * speedMultiplier,\n\t\t\t\tz: baseDirection.z * speed * speedMultiplier,\n\t\t\t};\n\t\t}\n\n\t\tconst tangentDirection = this.normalizeVector(tangentVector);\n\t\tconst angle = offsetStrength * (maxAngleDeg * Math.PI / 180);\n\t\tconst cosAngle = Math.cos(angle);\n\t\tconst sinAngle = Math.sin(angle);\n\t\tconst direction = this.normalizeVector({\n\t\t\tx: baseDirection.x * cosAngle + tangentDirection.x * sinAngle,\n\t\t\ty: baseDirection.y * cosAngle + tangentDirection.y * sinAngle,\n\t\t\tz: baseDirection.z * cosAngle + tangentDirection.z * sinAngle,\n\t\t});\n\t\tconst newSpeed = speed * speedMultiplier;\n\n\t\treturn {\n\t\t\tx: direction.x * newSpeed,\n\t\t\ty: direction.y * newSpeed,\n\t\t\tz: direction.z * newSpeed,\n\t\t};\n\t}\n\n\tprivate computeHitOffsetVector(\n\t\tvelocity: { x: number; y: number; z: number },\n\t\tnormal: { x: number; y: number; z: number },\n\t\tselfPosition?: { x: number; y: number; z: number },\n\t\totherPosition?: { x: number; y: number; z: number },\n\t\totherSize?: { x: number; y: number; z: number },\n\t\tcontactPosition?: { x: number; y: number; z: number },\n\t): { x: number; y: number; z: number } {\n\t\tif (otherPosition && otherSize) {\n\t\t\tconst faceAxis = this.getDominantAxis(normal);\n\t\t\tif (faceAxis === 'x') {\n\t\t\t\treturn {\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: ((selfPosition?.y ?? contactPosition?.y ?? otherPosition.y) - otherPosition.y) / Math.max(otherSize.y / 2, 1e-6),\n\t\t\t\t\tz: ((selfPosition?.z ?? contactPosition?.z ?? otherPosition.z) - otherPosition.z) / Math.max(otherSize.z / 2, 1e-6),\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (faceAxis === 'y') {\n\t\t\t\treturn {\n\t\t\t\t\tx: ((selfPosition?.x ?? contactPosition?.x ?? otherPosition.x) - otherPosition.x) / Math.max(otherSize.x / 2, 1e-6),\n\t\t\t\t\ty: 0,\n\t\t\t\t\tz: ((selfPosition?.z ?? contactPosition?.z ?? otherPosition.z) - otherPosition.z) / Math.max(otherSize.z / 2, 1e-6),\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tx: ((selfPosition?.x ?? contactPosition?.x ?? otherPosition.x) - otherPosition.x) / Math.max(otherSize.x / 2, 1e-6),\n\t\t\t\ty: ((selfPosition?.y ?? contactPosition?.y ?? otherPosition.y) - otherPosition.y) / Math.max(otherSize.y / 2, 1e-6),\n\t\t\t\tz: 0,\n\t\t\t};\n\t\t}\n\n\t\tconst tangent = {\n\t\t\tx: velocity.x - this.dot(velocity, normal) * normal.x,\n\t\t\ty: velocity.y - this.dot(velocity, normal) * normal.y,\n\t\t\tz: velocity.z - this.dot(velocity, normal) * normal.z,\n\t\t};\n\t\tconst tangentLength = length3(tangent.x, tangent.y, tangent.z);\n\t\tif (tangentLength <= 1e-6) {\n\t\t\treturn { x: 0, y: 0, z: 0 };\n\t\t}\n\t\treturn {\n\t\t\tx: tangent.x / tangentLength,\n\t\t\ty: tangent.y / tangentLength,\n\t\t\tz: tangent.z / tangentLength,\n\t\t};\n\t}\n\n\tprivate getDominantAxis(vector: { x: number; y: number; z: number }): 'x' | 'y' | 'z' {\n\t\tconst absX = Math.abs(vector.x);\n\t\tconst absY = Math.abs(vector.y);\n\t\tconst absZ = Math.abs(vector.z);\n\t\tif (absX >= absY && absX >= absZ) return 'x';\n\t\tif (absY >= absX && absY >= absZ) return 'y';\n\t\treturn 'z';\n\t}\n\n\tprivate applySpeedClamp(\n\t\tvelocity: { x: number; y: number; z: number },\n\t\tminSpeed: number,\n\t\tmaxSpeed: number,\n\t): { x: number; y: number; z: number } {\n\t\tconst currentSpeed = length3(velocity.x, velocity.y, velocity.z);\n\t\tif (currentSpeed === 0) return velocity;\n\n\t\tconst targetSpeed = clamp(currentSpeed, minSpeed, maxSpeed);\n\t\tconst scale = targetSpeed / currentSpeed;\n\t\treturn {\n\t\t\tx: velocity.x * scale,\n\t\t\ty: velocity.y * scale,\n\t\t\tz: velocity.z * scale,\n\t\t};\n\t}\n\n\tprivate dispatch(event: Ricochet3DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n}\n","import { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tRicochet3DFSM,\n\ttype Ricochet3DResult,\n\ttype Ricochet3DCollisionContext,\n\ttype Ricochet3DCallback,\n} from './ricochet-3d-fsm';\nimport {\n\tStageRicochetDim,\n\tStageRicochetReflection,\n\ttype WasmStageRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\nexport type { Ricochet3DResult };\n\nexport interface Ricochet3DOptions {\n\tminSpeed: number;\n\tmaxSpeed: number;\n\tspeedMultiplier: number;\n\treflectionMode: 'simple' | 'angled';\n\tmaxAngleDeg: number;\n}\n\nexport interface Ricochet3DHandle {\n\tgetRicochet(ctx: Ricochet3DCollisionContext): Ricochet3DResult | null;\n\tapplyRicochet(ctx: Ricochet3DCollisionContext): boolean;\n\tgetLastResult(): Ricochet3DResult | null;\n\tonRicochet(callback: Ricochet3DCallback): () => void;\n}\n\nconst defaultOptions: Ricochet3DOptions = {\n\tminSpeed: 2,\n\tmaxSpeed: 20,\n\tspeedMultiplier: 1.05,\n\treflectionMode: 'angled',\n\tmaxAngleDeg: 45,\n};\n\nconst RICOCHET_3D_BEHAVIOR_KEY = Symbol.for('zylem:behavior:ricochet-3d');\n\nfunction createRicochet3DHandle(\n\tref: BehaviorRef<Ricochet3DOptions>,\n): Ricochet3DHandle {\n\treturn {\n\t\tgetRicochet: (ctx: Ricochet3DCollisionContext) => {\n\t\t\tconst fsm = ref.fsm as Ricochet3DFSM | undefined;\n\t\t\tif (!fsm) return null;\n\t\t\treturn fsm.computeRicochet(ctx, ref.options);\n\t\t},\n\t\tapplyRicochet: (ctx: Ricochet3DCollisionContext): boolean => {\n\t\t\tconst fsm = ref.fsm as Ricochet3DFSM | undefined;\n\t\t\tif (!fsm || fsm.isOnCooldown()) return false;\n\n\t\t\tconst result = fsm.computeRicochet(ctx, ref.options);\n\t\t\tif (!result) return false;\n\n\t\t\tconst entity = ctx.entity as any;\n\t\t\tif (entity?.transformStore) {\n\t\t\t\tentity.transformStore.velocity.x = result.velocity.x;\n\t\t\t\tentity.transformStore.velocity.y = result.velocity.y;\n\t\t\t\tentity.transformStore.velocity.z = result.velocity.z;\n\t\t\t\tentity.transformStore.dirty.velocity = true;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t\tgetLastResult: () => {\n\t\t\tconst fsm = ref.fsm as Ricochet3DFSM | undefined;\n\t\t\treturn fsm?.getLastResult() ?? null;\n\t\t},\n\t\tonRicochet: (callback: Ricochet3DCallback) => {\n\t\t\tconst fsm = ref.fsm as Ricochet3DFSM | undefined;\n\t\t\tif (!fsm) {\n\t\t\t\tif (!(ref as any).pendingListeners) {\n\t\t\t\t\t(ref as any).pendingListeners = [];\n\t\t\t\t}\n\t\t\t\t(ref as any).pendingListeners.push(callback);\n\t\t\t\treturn () => {\n\t\t\t\t\tconst pending = (ref as any).pendingListeners as Ricochet3DCallback[];\n\t\t\t\t\tconst index = pending.indexOf(callback);\n\t\t\t\t\tif (index >= 0) pending.splice(index, 1);\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn fsm.addListener(callback);\n\t\t},\n\t};\n}\n\nclass Ricochet3DSystem implements BehaviorSystem {\n\tprivate elapsedMs = 0;\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate world: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tthis.elapsedMs += delta * 1000;\n\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_3D_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst ref = link.ref as any;\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tif (!ref.fsm) {\n\t\t\t\tref.fsm = new Ricochet3DFSM();\n\t\t\t\tconst pending = ref.pendingListeners as Ricochet3DCallback[] | undefined;\n\t\t\t\tif (pending) {\n\t\t\t\t\tfor (const callback of pending) {\n\t\t\t\t\t\tref.fsm.addListener(callback);\n\t\t\t\t\t}\n\t\t\t\t\tref.pendingListeners = [];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tref.fsm.setCurrentTimeMs(this.elapsedMs);\n\n\t\t\tconst handle = (gameEntity?.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, ref.options as Ricochet3DOptions);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Ricochet3DOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst reflectionMode = options.reflectionMode === 'simple'\n\t\t\t? StageRicochetReflection.Mirror\n\t\t\t: StageRicochetReflection.Angled;\n\t\tthis.wasmStage.attachRicochet(handle, StageRicochetDim.Three, {\n\t\t\tminSpeed: options.minSpeed,\n\t\t\tmaxSpeed: options.maxSpeed,\n\t\t\tspeedMultiplier: options.speedMultiplier,\n\t\t\tmaxAngleDeg: options.maxAngleDeg,\n\t\t\treflectionMode,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_3D_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\tconst ref = link.ref as any;\n\t\t\t\tref.fsm?.resetCooldown();\n\t\t\t}\n\t\t}\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\nexport const Ricochet3DBehavior = defineBehavior({\n\tname: 'ricochet-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Ricochet3DSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createRicochet3DHandle,\n});\n"],"mappings":"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","names":["Ricochet3DState","Ricochet3DEvent"]}