@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.
- package/README.md +26 -0
- package/dist/behavior-system-DYbx-x_-.d.ts +307 -0
- package/dist/chunk-2C3Z5GE7.js +176 -0
- package/dist/chunk-2C3Z5GE7.js.map +1 -0
- package/dist/chunk-2CLT36VB.js +241 -0
- package/dist/chunk-2CLT36VB.js.map +1 -0
- package/dist/chunk-3PYGRHAL.js +35 -0
- package/dist/chunk-3PYGRHAL.js.map +1 -0
- package/dist/chunk-4I6E6DGV.js +212 -0
- package/dist/chunk-4I6E6DGV.js.map +1 -0
- package/dist/chunk-4URF65BR.js +44 -0
- package/dist/chunk-4URF65BR.js.map +1 -0
- package/dist/chunk-6C6NXNEW.js +38 -0
- package/dist/chunk-6C6NXNEW.js.map +1 -0
- package/dist/chunk-ARJWUNRE.js +431 -0
- package/dist/chunk-ARJWUNRE.js.map +1 -0
- package/dist/chunk-BXP4K7RF.js +1205 -0
- package/dist/chunk-BXP4K7RF.js.map +1 -0
- package/dist/chunk-DYLH6K7B.js +44 -0
- package/dist/chunk-DYLH6K7B.js.map +1 -0
- package/dist/chunk-EIWQM6U3.js +27 -0
- package/dist/chunk-EIWQM6U3.js.map +1 -0
- package/dist/chunk-EZNCCO4L.js +14 -0
- package/dist/chunk-EZNCCO4L.js.map +1 -0
- package/dist/chunk-F3KRX2V4.js +457 -0
- package/dist/chunk-F3KRX2V4.js.map +1 -0
- package/dist/chunk-FPTWVCPN.js +53 -0
- package/dist/chunk-FPTWVCPN.js.map +1 -0
- package/dist/chunk-GCNRXAKH.js +37 -0
- package/dist/chunk-GCNRXAKH.js.map +1 -0
- package/dist/chunk-GYURWCIQ.js +1985 -0
- package/dist/chunk-GYURWCIQ.js.map +1 -0
- package/dist/chunk-HZMY3TT4.js +244 -0
- package/dist/chunk-HZMY3TT4.js.map +1 -0
- package/dist/chunk-ID5QJYF5.js +50 -0
- package/dist/chunk-ID5QJYF5.js.map +1 -0
- package/dist/chunk-JAN34G6S.js +552 -0
- package/dist/chunk-JAN34G6S.js.map +1 -0
- package/dist/chunk-K3UNLQ7W.js +118 -0
- package/dist/chunk-K3UNLQ7W.js.map +1 -0
- package/dist/chunk-KDY5N6J4.js +82 -0
- package/dist/chunk-KDY5N6J4.js.map +1 -0
- package/dist/chunk-KOZUNIIE.js +413 -0
- package/dist/chunk-KOZUNIIE.js.map +1 -0
- package/dist/chunk-KS72RZHX.js +30 -0
- package/dist/chunk-KS72RZHX.js.map +1 -0
- package/dist/chunk-LD5SMIB3.js +32 -0
- package/dist/chunk-LD5SMIB3.js.map +1 -0
- package/dist/chunk-OHCPV2NT.js +86 -0
- package/dist/chunk-OHCPV2NT.js.map +1 -0
- package/dist/chunk-OYWFPIHF.js +115 -0
- package/dist/chunk-OYWFPIHF.js.map +1 -0
- package/dist/chunk-POZER3MQ.js +407 -0
- package/dist/chunk-POZER3MQ.js.map +1 -0
- package/dist/chunk-RTRVBEIB.js +56 -0
- package/dist/chunk-RTRVBEIB.js.map +1 -0
- package/dist/chunk-RTVRUNYR.js +29 -0
- package/dist/chunk-RTVRUNYR.js.map +1 -0
- package/dist/chunk-SS7ELMJ7.js +406 -0
- package/dist/chunk-SS7ELMJ7.js.map +1 -0
- package/dist/chunk-STCCNLPC.js +160 -0
- package/dist/chunk-STCCNLPC.js.map +1 -0
- package/dist/chunk-SVLNF434.js +261 -0
- package/dist/chunk-SVLNF434.js.map +1 -0
- package/dist/chunk-UYFOLI2X.js +24 -0
- package/dist/chunk-UYFOLI2X.js.map +1 -0
- package/dist/chunk-VAN4WW3F.js +67 -0
- package/dist/chunk-VAN4WW3F.js.map +1 -0
- package/dist/chunk-WOMHL23C.js +369 -0
- package/dist/chunk-WOMHL23C.js.map +1 -0
- package/dist/chunk-WWVD5DR5.js +120 -0
- package/dist/chunk-WWVD5DR5.js.map +1 -0
- package/dist/chunk-XG2YMCJW.js +201 -0
- package/dist/chunk-XG2YMCJW.js.map +1 -0
- package/dist/chunk-XIJNE67Y.js +210 -0
- package/dist/chunk-XIJNE67Y.js.map +1 -0
- package/dist/chunk-Y6UJOUE5.js +44 -0
- package/dist/chunk-Y6UJOUE5.js.map +1 -0
- package/dist/chunk-YUO6SKJD.js +348 -0
- package/dist/chunk-YUO6SKJD.js.map +1 -0
- package/dist/components--hjBMTnz.d.ts +120 -0
- package/dist/components-B29WHGQN.d.ts +39 -0
- package/dist/components-BWG1GkZA.d.ts +20 -0
- package/dist/components-XCpL6IYt.d.ts +18 -0
- package/dist/components-qWwOsvwh.d.ts +43 -0
- package/dist/cooldown.d.ts +116 -0
- package/dist/cooldown.js +20 -0
- package/dist/cooldown.js.map +1 -0
- package/dist/coordinators/boundary-ricochet-3d.d.ts +19 -0
- package/dist/coordinators/boundary-ricochet-3d.js +8 -0
- package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
- package/dist/coordinators/boundary-ricochet.d.ts +34 -0
- package/dist/coordinators/boundary-ricochet.js +8 -0
- package/dist/coordinators/boundary-ricochet.js.map +1 -0
- package/dist/coordinators/first-person-shooter.d.ts +35 -0
- package/dist/coordinators/first-person-shooter.js +9 -0
- package/dist/coordinators/first-person-shooter.js.map +1 -0
- package/dist/coordinators/multidirectional-space-shooter.d.ts +27 -0
- package/dist/coordinators/multidirectional-space-shooter.js +10 -0
- package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
- package/dist/coordinators/top-down-shooter.d.ts +27 -0
- package/dist/coordinators/top-down-shooter.js +10 -0
- package/dist/coordinators/top-down-shooter.js.map +1 -0
- package/dist/core.d.ts +25 -0
- package/dist/core.js +327 -0
- package/dist/core.js.map +1 -0
- package/dist/destructible-3d.d.ts +42 -0
- package/dist/destructible-3d.js +13 -0
- package/dist/destructible-3d.js.map +1 -0
- package/dist/destructible-prebake.d.ts +28 -0
- package/dist/destructible-prebake.js +23 -0
- package/dist/destructible-prebake.js.map +1 -0
- package/dist/entity-types-CmtQ-IBp.d.ts +15 -0
- package/dist/first-person-perspective-C9Mptl0-.d.ts +23 -0
- package/dist/first-person.d.ts +204 -0
- package/dist/first-person.js +27 -0
- package/dist/first-person.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +263 -0
- package/dist/index.js.map +1 -0
- package/dist/jumper-2d.d.ts +113 -0
- package/dist/jumper-2d.js +27 -0
- package/dist/jumper-2d.js.map +1 -0
- package/dist/jumper-3d.d.ts +164 -0
- package/dist/jumper-3d.js +29 -0
- package/dist/jumper-3d.js.map +1 -0
- package/dist/moveable-BCRpjAQb.d.ts +176 -0
- package/dist/particle-emitter/presets.d.ts +46 -0
- package/dist/particle-emitter/presets.js +15 -0
- package/dist/particle-emitter/presets.js.map +1 -0
- package/dist/particle-emitter.d.ts +78 -0
- package/dist/particle-emitter.js +15 -0
- package/dist/particle-emitter.js.map +1 -0
- package/dist/payload-BQzu-oY_.d.ts +89 -0
- package/dist/platformer-3d.d.ts +347 -0
- package/dist/platformer-3d.js +23 -0
- package/dist/platformer-3d.js.map +1 -0
- package/dist/ricochet-2d.d.ts +274 -0
- package/dist/ricochet-2d.js +16 -0
- package/dist/ricochet-2d.js.map +1 -0
- package/dist/ricochet-3d.d.ts +116 -0
- package/dist/ricochet-3d.js +16 -0
- package/dist/ricochet-3d.js.map +1 -0
- package/dist/runtime-2d.d.ts +2 -0
- package/dist/runtime-2d.js +32 -0
- package/dist/runtime-2d.js.map +1 -0
- package/dist/runtime-pong.d.ts +92 -0
- package/dist/runtime-pong.js +38 -0
- package/dist/runtime-pong.js.map +1 -0
- package/dist/screen-visibility.d.ts +74 -0
- package/dist/screen-visibility.js +10 -0
- package/dist/screen-visibility.js.map +1 -0
- package/dist/screen-wrap.d.ts +86 -0
- package/dist/screen-wrap.js +16 -0
- package/dist/screen-wrap.js.map +1 -0
- package/dist/shooter-2d.d.ts +77 -0
- package/dist/shooter-2d.js +12 -0
- package/dist/shooter-2d.js.map +1 -0
- package/dist/spark-DDlIg1nM.d.ts +148 -0
- package/dist/sync-state-machine-CZyspBpj.d.ts +16 -0
- package/dist/thruster.d.ts +132 -0
- package/dist/thruster.js +26 -0
- package/dist/thruster.js.map +1 -0
- package/dist/top-down-movement.d.ts +40 -0
- package/dist/top-down-movement.js +20 -0
- package/dist/top-down-movement.js.map +1 -0
- package/dist/use-behavior-D_82jAL3.d.ts +13 -0
- package/dist/vector-Bm65-FOG.d.ts +45 -0
- package/dist/world-boundary-2d.d.ts +141 -0
- package/dist/world-boundary-2d.js +21 -0
- package/dist/world-boundary-2d.js.map +1 -0
- package/dist/world-boundary-3d.d.ts +75 -0
- package/dist/world-boundary-3d.js +21 -0
- package/dist/world-boundary-3d.js.map +1 -0
- 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"]}
|