@zylem/behaviors 0.4.1 → 0.5.1
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 +13 -1
- package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CeJXzNvr.d.ts} +305 -17
- package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
- package/dist/chunk-2PAHQZZD.js.map +1 -0
- package/dist/chunk-52FJIDGL.js +30 -0
- package/dist/chunk-52FJIDGL.js.map +1 -0
- package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
- package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
- package/dist/{chunk-A4CA35DQ.js → chunk-5EBIIYZD.js} +25 -45
- package/dist/chunk-5EBIIYZD.js.map +1 -0
- package/dist/{chunk-4L36OPY2.js → chunk-5NJGASUJ.js} +81 -135
- package/dist/chunk-5NJGASUJ.js.map +1 -0
- package/dist/{chunk-27UPCP5B.js → chunk-5UMCWV5A.js} +22 -13
- package/dist/chunk-5UMCWV5A.js.map +1 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
- package/dist/{chunk-Z72F2ENM.js → chunk-AEBDZWCP.js} +17 -26
- package/dist/chunk-AEBDZWCP.js.map +1 -0
- package/dist/chunk-AS3HR7AS.js +188 -0
- package/dist/chunk-AS3HR7AS.js.map +1 -0
- package/dist/chunk-E4X4YJZB.js +841 -0
- package/dist/chunk-E4X4YJZB.js.map +1 -0
- package/dist/{chunk-VMQHNJJI.js → chunk-F6ESSHQK.js} +17 -23
- package/dist/chunk-F6ESSHQK.js.map +1 -0
- package/dist/chunk-GQAPBNGT.js +210 -0
- package/dist/chunk-GQAPBNGT.js.map +1 -0
- package/dist/chunk-JGXRQUTC.js +191 -0
- package/dist/chunk-JGXRQUTC.js.map +1 -0
- package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
- package/dist/chunk-JVADRLWX.js.map +1 -0
- package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
- package/dist/{chunk-QDCJLJUV.js → chunk-KOWGILCN.js} +22 -13
- package/dist/chunk-KOWGILCN.js.map +1 -0
- package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
- package/dist/chunk-M3QDKKDF.js.map +1 -0
- package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
- package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
- package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
- package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
- package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
- package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
- package/dist/chunk-PLIXVF7B.js.map +1 -0
- package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
- package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
- package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
- package/dist/chunk-TBUKJKY6.js.map +1 -0
- package/dist/chunk-VFDUKGRZ.js +155 -0
- package/dist/chunk-VFDUKGRZ.js.map +1 -0
- package/dist/chunk-VT3H43QA.js +288 -0
- package/dist/chunk-VT3H43QA.js.map +1 -0
- package/dist/chunk-W26PHBME.js +309 -0
- package/dist/chunk-W26PHBME.js.map +1 -0
- package/dist/components-BANNjAZP.d.ts +30 -0
- package/dist/cooldown.d.ts +2 -2
- package/dist/cooldown.js +1 -0
- package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet-3d.js +1 -0
- package/dist/coordinators/boundary-ricochet.d.ts +4 -4
- package/dist/coordinators/boundary-ricochet.js +3 -2
- package/dist/coordinators/first-person-shooter.js +1 -0
- package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
- package/dist/coordinators/multidirectional-space-shooter.js +5 -3
- package/dist/coordinators/top-down-shooter.d.ts +3 -3
- package/dist/coordinators/top-down-shooter.js +5 -3
- package/dist/core.d.ts +288 -8
- package/dist/core.js +480 -13
- package/dist/core.js.map +1 -1
- package/dist/destructible-3d.d.ts +32 -4
- package/dist/destructible-3d.js +2 -1
- package/dist/destructible-prebake.js +1 -0
- package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
- package/dist/first-person.d.ts +27 -38
- package/dist/first-person.js +8 -8
- package/dist/index.d.ts +14 -15
- package/dist/index.js +37 -52
- package/dist/jumper-2d.d.ts +3 -17
- package/dist/jumper-2d.js +4 -9
- package/dist/jumper-3d.d.ts +5 -39
- package/dist/jumper-3d.js +5 -10
- package/dist/{moveable-Cl9h-_w7.d.ts → moveable-XhzWPAw5.d.ts} +21 -4
- package/dist/particle-emitter/presets.js +1 -0
- package/dist/particle-emitter.d.ts +3 -3
- package/dist/particle-emitter.js +3 -2
- package/dist/platformer-2d.d.ts +13 -82
- package/dist/platformer-2d.js +4 -5
- package/dist/platformer-3d.d.ts +13 -78
- package/dist/platformer-3d.js +4 -5
- package/dist/ricochet-2d.d.ts +3 -3
- package/dist/ricochet-2d.js +4 -3
- package/dist/ricochet-3d.d.ts +3 -3
- package/dist/ricochet-3d.js +4 -3
- package/dist/runtime-2d.d.ts +2 -2
- package/dist/runtime-2d.js +1 -0
- package/dist/runtime-2d.js.map +1 -1
- package/dist/screen-visibility.d.ts +2 -2
- package/dist/screen-visibility.js +1 -0
- package/dist/screen-wrap.d.ts +2 -2
- package/dist/screen-wrap.js +4 -3
- package/dist/shooter-2d.d.ts +3 -3
- package/dist/shooter-2d.js +4 -3
- package/dist/thruster.d.ts +5 -34
- package/dist/thruster.js +4 -6
- package/dist/top-down-movement.d.ts +9 -27
- package/dist/top-down-movement.js +6 -6
- package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
- package/dist/world-boundary-2d.d.ts +2 -2
- package/dist/world-boundary-2d.js +5 -4
- package/dist/world-boundary-3d.d.ts +2 -2
- package/dist/world-boundary-3d.js +4 -3
- package/package.json +2 -3
- package/dist/chunk-27UPCP5B.js.map +0 -1
- package/dist/chunk-4L36OPY2.js.map +0 -1
- package/dist/chunk-4URF65BR.js +0 -44
- package/dist/chunk-4URF65BR.js.map +0 -1
- package/dist/chunk-5XZWTFGF.js.map +0 -1
- package/dist/chunk-67XLJ26X.js +0 -536
- package/dist/chunk-67XLJ26X.js.map +0 -1
- package/dist/chunk-75FJIUIG.js +0 -240
- package/dist/chunk-75FJIUIG.js.map +0 -1
- package/dist/chunk-A4CA35DQ.js.map +0 -1
- package/dist/chunk-BXP4K7RF.js.map +0 -1
- package/dist/chunk-F72WX4MH.js +0 -422
- package/dist/chunk-F72WX4MH.js.map +0 -1
- package/dist/chunk-GFARAJV2.js.map +0 -1
- package/dist/chunk-JXMF4NUI.js +0 -309
- package/dist/chunk-JXMF4NUI.js.map +0 -1
- package/dist/chunk-OTLSUYQQ.js +0 -29
- package/dist/chunk-OTLSUYQQ.js.map +0 -1
- package/dist/chunk-Q75LKHDF.js +0 -56
- package/dist/chunk-Q75LKHDF.js.map +0 -1
- package/dist/chunk-QDCJLJUV.js.map +0 -1
- package/dist/chunk-RDHSHEZM.js +0 -479
- package/dist/chunk-RDHSHEZM.js.map +0 -1
- package/dist/chunk-UIG7MWS2.js +0 -518
- package/dist/chunk-UIG7MWS2.js.map +0 -1
- package/dist/chunk-UL6Q5HDP.js.map +0 -1
- package/dist/chunk-VMQHNJJI.js.map +0 -1
- package/dist/chunk-WWVD5DR5.js.map +0 -1
- package/dist/chunk-Z72F2ENM.js.map +0 -1
- package/dist/components-BWG1GkZA.d.ts +0 -20
- package/dist/use-behavior-B85d5u7-.d.ts +0 -13
- /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
- /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
- /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createJumpInput3D
|
|
3
|
+
} from "./chunk-4WH2ZN7P.js";
|
|
4
|
+
import {
|
|
5
|
+
SyncStateMachine,
|
|
6
|
+
import_typescript_fsm
|
|
7
|
+
} from "./chunk-AS3HR7AS.js";
|
|
8
|
+
import {
|
|
9
|
+
STAGE_INPUT_BUTTON_JUMP,
|
|
10
|
+
readBehaviorSnapshot
|
|
11
|
+
} from "./chunk-E4X4YJZB.js";
|
|
12
|
+
import {
|
|
13
|
+
defineBehavior
|
|
14
|
+
} from "./chunk-EZNCCO4L.js";
|
|
15
|
+
|
|
16
|
+
// src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts
|
|
17
|
+
var Jumper3DState = /* @__PURE__ */ ((Jumper3DState2) => {
|
|
18
|
+
Jumper3DState2["Grounded"] = "grounded";
|
|
19
|
+
Jumper3DState2["Jumping"] = "jumping";
|
|
20
|
+
Jumper3DState2["Falling"] = "falling";
|
|
21
|
+
return Jumper3DState2;
|
|
22
|
+
})(Jumper3DState || {});
|
|
23
|
+
var Jumper3DEvent = /* @__PURE__ */ ((Jumper3DEvent2) => {
|
|
24
|
+
Jumper3DEvent2["Jump"] = "jump";
|
|
25
|
+
Jumper3DEvent2["Fall"] = "fall";
|
|
26
|
+
Jumper3DEvent2["Land"] = "land";
|
|
27
|
+
return Jumper3DEvent2;
|
|
28
|
+
})(Jumper3DEvent || {});
|
|
29
|
+
var Jumper3DFSM = class {
|
|
30
|
+
constructor(ctx) {
|
|
31
|
+
this.ctx = ctx;
|
|
32
|
+
this.machine = new SyncStateMachine(
|
|
33
|
+
"grounded" /* Grounded */,
|
|
34
|
+
[
|
|
35
|
+
// Grounded
|
|
36
|
+
(0, import_typescript_fsm.t)("grounded" /* Grounded */, "jump" /* Jump */, "jumping" /* Jumping */),
|
|
37
|
+
(0, import_typescript_fsm.t)("grounded" /* Grounded */, "fall" /* Fall */, "falling" /* Falling */),
|
|
38
|
+
(0, import_typescript_fsm.t)("grounded" /* Grounded */, "land" /* Land */, "grounded" /* Grounded */),
|
|
39
|
+
// Jumping
|
|
40
|
+
(0, import_typescript_fsm.t)("jumping" /* Jumping */, "fall" /* Fall */, "falling" /* Falling */),
|
|
41
|
+
(0, import_typescript_fsm.t)("jumping" /* Jumping */, "land" /* Land */, "grounded" /* Grounded */),
|
|
42
|
+
(0, import_typescript_fsm.t)("jumping" /* Jumping */, "jump" /* Jump */, "jumping" /* Jumping */),
|
|
43
|
+
// Falling
|
|
44
|
+
(0, import_typescript_fsm.t)("falling" /* Falling */, "land" /* Land */, "grounded" /* Grounded */),
|
|
45
|
+
(0, import_typescript_fsm.t)("falling" /* Falling */, "jump" /* Jump */, "jumping" /* Jumping */),
|
|
46
|
+
(0, import_typescript_fsm.t)("falling" /* Falling */, "fall" /* Fall */, "falling" /* Falling */)
|
|
47
|
+
]
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
ctx;
|
|
51
|
+
machine;
|
|
52
|
+
getState() {
|
|
53
|
+
return this.machine.getState();
|
|
54
|
+
}
|
|
55
|
+
dispatch(event) {
|
|
56
|
+
if (this.machine.can(event)) {
|
|
57
|
+
this.machine.syncDispatch(event);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
isJumping() {
|
|
61
|
+
return this.getState() === "jumping" /* Jumping */;
|
|
62
|
+
}
|
|
63
|
+
isFalling() {
|
|
64
|
+
return this.getState() === "falling" /* Falling */;
|
|
65
|
+
}
|
|
66
|
+
isGrounded() {
|
|
67
|
+
return this.getState() === "grounded" /* Grounded */;
|
|
68
|
+
}
|
|
69
|
+
getJumpsUsed() {
|
|
70
|
+
return this.ctx.state.jumpsUsed;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Translate a tick event into an FSM dispatch.
|
|
74
|
+
* Also handles the implicit Grounded→Falling transition when the entity
|
|
75
|
+
* is no longer grounded but no explicit event was emitted (e.g. walked
|
|
76
|
+
* off a ledge without jumping).
|
|
77
|
+
*/
|
|
78
|
+
applyTickEvent(tickEvent, isGrounded) {
|
|
79
|
+
switch (tickEvent) {
|
|
80
|
+
case "jump":
|
|
81
|
+
this.dispatch("jump" /* Jump */);
|
|
82
|
+
break;
|
|
83
|
+
case "fall":
|
|
84
|
+
this.dispatch("fall" /* Fall */);
|
|
85
|
+
break;
|
|
86
|
+
case "land":
|
|
87
|
+
this.dispatch("land" /* Land */);
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
if (!isGrounded && this.getState() === "grounded" /* Grounded */) {
|
|
91
|
+
this.dispatch("fall" /* Fall */);
|
|
92
|
+
}
|
|
93
|
+
if (isGrounded && this.getState() !== "grounded" /* Grounded */) {
|
|
94
|
+
this.dispatch("land" /* Land */);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts
|
|
102
|
+
var defaultOptions = {
|
|
103
|
+
jumpHeight: 2.5,
|
|
104
|
+
gravity: 20,
|
|
105
|
+
maxJumps: 1,
|
|
106
|
+
resetJumpsOnGround: true,
|
|
107
|
+
coyoteTimeMs: 100,
|
|
108
|
+
jumpBufferMs: 80,
|
|
109
|
+
groundRayLength: 1,
|
|
110
|
+
debugGroundProbe: false
|
|
111
|
+
};
|
|
112
|
+
var JUMPER_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:jumper-3d");
|
|
113
|
+
var Jumper3DBehaviorSystem = class {
|
|
114
|
+
constructor(wasmStage, getBehaviorLinks) {
|
|
115
|
+
this.wasmStage = wasmStage;
|
|
116
|
+
this.getBehaviorLinks = getBehaviorLinks;
|
|
117
|
+
}
|
|
118
|
+
wasmStage;
|
|
119
|
+
getBehaviorLinks;
|
|
120
|
+
attachedRuntimeSlots = /* @__PURE__ */ new Set();
|
|
121
|
+
update(_ecs, _delta) {
|
|
122
|
+
const links = this.getBehaviorLinks?.(JUMPER_BEHAVIOR_KEY);
|
|
123
|
+
if (!links) return;
|
|
124
|
+
for (const link of links) {
|
|
125
|
+
const gameEntity = link.entity;
|
|
126
|
+
const jumperRef = link.ref;
|
|
127
|
+
const options = jumperRef.options;
|
|
128
|
+
const handle = gameEntity.runtimeHandle ?? -1;
|
|
129
|
+
if (!this.wasmStage || handle < 0) continue;
|
|
130
|
+
if (!gameEntity.$jumper) {
|
|
131
|
+
gameEntity.$jumper = createJumpInput3D();
|
|
132
|
+
}
|
|
133
|
+
this.ensureWasmAttached(handle, options);
|
|
134
|
+
jumperRef.__wasmStage = this.wasmStage;
|
|
135
|
+
jumperRef.__entity = gameEntity;
|
|
136
|
+
const input = gameEntity.$jumper;
|
|
137
|
+
const jumpPressed = !!(input.jumpPressed || input.jumpHeld);
|
|
138
|
+
this.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
ensureWasmAttached(handle, options) {
|
|
142
|
+
if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
|
|
143
|
+
const jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));
|
|
144
|
+
this.wasmStage.attachJumper3D(handle, {
|
|
145
|
+
jumpForce,
|
|
146
|
+
maxJumps: options.maxJumps ?? 1,
|
|
147
|
+
gravity: options.gravity ?? 20,
|
|
148
|
+
coyoteTime: (options.coyoteTimeMs ?? 100) / 1e3,
|
|
149
|
+
jumpBufferTime: (options.jumpBufferMs ?? 80) / 1e3
|
|
150
|
+
});
|
|
151
|
+
this.attachedRuntimeSlots.add(handle);
|
|
152
|
+
}
|
|
153
|
+
destroy(_ecs) {
|
|
154
|
+
this.attachedRuntimeSlots.clear();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var Jumper3DBehavior = defineBehavior({
|
|
158
|
+
name: "jumper-3d",
|
|
159
|
+
defaultOptions,
|
|
160
|
+
systemFactory: (ctx) => new Jumper3DBehaviorSystem(
|
|
161
|
+
ctx.wasmStage ?? null,
|
|
162
|
+
ctx.getBehaviorLinks
|
|
163
|
+
),
|
|
164
|
+
// Handles read the runtime snapshot buffer (previous-step values). The
|
|
165
|
+
// Rust behavior is the single source of truth.
|
|
166
|
+
createHandle: (ref) => {
|
|
167
|
+
const jumpsUsed = () => readBehaviorSnapshot(ref)?.jumpCount ?? 0;
|
|
168
|
+
return {
|
|
169
|
+
getState: () => {
|
|
170
|
+
const snapshot = readBehaviorSnapshot(ref);
|
|
171
|
+
if (!snapshot) return "grounded" /* Grounded */;
|
|
172
|
+
if (snapshot.grounded) return "grounded" /* Grounded */;
|
|
173
|
+
return snapshot.verticalVelocity > 0 ? "jumping" /* Jumping */ : "falling" /* Falling */;
|
|
174
|
+
},
|
|
175
|
+
isJumping: () => {
|
|
176
|
+
const snapshot = readBehaviorSnapshot(ref);
|
|
177
|
+
return snapshot ? !snapshot.grounded && snapshot.verticalVelocity > 0 : false;
|
|
178
|
+
},
|
|
179
|
+
getJumpsUsed: jumpsUsed,
|
|
180
|
+
getJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed()
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
Jumper3DState,
|
|
187
|
+
Jumper3DEvent,
|
|
188
|
+
Jumper3DFSM,
|
|
189
|
+
Jumper3DBehavior
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=chunk-JGXRQUTC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts","../src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts"],"sourcesContent":["/**\n * Jumper 3D Finite State Machine\n *\n * Three high-level states driven by events emitted from the behavior tick:\n * Grounded ──Jump──▶ Jumping\n * Grounded ──Fall──▶ Falling (walked off a ledge)\n * Jumping ──Fall──▶ Falling (apex / descending)\n * Jumping ──Jump──▶ Jumping (multi-jump)\n * Jumping ──Land──▶ Grounded (rare — very short hop)\n * Falling ──Land──▶ Grounded\n * Falling ──Jump──▶ Jumping (air-jump while falling)\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState3D } from './components';\n\nexport enum Jumper3DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper3DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper3DFSMContext {\n\tstate: JumpState3D;\n}\n\nexport class Jumper3DFSM {\n\tmachine: SyncStateMachine<Jumper3DState, Jumper3DEvent, never>;\n\n\tconstructor(private ctx: Jumper3DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper3DState, Jumper3DEvent, never>(\n\t\t\tJumper3DState.Grounded,\n\t\t\t[\n\t\t\t\t// Grounded\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\n\t\t\t\t// Jumping\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\n\t\t\t\t// Falling\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper3DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper3DState.Jumping;\n\t}\n\n\tisFalling(): boolean {\n\t\treturn this.getState() === Jumper3DState.Falling;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper3DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\t/**\n\t * Translate a tick event into an FSM dispatch.\n\t * Also handles the implicit Grounded→Falling transition when the entity\n\t * is no longer grounded but no explicit event was emitted (e.g. walked\n\t * off a ledge without jumping).\n\t */\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// No explicit event — detect implicit fall\n\t\t\t\tif (!isGrounded && this.getState() === Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","/**\n * Jumper 3D Behavior Descriptor\n *\n * Type-safe descriptor for the jumper-3d behavior system.\n * Provides `entity.use()` API for composable 3D jumping.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { Jumper3DState } from './jumper-3d-fsm';\nimport {\n\tcreateJumpInput3D,\n\ttype JumpConfig3D,\n\ttype JumpInput3D,\n\ttype JumpState3D,\n} from './components';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\treadBehaviorSnapshot,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Options exposed through entity.use()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DBehaviorOptions {\n\t/** Desired peak height in world units (default: 2.5) */\n\tjumpHeight?: number;\n\t/** Gravity magnitude applied by the behavior (default: 20) */\n\tgravity?: number;\n\t/** Terminal fall speed (optional) */\n\tmaxFallSpeed?: number;\n\t/** Max concurrent jumps, 1 = single, 2 = double, etc. (default: 1) */\n\tmaxJumps?: number;\n\t/** Reset jump counter on ground (default: true) */\n\tresetJumpsOnGround?: boolean;\n\t/** Reset jump counter on wall contact (default: undefined) */\n\tresetJumpsOnWall?: boolean;\n\t/** Coyote time in ms (default: 100) */\n\tcoyoteTimeMs?: number;\n\t/** Jump buffer in ms (default: 80) */\n\tjumpBufferMs?: number;\n\t/** Min cooldown between jumps in ms (optional) */\n\tminTimeBetweenJumpsMs?: number;\n\t/** Variable jump height config (optional) */\n\tvariableJump?: JumpConfig3D['variableJump'];\n\t/** Planar control config (optional) */\n\tplanar?: JumpConfig3D['planar'];\n\t/** Fall tuning (optional) */\n\tfall?: JumpConfig3D['fall'];\n\t/** Ground-detection ray length (default: 1.0) */\n\tgroundRayLength?: number;\n\t/** Max support distance that counts as grounded and can snap to ground */\n\tsnapToGroundDistance?: number;\n\t/** Enable debug visualization for ground probe rays (default: false) */\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper3DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1.0,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-3d');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Entity shape expected by the system\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DEntity {\n\tuuid: string;\n\ttransformStore: import('../../capabilities/transform-store').TransformState;\n\tjumper: JumpConfig3D;\n\t$jumper: JumpInput3D;\n\tjumperState: JumpState3D;\n}\n\nexport function isJumper3DGrounded(params: {\n\tsupportToi?: number | null;\n\tvelocityY: number;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance &&\n\t\t\tparams.velocityY <= 0.25\n\t\t);\n\t}\n\n\treturn (\n\t\tparams.supportToi != null &&\n\t\tparams.velocityY > -2.0 &&\n\t\tparams.velocityY < 2.0\n\t);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Behavior System adapter\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Forwards jump input into the wasm runtime. The Rust `jumper_3d` Stage\n * behavior (ground probe + jump core) is the single simulation path; handles\n * read its state back via the snapshot buffer.\n */\nclass Jumper3DBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(JUMPER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper3DBehaviorOptions;\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tif (!gameEntity.$jumper) {\n\t\t\t\tgameEntity.$jumper = createJumpInput3D();\n\t\t\t}\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tjumperRef.__wasmStage = this.wasmStage;\n\t\t\tjumperRef.__entity = gameEntity;\n\t\t\tconst input = gameEntity.$jumper as JumpInput3D;\n\t\t\tconst jumpPressed = !!(input.jumpPressed || input.jumpHeld);\n\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper3DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper3D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tgravity: options.gravity ?? 20,\n\t\t\tcoyoteTime: (options.coyoteTimeMs ?? 100) / 1000,\n\t\t\tjumpBufferTime: (options.jumpBufferMs ?? 80) / 1000,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public descriptor\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Jumper3DBehavior — composable 3D jump behavior.\n *\n * Provides height-based jumping, multi-jump, coyote time, jump buffering,\n * variable jump height, configurable fall gravity, and optional air control.\n *\n * Designed to compose with any movement controller (e.g. FirstPersonBehavior)\n * — the controller writes X/Z velocity and Jumper3DBehavior writes Y velocity.\n *\n * @example\n * ```typescript\n * import { Jumper3DBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const jumper = player.use(Jumper3DBehavior, {\n * jumpHeight: 2.5,\n * gravity: 20,\n * maxJumps: 2,\n * coyoteTimeMs: 100,\n * jumpBufferMs: 80,\n * variableJump: { enabled: true, cutGravityMultiplier: 3 },\n * fall: { fallGravityMultiplier: 1.5 },\n * });\n *\n * player.onUpdate(({ inputs }) => {\n * player.$jumper.jumpPressed = inputs.p1.buttons.A.pressed;\n * player.$jumper.jumpHeld = inputs.p1.buttons.A.held > 0;\n * player.$jumper.jumpReleased = inputs.p1.buttons.A.released;\n *\n * const state = jumper.getState(); // Grounded | Jumping | Falling\n * });\n * ```\n */\nexport const Jumper3DBehavior = defineBehavior<\n\tJumper3DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper3DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper3DEntity\n>({\n\tname: 'jumper-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper3DBehaviorSystem(\n\t\t\tctx.wasmStage ?? null,\n\t\t\tctx.getBehaviorLinks,\n\t\t),\n\t// Handles read the runtime snapshot buffer (previous-step values). The\n\t// Rust behavior is the single source of truth.\n\tcreateHandle: (ref) => {\n\t\tconst jumpsUsed = () => readBehaviorSnapshot(ref)?.jumpCount ?? 0;\n\t\treturn {\n\t\t\tgetState: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (!snapshot) return Jumper3DState.Grounded;\n\t\t\t\tif (snapshot.grounded) return Jumper3DState.Grounded;\n\t\t\t\treturn snapshot.verticalVelocity > 0\n\t\t\t\t\t? Jumper3DState.Jumping\n\t\t\t\t\t: Jumper3DState.Falling;\n\t\t\t},\n\t\t\tisJumping: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\treturn snapshot ? !snapshot.grounded && snapshot.verticalVelocity > 0 : false;\n\t\t\t},\n\t\t\tgetJumpsUsed: jumpsUsed,\n\t\t\tgetJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed(),\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["Jumper3DState","Jumper3DEvent"]}
|
|
@@ -10,11 +10,6 @@ import {
|
|
|
10
10
|
} from "./chunk-EZNCCO4L.js";
|
|
11
11
|
|
|
12
12
|
// src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts
|
|
13
|
-
import {
|
|
14
|
-
ActiveCollisionTypes,
|
|
15
|
-
ColliderDesc,
|
|
16
|
-
RigidBodyDesc
|
|
17
|
-
} from "@dimforge/rapier3d-compat";
|
|
18
13
|
import {
|
|
19
14
|
DestructibleMesh,
|
|
20
15
|
FractureOptions as PinataFractureOptions
|
|
@@ -24,111 +19,14 @@ import {
|
|
|
24
19
|
BufferAttribute,
|
|
25
20
|
Group,
|
|
26
21
|
Matrix4,
|
|
27
|
-
Quaternion
|
|
22
|
+
Quaternion,
|
|
28
23
|
Vector2,
|
|
29
24
|
Vector3
|
|
30
25
|
} from "three";
|
|
31
26
|
import * as Comlink from "comlink";
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
import { Quaternion } from "three";
|
|
35
|
-
var directBodyPoseHistory = /* @__PURE__ */ new WeakMap();
|
|
36
|
-
var _previousQuaternion = new Quaternion();
|
|
37
|
-
var _currentQuaternion = new Quaternion();
|
|
38
|
-
var _renderQuaternion = new Quaternion();
|
|
39
|
-
function clonePhysicsVector3(vector) {
|
|
40
|
-
return { x: vector.x, y: vector.y, z: vector.z };
|
|
41
|
-
}
|
|
42
|
-
function clonePhysicsQuaternion(rotation) {
|
|
43
|
-
return { x: rotation.x, y: rotation.y, z: rotation.z, w: rotation.w };
|
|
44
|
-
}
|
|
45
|
-
function clonePhysicsPose(pose) {
|
|
46
|
-
return {
|
|
47
|
-
position: clonePhysicsVector3(pose.position),
|
|
48
|
-
rotation: clonePhysicsQuaternion(pose.rotation)
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
function clampInterpolationAlpha(alpha) {
|
|
52
|
-
if (!Number.isFinite(alpha)) return 0;
|
|
53
|
-
return Math.max(0, Math.min(1, alpha));
|
|
54
|
-
}
|
|
55
|
-
function capturePhysicsPose(body) {
|
|
56
|
-
return {
|
|
57
|
-
position: clonePhysicsVector3(body.translation()),
|
|
58
|
-
rotation: clonePhysicsQuaternion(body.rotation())
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function createCollapsedPhysicsPoseHistory(pose) {
|
|
62
|
-
const current = clonePhysicsPose(pose);
|
|
63
|
-
return {
|
|
64
|
-
previous: clonePhysicsPose(current),
|
|
65
|
-
current
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function collapseDirectBodyPoseHistory(body) {
|
|
69
|
-
const pose = capturePhysicsPose(body);
|
|
70
|
-
const history = directBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);
|
|
71
|
-
history.previous = clonePhysicsPose(pose);
|
|
72
|
-
history.current = clonePhysicsPose(pose);
|
|
73
|
-
directBodyPoseHistory.set(body, history);
|
|
74
|
-
return history;
|
|
75
|
-
}
|
|
76
|
-
function interpolatePhysicsPose(previous, current, alpha) {
|
|
77
|
-
const t = clampInterpolationAlpha(alpha);
|
|
78
|
-
_previousQuaternion.set(
|
|
79
|
-
previous.rotation.x,
|
|
80
|
-
previous.rotation.y,
|
|
81
|
-
previous.rotation.z,
|
|
82
|
-
previous.rotation.w
|
|
83
|
-
);
|
|
84
|
-
_currentQuaternion.set(
|
|
85
|
-
current.rotation.x,
|
|
86
|
-
current.rotation.y,
|
|
87
|
-
current.rotation.z,
|
|
88
|
-
current.rotation.w
|
|
89
|
-
);
|
|
90
|
-
_renderQuaternion.slerpQuaternions(
|
|
91
|
-
_previousQuaternion,
|
|
92
|
-
_currentQuaternion,
|
|
93
|
-
t
|
|
94
|
-
);
|
|
95
|
-
return {
|
|
96
|
-
position: {
|
|
97
|
-
x: previous.position.x + (current.position.x - previous.position.x) * t,
|
|
98
|
-
y: previous.position.y + (current.position.y - previous.position.y) * t,
|
|
99
|
-
z: previous.position.z + (current.position.z - previous.position.z) * t
|
|
100
|
-
},
|
|
101
|
-
rotation: {
|
|
102
|
-
x: _renderQuaternion.x,
|
|
103
|
-
y: _renderQuaternion.y,
|
|
104
|
-
z: _renderQuaternion.z,
|
|
105
|
-
w: _renderQuaternion.w
|
|
106
|
-
}
|
|
107
|
-
};
|
|
27
|
+
function getBodyLike(entity) {
|
|
28
|
+
return entity.body ?? null;
|
|
108
29
|
}
|
|
109
|
-
function getBodyRenderPose(body, alpha) {
|
|
110
|
-
if (isRenderPoseProvider(body)) {
|
|
111
|
-
return body.getRenderPose(alpha);
|
|
112
|
-
}
|
|
113
|
-
const history = directBodyPoseHistory.get(body);
|
|
114
|
-
if (!history) {
|
|
115
|
-
return capturePhysicsPose(body);
|
|
116
|
-
}
|
|
117
|
-
const latestPose = capturePhysicsPose(body);
|
|
118
|
-
if (!posesEqual(latestPose, history.current)) {
|
|
119
|
-
const collapsed = collapseDirectBodyPoseHistory(body);
|
|
120
|
-
return clonePhysicsPose(collapsed.current);
|
|
121
|
-
}
|
|
122
|
-
return interpolatePhysicsPose(history.previous, history.current, alpha);
|
|
123
|
-
}
|
|
124
|
-
function isRenderPoseProvider(value) {
|
|
125
|
-
return value != null && typeof value === "object" && typeof value.getPoseHistory === "function" && typeof value.getRenderPose === "function";
|
|
126
|
-
}
|
|
127
|
-
function posesEqual(a, b) {
|
|
128
|
-
return a.position.x === b.position.x && a.position.y === b.position.y && a.position.z === b.position.z && a.rotation.x === b.rotation.x && a.rotation.y === b.rotation.y && a.rotation.z === b.rotation.z && a.rotation.w === b.rotation.w;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts
|
|
132
30
|
var DESTRUCTIBLE_3D_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for(
|
|
133
31
|
"zylem:behavior:destructible-3d"
|
|
134
32
|
);
|
|
@@ -157,8 +55,7 @@ var defaultOptions = {
|
|
|
157
55
|
innerMaterial: null,
|
|
158
56
|
collider: {
|
|
159
57
|
shape: "convexHull",
|
|
160
|
-
sensor: false
|
|
161
|
-
activeCollisionTypes: ActiveCollisionTypes.DEFAULT
|
|
58
|
+
sensor: false
|
|
162
59
|
},
|
|
163
60
|
fragmentPhysics: DEFAULT_FRAGMENT_PHYSICS
|
|
164
61
|
};
|
|
@@ -299,8 +196,7 @@ function resolveColliderOptions(input) {
|
|
|
299
196
|
return {
|
|
300
197
|
shape: input?.shape ?? defaultOptions.collider?.shape ?? "convexHull",
|
|
301
198
|
sensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,
|
|
302
|
-
collisionGroups: input?.collisionGroups
|
|
303
|
-
activeCollisionTypes: input?.activeCollisionTypes ?? defaultOptions.collider?.activeCollisionTypes ?? ActiveCollisionTypes.DEFAULT
|
|
199
|
+
collisionGroups: input?.collisionGroups
|
|
304
200
|
};
|
|
305
201
|
}
|
|
306
202
|
function resolveFragmentPhysicsOptions(input) {
|
|
@@ -445,21 +341,6 @@ function instantiatePrebakedFragments(mesh, innerMaterial, templates) {
|
|
|
445
341
|
return fragment;
|
|
446
342
|
});
|
|
447
343
|
}
|
|
448
|
-
function tagConvexHullCollider(colliderDesc, vertices) {
|
|
449
|
-
colliderDesc.__zylemShapeData = {
|
|
450
|
-
shape: "convexHull",
|
|
451
|
-
vertices: Array.from(vertices)
|
|
452
|
-
};
|
|
453
|
-
return colliderDesc;
|
|
454
|
-
}
|
|
455
|
-
function tagTrimeshCollider(colliderDesc, vertices, indices) {
|
|
456
|
-
colliderDesc.__zylemShapeData = {
|
|
457
|
-
shape: "trimesh",
|
|
458
|
-
vertices: Array.from(vertices),
|
|
459
|
-
indices: Array.from(indices)
|
|
460
|
-
};
|
|
461
|
-
return colliderDesc;
|
|
462
|
-
}
|
|
463
344
|
function getFragmentVertices(fragment) {
|
|
464
345
|
const position = fragment.geometry.getAttribute("position");
|
|
465
346
|
if (!(position instanceof BufferAttribute)) {
|
|
@@ -478,62 +359,56 @@ function getFragmentIndices(fragment) {
|
|
|
478
359
|
}
|
|
479
360
|
return Uint32Array.from({ length: position.count }, (_value, index) => index);
|
|
480
361
|
}
|
|
481
|
-
function
|
|
362
|
+
function createCuboidColliderShape(fragment) {
|
|
482
363
|
const bounds = fragment.geometry.boundingBox ?? new Box3();
|
|
483
364
|
if (!fragment.geometry.boundingBox) {
|
|
484
365
|
fragment.geometry.computeBoundingBox();
|
|
485
366
|
}
|
|
486
367
|
bounds.copy(fragment.geometry.boundingBox ?? bounds);
|
|
487
368
|
const size = bounds.getSize(new Vector3());
|
|
488
|
-
return
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
369
|
+
return {
|
|
370
|
+
type: "box",
|
|
371
|
+
halfExtents: [
|
|
372
|
+
Math.max(size.x / 2, 1e-3),
|
|
373
|
+
Math.max(size.y / 2, 1e-3),
|
|
374
|
+
Math.max(size.z / 2, 1e-3)
|
|
375
|
+
]
|
|
376
|
+
};
|
|
493
377
|
}
|
|
494
|
-
function
|
|
378
|
+
function createFragmentColliderDefinition(fragment, options, translation) {
|
|
495
379
|
const resolved = resolveColliderOptions(options);
|
|
496
380
|
const vertices = getFragmentVertices(fragment);
|
|
497
|
-
let
|
|
498
|
-
if (resolved.shape === "convexHull") {
|
|
499
|
-
|
|
500
|
-
if (colliderDesc) {
|
|
501
|
-
colliderDesc = tagConvexHullCollider(colliderDesc, vertices);
|
|
502
|
-
}
|
|
381
|
+
let shape = null;
|
|
382
|
+
if (resolved.shape === "convexHull" && vertices.length >= 12) {
|
|
383
|
+
shape = { type: "convexHull", vertices };
|
|
503
384
|
}
|
|
504
|
-
if (!
|
|
505
|
-
|
|
506
|
-
colliderDesc = tagTrimeshCollider(
|
|
507
|
-
ColliderDesc.trimesh(vertices, indices),
|
|
508
|
-
vertices,
|
|
509
|
-
indices
|
|
510
|
-
);
|
|
385
|
+
if (!shape && resolved.shape === "trimesh") {
|
|
386
|
+
shape = { type: "trimesh", vertices, indices: getFragmentIndices(fragment) };
|
|
511
387
|
}
|
|
512
|
-
if (!
|
|
513
|
-
|
|
388
|
+
if (!shape) {
|
|
389
|
+
shape = createCuboidColliderShape(fragment);
|
|
514
390
|
}
|
|
391
|
+
const definition = {
|
|
392
|
+
shape,
|
|
393
|
+
sensor: resolved.sensor
|
|
394
|
+
};
|
|
515
395
|
if (translation) {
|
|
516
|
-
|
|
517
|
-
translation.x,
|
|
518
|
-
translation.y,
|
|
519
|
-
translation.z
|
|
520
|
-
);
|
|
396
|
+
definition.offset = [translation.x, translation.y, translation.z];
|
|
521
397
|
}
|
|
522
|
-
colliderDesc.setSensor(resolved.sensor);
|
|
523
398
|
if (resolved.collisionGroups !== void 0) {
|
|
524
|
-
|
|
399
|
+
definition.collisionGroups = resolved.collisionGroups;
|
|
525
400
|
}
|
|
526
|
-
|
|
527
|
-
return colliderDesc;
|
|
401
|
+
return definition;
|
|
528
402
|
}
|
|
529
403
|
function snapshotBody(entity) {
|
|
530
|
-
|
|
404
|
+
const body = getBodyLike(entity);
|
|
405
|
+
if (!body) {
|
|
531
406
|
return null;
|
|
532
407
|
}
|
|
533
|
-
const translation =
|
|
534
|
-
const rotation =
|
|
535
|
-
const linearVelocity =
|
|
536
|
-
const angularVelocity =
|
|
408
|
+
const translation = body.translation();
|
|
409
|
+
const rotation = body.rotation();
|
|
410
|
+
const linearVelocity = body.linvel();
|
|
411
|
+
const angularVelocity = body.angvel();
|
|
537
412
|
return {
|
|
538
413
|
translation: { ...translation },
|
|
539
414
|
rotation: { ...rotation },
|
|
@@ -542,13 +417,14 @@ function snapshotBody(entity) {
|
|
|
542
417
|
};
|
|
543
418
|
}
|
|
544
419
|
function restoreBodySnapshot(entity, snapshot) {
|
|
545
|
-
|
|
420
|
+
const body = getBodyLike(entity);
|
|
421
|
+
if (!snapshot || !body) {
|
|
546
422
|
return;
|
|
547
423
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
424
|
+
body.setTranslation(snapshot.translation, true);
|
|
425
|
+
body.setRotation(snapshot.rotation, true);
|
|
426
|
+
body.setLinvel(snapshot.linearVelocity, true);
|
|
427
|
+
body.setAngvel(snapshot.angularVelocity, true);
|
|
552
428
|
}
|
|
553
429
|
function attachEntityPhysics(ref, entity, snapshot) {
|
|
554
430
|
const world = getBehaviorWorld(ref);
|
|
@@ -574,7 +450,7 @@ function disposeFragments(fragments) {
|
|
|
574
450
|
fragment.geometry.dispose();
|
|
575
451
|
}
|
|
576
452
|
}
|
|
577
|
-
function syncRuntimeFragmentEntityTransform(entity,
|
|
453
|
+
function syncRuntimeFragmentEntityTransform(entity, _interpolationAlpha) {
|
|
578
454
|
const target = entity.group ?? entity.mesh;
|
|
579
455
|
if (!target) {
|
|
580
456
|
return;
|
|
@@ -583,14 +459,7 @@ function syncRuntimeFragmentEntityTransform(entity, interpolationAlpha) {
|
|
|
583
459
|
if (wasmPose && entity.runtimeHandle >= 0) {
|
|
584
460
|
target.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);
|
|
585
461
|
target.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
if (!entity.body) {
|
|
589
|
-
return;
|
|
590
462
|
}
|
|
591
|
-
const pose = getBodyRenderPose(entity.body, interpolationAlpha);
|
|
592
|
-
target.position.set(pose.position.x, pose.position.y, pose.position.z);
|
|
593
|
-
target.quaternion.set(pose.rotation.x, pose.rotation.y, pose.rotation.z, pose.rotation.w);
|
|
594
463
|
}
|
|
595
464
|
function bakeScaleIntoFragmentGeometry(fragment, scale) {
|
|
596
465
|
if (Math.abs(scale.x - 1) < 1e-6 && Math.abs(scale.y - 1) < 1e-6 && Math.abs(scale.z - 1) < 1e-6) {
|
|
@@ -619,7 +488,7 @@ function computeFragmentWorldPose(root, fragment) {
|
|
|
619
488
|
fragment.updateMatrix();
|
|
620
489
|
const worldMatrix = new Matrix4().copy(root.matrixWorld).multiply(fragment.matrix);
|
|
621
490
|
const position = new Vector3();
|
|
622
|
-
const rotation = new
|
|
491
|
+
const rotation = new Quaternion();
|
|
623
492
|
const scale = new Vector3();
|
|
624
493
|
worldMatrix.decompose(position, rotation, scale);
|
|
625
494
|
return {
|
|
@@ -699,18 +568,19 @@ function createRuntimeFragmentEntity(createEntity, parentEntity, fragment, index
|
|
|
699
568
|
} else if (fragment.material) {
|
|
700
569
|
entity.materials = [fragment.material];
|
|
701
570
|
}
|
|
702
|
-
entity.colliderDesc =
|
|
571
|
+
entity.colliderDesc = createFragmentColliderDefinition(fragment, colliderOptions);
|
|
703
572
|
entity.colliderDescs = [entity.colliderDesc];
|
|
704
|
-
|
|
573
|
+
const bodyDefinition = {
|
|
574
|
+
kind: "dynamic",
|
|
575
|
+
position: [position.x, position.y, position.z],
|
|
576
|
+
rotation: [rotation.x, rotation.y, rotation.z, rotation.w],
|
|
577
|
+
canSleep: false,
|
|
578
|
+
ccdEnabled: true
|
|
579
|
+
};
|
|
580
|
+
entity.bodyDesc = bodyDefinition;
|
|
705
581
|
fragment.position.set(0, 0, 0);
|
|
706
582
|
fragment.quaternion.identity();
|
|
707
583
|
fragment.scale.set(1, 1, 1);
|
|
708
|
-
entity.bodyDesc.setRotation({
|
|
709
|
-
x: rotation.x,
|
|
710
|
-
y: rotation.y,
|
|
711
|
-
z: rotation.z,
|
|
712
|
-
w: rotation.w
|
|
713
|
-
});
|
|
714
584
|
return entity;
|
|
715
585
|
}
|
|
716
586
|
function unlockIndependentFragmentPhysicsBody(entity) {
|
|
@@ -834,7 +704,7 @@ function fractureCompoundEntity(ref, entity, root, fragments, state) {
|
|
|
834
704
|
root.add(fragmentContainer);
|
|
835
705
|
state.fragmentContainer = fragmentContainer;
|
|
836
706
|
state.fractureMode = "compound";
|
|
837
|
-
const colliderDescs = fragments.map((fragment) =>
|
|
707
|
+
const colliderDescs = fragments.map((fragment) => createFragmentColliderDefinition(
|
|
838
708
|
fragment,
|
|
839
709
|
ref.options.collider,
|
|
840
710
|
fragment.position
|
|
@@ -893,8 +763,9 @@ function fractureIndependentEntity(ref, entity, root, fractureOptions, fragments
|
|
|
893
763
|
physicsOptions,
|
|
894
764
|
sourceVelocity
|
|
895
765
|
);
|
|
896
|
-
fragmentEntity
|
|
897
|
-
|
|
766
|
+
const fragmentBody = getBodyLike(fragmentEntity);
|
|
767
|
+
fragmentBody?.setLinvel(linearVelocity, true);
|
|
768
|
+
fragmentBody?.setAngvel(
|
|
898
769
|
computeFragmentAngularVelocity(
|
|
899
770
|
index,
|
|
900
771
|
physicsOptions.angularVelocity
|
|
@@ -1202,4 +1073,4 @@ export {
|
|
|
1202
1073
|
DestructibleMesh2 as DestructibleMesh,
|
|
1203
1074
|
FractureOptions
|
|
1204
1075
|
};
|
|
1205
|
-
//# sourceMappingURL=chunk-
|
|
1076
|
+
//# sourceMappingURL=chunk-JVADRLWX.js.map
|