@combos-fun/plugin-cannon 0.0.41 → 0.0.44
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 +1 -1
- package/agent-skill.md +79 -16
- package/combos-plugin.json +8 -2
- package/dist/plugin-cannon.cjs.js +694 -76
- package/dist/plugin-cannon.cjs.js.map +1 -1
- package/dist/plugin-cannon.cjs.prod.js +1 -1
- package/dist/plugin-cannon.d.ts +170 -33
- package/dist/plugin-cannon.esm.js +693 -77
- package/dist/plugin-cannon.esm.js.map +1 -1
- package/package.json +7 -3
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
var tslib = require('tslib');
|
|
4
4
|
var engine = require('@combos-fun/engine');
|
|
5
5
|
var CANNON = require('cannon-es');
|
|
6
|
+
var three = require('three');
|
|
7
|
+
var pluginRenderer3d = require('@combos-fun/plugin-renderer-3d');
|
|
8
|
+
var ConvexGeometry_js = require('three/addons/geometries/ConvexGeometry.js');
|
|
6
9
|
|
|
7
10
|
function _interopNamespace(e) {
|
|
8
11
|
if (e && e.__esModule) return e;
|
|
@@ -30,6 +33,10 @@ exports.Physics3DType = void 0;
|
|
|
30
33
|
Physics3DType["SPHERE"] = "sphere";
|
|
31
34
|
Physics3DType["CYLINDER"] = "cylinder";
|
|
32
35
|
Physics3DType["PLANE"] = "plane";
|
|
36
|
+
Physics3DType["CONE"] = "cone";
|
|
37
|
+
Physics3DType["TORUS"] = "torus";
|
|
38
|
+
Physics3DType["CAPSULE"] = "capsule";
|
|
39
|
+
Physics3DType["COMPOUND"] = "compound";
|
|
33
40
|
})(exports.Physics3DType || (exports.Physics3DType = {}));
|
|
34
41
|
class Physics3D extends engine.Component {
|
|
35
42
|
constructor() {
|
|
@@ -42,10 +49,14 @@ class Physics3D extends engine.Component {
|
|
|
42
49
|
this.rotationY = 0;
|
|
43
50
|
this.rotationZ = 0;
|
|
44
51
|
this._euler = new CANNON__namespace.Vec3();
|
|
52
|
+
this._worldPos = new three.Vector3();
|
|
53
|
+
this._worldQuat = new three.Quaternion();
|
|
54
|
+
this._bodyQuat = new three.Quaternion();
|
|
55
|
+
this._localEuler = new three.Euler();
|
|
45
56
|
}
|
|
46
57
|
static { this.componentName = 'Physics3D'; }
|
|
47
58
|
init(params) {
|
|
48
|
-
this.bodyParams = params;
|
|
59
|
+
this.bodyParams = params || {};
|
|
49
60
|
}
|
|
50
61
|
update() {
|
|
51
62
|
if (this.body && this.gameObject) {
|
|
@@ -60,7 +71,8 @@ class Physics3D extends engine.Component {
|
|
|
60
71
|
this.rotationY = this._euler.y;
|
|
61
72
|
this.rotationZ = this._euler.z;
|
|
62
73
|
}
|
|
63
|
-
|
|
74
|
+
this._worldPoseToLocalIfParented();
|
|
75
|
+
// Auto-sync to sibling Transform3D / visual components on the same GameObject
|
|
64
76
|
this._syncToSiblings();
|
|
65
77
|
}
|
|
66
78
|
}
|
|
@@ -69,6 +81,28 @@ class Physics3D extends engine.Component {
|
|
|
69
81
|
this.world.removeBody(this.body);
|
|
70
82
|
}
|
|
71
83
|
}
|
|
84
|
+
_worldPoseToLocalIfParented() {
|
|
85
|
+
const renderer = this.game?.getSystem(pluginRenderer3d.Renderer3DSystem);
|
|
86
|
+
const node = renderer?.threeContext?.object3DFor(this.gameObject.id);
|
|
87
|
+
const scene = renderer?.threeContext?.scene;
|
|
88
|
+
if (!node?.parent || node.parent === scene)
|
|
89
|
+
return;
|
|
90
|
+
node.parent.updateWorldMatrix(true, false);
|
|
91
|
+
this._worldPos.set(this.positionX, this.positionY, this.positionZ);
|
|
92
|
+
node.parent.worldToLocal(this._worldPos);
|
|
93
|
+
this.positionX = this._worldPos.x;
|
|
94
|
+
this.positionY = this._worldPos.y;
|
|
95
|
+
this.positionZ = this._worldPos.z;
|
|
96
|
+
if (!this.bodyParams.stopRotation) {
|
|
97
|
+
node.parent.getWorldQuaternion(this._worldQuat).invert();
|
|
98
|
+
this._bodyQuat.set(this.body.quaternion.x, this.body.quaternion.y, this.body.quaternion.z, this.body.quaternion.w);
|
|
99
|
+
this._bodyQuat.premultiply(this._worldQuat);
|
|
100
|
+
this._localEuler.setFromQuaternion(this._bodyQuat);
|
|
101
|
+
this.rotationX = this._localEuler.x;
|
|
102
|
+
this.rotationY = this._localEuler.y;
|
|
103
|
+
this.rotationZ = this._localEuler.z;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
72
106
|
_syncToSiblings() {
|
|
73
107
|
const components = this.gameObject.components;
|
|
74
108
|
if (!components)
|
|
@@ -91,74 +125,385 @@ class Physics3D extends engine.Component {
|
|
|
91
125
|
}
|
|
92
126
|
}
|
|
93
127
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
128
|
+
const TYPE_BY_SHAPE = {
|
|
129
|
+
box: exports.Physics3DType.BOX,
|
|
130
|
+
sphere: exports.Physics3DType.SPHERE,
|
|
131
|
+
cylinder: exports.Physics3DType.CYLINDER,
|
|
132
|
+
plane: exports.Physics3DType.PLANE,
|
|
133
|
+
cone: exports.Physics3DType.CONE,
|
|
134
|
+
torus: exports.Physics3DType.TORUS,
|
|
135
|
+
capsule: exports.Physics3DType.CAPSULE,
|
|
136
|
+
compound: exports.Physics3DType.COMPOUND,
|
|
137
|
+
};
|
|
138
|
+
function normalizeType(type) {
|
|
139
|
+
if (!type)
|
|
140
|
+
return exports.Physics3DType.BOX;
|
|
141
|
+
return TYPE_BY_SHAPE[type] ?? type;
|
|
142
|
+
}
|
|
143
|
+
function torusTube(radius, tube) {
|
|
144
|
+
return tube && tube > 0 ? tube : radius * 0.4;
|
|
145
|
+
}
|
|
146
|
+
function dimsFromParams(params, fallback) {
|
|
147
|
+
const radius = params.radius ?? fallback?.radius ?? 0.5;
|
|
148
|
+
return {
|
|
149
|
+
width: params.width ?? fallback?.width ?? 1,
|
|
150
|
+
height: params.height ?? fallback?.height ?? 1,
|
|
151
|
+
depth: params.depth ?? fallback?.depth ?? 1,
|
|
152
|
+
radius,
|
|
153
|
+
radiusTop: params.radiusTop ?? radius,
|
|
154
|
+
radiusBottom: params.radiusBottom ?? radius,
|
|
155
|
+
segments: Math.max(6, Math.round(params.segments ?? fallback?.segments ?? 12)),
|
|
156
|
+
tube: torusTube(radius, params.tube ?? fallback?.tube),
|
|
157
|
+
finite: params.finite ?? fallback?.finite,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function offsetFromPart(part) {
|
|
161
|
+
return new CANNON__namespace.Vec3(part.positionX ?? part.position?.x ?? 0, part.positionY ?? part.position?.y ?? 0, part.positionZ ?? part.position?.z ?? 0);
|
|
162
|
+
}
|
|
163
|
+
function quaternionFromPart(part) {
|
|
164
|
+
const x = part.rotationX ?? part.rotation?.x ?? 0;
|
|
165
|
+
const y = part.rotationY ?? part.rotation?.y ?? 0;
|
|
166
|
+
const z = part.rotationZ ?? part.rotation?.z ?? 0;
|
|
167
|
+
if (!x && !y && !z)
|
|
168
|
+
return undefined;
|
|
169
|
+
const q = new CANNON__namespace.Quaternion();
|
|
170
|
+
q.setFromEuler(x, y, z);
|
|
171
|
+
return q;
|
|
172
|
+
}
|
|
173
|
+
function placedShapesForType(type, dims) {
|
|
174
|
+
const kind = normalizeType(type);
|
|
175
|
+
switch (kind) {
|
|
176
|
+
case exports.Physics3DType.SPHERE:
|
|
177
|
+
return [{ shape: new CANNON__namespace.Sphere(dims.radius) }];
|
|
178
|
+
case exports.Physics3DType.CYLINDER:
|
|
179
|
+
return [{
|
|
180
|
+
shape: new CANNON__namespace.Cylinder(dims.radiusTop, dims.radiusBottom, dims.height, dims.segments),
|
|
181
|
+
}];
|
|
182
|
+
case exports.Physics3DType.CONE:
|
|
183
|
+
return [{
|
|
184
|
+
shape: new CANNON__namespace.Cylinder(0.001, dims.radius, dims.height, dims.segments),
|
|
185
|
+
}];
|
|
186
|
+
case exports.Physics3DType.PLANE:
|
|
187
|
+
if (dims.finite) {
|
|
188
|
+
return [{ shape: new CANNON__namespace.Box(new CANNON__namespace.Vec3(dims.width / 2, dims.height / 2, 0.01)) }];
|
|
107
189
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
190
|
+
return [{ shape: new CANNON__namespace.Plane() }];
|
|
191
|
+
case exports.Physics3DType.TORUS:
|
|
192
|
+
return torusShapes(dims);
|
|
193
|
+
case exports.Physics3DType.CAPSULE:
|
|
194
|
+
return capsuleShapes(dims);
|
|
195
|
+
case exports.Physics3DType.BOX:
|
|
196
|
+
default:
|
|
197
|
+
return [{
|
|
198
|
+
shape: new CANNON__namespace.Box(new CANNON__namespace.Vec3(dims.width / 2, dims.height / 2, dims.depth / 2)),
|
|
199
|
+
}];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function torusShapes(dims) {
|
|
203
|
+
const n = Math.max(8, Math.min(12, dims.segments));
|
|
204
|
+
const placed = [];
|
|
205
|
+
for (let i = 0; i < n; i++) {
|
|
206
|
+
const angle = (i / n) * Math.PI * 2;
|
|
207
|
+
placed.push({
|
|
208
|
+
shape: new CANNON__namespace.Sphere(dims.tube),
|
|
209
|
+
offset: new CANNON__namespace.Vec3(Math.cos(angle) * dims.radius, 0, Math.sin(angle) * dims.radius),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return placed;
|
|
213
|
+
}
|
|
214
|
+
function capsuleShapes(dims) {
|
|
215
|
+
const cyl = Math.max(0, dims.height - 2 * dims.radius);
|
|
216
|
+
const placed = [];
|
|
217
|
+
if (cyl > 0.001) {
|
|
218
|
+
placed.push({
|
|
219
|
+
shape: new CANNON__namespace.Cylinder(dims.radius, dims.radius, cyl, dims.segments),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
placed.push({
|
|
223
|
+
shape: new CANNON__namespace.Sphere(dims.radius),
|
|
224
|
+
offset: new CANNON__namespace.Vec3(0, cyl / 2, 0),
|
|
225
|
+
});
|
|
226
|
+
placed.push({
|
|
227
|
+
shape: new CANNON__namespace.Sphere(dims.radius),
|
|
228
|
+
offset: new CANNON__namespace.Vec3(0, -cyl / 2, 0),
|
|
229
|
+
});
|
|
230
|
+
return placed;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const _box = new three.Box3();
|
|
234
|
+
const _size = new three.Vector3();
|
|
235
|
+
const _center = new three.Vector3();
|
|
236
|
+
const _vertex = new three.Vector3();
|
|
237
|
+
function withIdentityPose(root, fn) {
|
|
238
|
+
const px = root.position.x;
|
|
239
|
+
const py = root.position.y;
|
|
240
|
+
const pz = root.position.z;
|
|
241
|
+
const rx = root.rotation.x;
|
|
242
|
+
const ry = root.rotation.y;
|
|
243
|
+
const rz = root.rotation.z;
|
|
244
|
+
root.position.set(0, 0, 0);
|
|
245
|
+
root.rotation.set(0, 0, 0);
|
|
246
|
+
root.updateMatrixWorld(true);
|
|
247
|
+
try {
|
|
248
|
+
return fn();
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
root.position.set(px, py, pz);
|
|
252
|
+
root.rotation.set(rx, ry, rz);
|
|
253
|
+
root.updateMatrixWorld(true);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function addModelCollider(body, root, collider) {
|
|
257
|
+
return withIdentityPose(root, () => {
|
|
258
|
+
if (collider === 'trimesh') {
|
|
259
|
+
return addTrimesh(body, root);
|
|
260
|
+
}
|
|
261
|
+
if (collider === 'hull') {
|
|
262
|
+
return addHull(body, root);
|
|
263
|
+
}
|
|
264
|
+
return addAabb(body, root);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function addAabb(body, root) {
|
|
268
|
+
_box.setFromObject(root);
|
|
269
|
+
if (_box.isEmpty())
|
|
270
|
+
return false;
|
|
271
|
+
_box.getSize(_size);
|
|
272
|
+
_box.getCenter(_center);
|
|
273
|
+
if (_size.x <= 0 && _size.y <= 0 && _size.z <= 0)
|
|
274
|
+
return false;
|
|
275
|
+
body.addShape(new CANNON__namespace.Box(new CANNON__namespace.Vec3(Math.max(_size.x / 2, 0.01), Math.max(_size.y / 2, 0.01), Math.max(_size.z / 2, 0.01))), new CANNON__namespace.Vec3(_center.x, _center.y, _center.z));
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
function addTrimesh(body, root) {
|
|
279
|
+
let added = false;
|
|
280
|
+
root.traverse((child) => {
|
|
281
|
+
const mesh = child;
|
|
282
|
+
const geometry = mesh.geometry;
|
|
283
|
+
const position = geometry?.attributes?.position;
|
|
284
|
+
if (!position)
|
|
285
|
+
return;
|
|
286
|
+
const vertices = [];
|
|
287
|
+
for (let i = 0; i < position.count; i++) {
|
|
288
|
+
_vertex.fromBufferAttribute(position, i).applyMatrix4(mesh.matrixWorld);
|
|
289
|
+
vertices.push(_vertex.x, _vertex.y, _vertex.z);
|
|
290
|
+
}
|
|
291
|
+
const indices = [];
|
|
292
|
+
if (geometry.index) {
|
|
293
|
+
const array = geometry.index.array;
|
|
294
|
+
for (let i = 0; i < array.length; i++) {
|
|
295
|
+
indices.push(array[i]);
|
|
115
296
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
for (let i = 0; i < position.count; i++) {
|
|
300
|
+
indices.push(i);
|
|
119
301
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
302
|
+
}
|
|
303
|
+
if (indices.length < 3)
|
|
304
|
+
return;
|
|
305
|
+
body.addShape(new CANNON__namespace.Trimesh(vertices, indices));
|
|
306
|
+
added = true;
|
|
307
|
+
});
|
|
308
|
+
return added;
|
|
309
|
+
}
|
|
310
|
+
function addHull(body, root) {
|
|
311
|
+
const points = [];
|
|
312
|
+
root.traverse((child) => {
|
|
313
|
+
const mesh = child;
|
|
314
|
+
const position = mesh.geometry?.attributes?.position;
|
|
315
|
+
if (!position)
|
|
316
|
+
return;
|
|
317
|
+
const stride = position.count > 128 ? Math.ceil(position.count / 128) : 1;
|
|
318
|
+
for (let i = 0; i < position.count; i += stride) {
|
|
319
|
+
points.push(_vertex.fromBufferAttribute(position, i).applyMatrix4(mesh.matrixWorld).clone());
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
if (points.length < 4) {
|
|
323
|
+
return addAabb(body, root);
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
const geometry = new ConvexGeometry_js.ConvexGeometry(points);
|
|
327
|
+
const pos = geometry.attributes.position;
|
|
328
|
+
const vertices = [];
|
|
329
|
+
const indexOf = new Map();
|
|
330
|
+
const add = (x, y, z) => {
|
|
331
|
+
const key = `${x.toFixed(5)},${y.toFixed(5)},${z.toFixed(5)}`;
|
|
332
|
+
const existing = indexOf.get(key);
|
|
333
|
+
if (existing != null)
|
|
334
|
+
return existing;
|
|
335
|
+
const i = vertices.length;
|
|
336
|
+
vertices.push(new CANNON__namespace.Vec3(x, y, z));
|
|
337
|
+
indexOf.set(key, i);
|
|
338
|
+
return i;
|
|
339
|
+
};
|
|
340
|
+
const faces = [];
|
|
341
|
+
if (geometry.index) {
|
|
342
|
+
const array = geometry.index.array;
|
|
343
|
+
for (let i = 0; i + 2 < array.length; i += 3) {
|
|
344
|
+
faces.push([
|
|
345
|
+
add(pos.getX(array[i]), pos.getY(array[i]), pos.getZ(array[i])),
|
|
346
|
+
add(pos.getX(array[i + 1]), pos.getY(array[i + 1]), pos.getZ(array[i + 1])),
|
|
347
|
+
add(pos.getX(array[i + 2]), pos.getY(array[i + 2]), pos.getZ(array[i + 2])),
|
|
348
|
+
]);
|
|
127
349
|
}
|
|
128
350
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
351
|
+
else {
|
|
352
|
+
for (let i = 0; i + 2 < pos.count; i += 3) {
|
|
353
|
+
faces.push([
|
|
354
|
+
add(pos.getX(i), pos.getY(i), pos.getZ(i)),
|
|
355
|
+
add(pos.getX(i + 1), pos.getY(i + 1), pos.getZ(i + 1)),
|
|
356
|
+
add(pos.getX(i + 2), pos.getY(i + 2), pos.getZ(i + 2)),
|
|
357
|
+
]);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
geometry.dispose();
|
|
361
|
+
if (vertices.length < 4 || faces.length < 4) {
|
|
362
|
+
return addAabb(body, root);
|
|
363
|
+
}
|
|
364
|
+
body.addShape(new CANNON__namespace.ConvexPolyhedron({ vertices, faces }));
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return addAabb(body, root);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function resolveCollider(params, model) {
|
|
373
|
+
if (params.collider)
|
|
374
|
+
return params.collider;
|
|
375
|
+
if (params.type || (params.parts && params.parts.length > 0))
|
|
376
|
+
return 'manual';
|
|
377
|
+
return model ? 'aabb' : 'manual';
|
|
378
|
+
}
|
|
379
|
+
function resolveType(params, graphics) {
|
|
380
|
+
if (params.type)
|
|
381
|
+
return normalizeType(params.type);
|
|
382
|
+
if ((params.parts && params.parts.length > 0) || (graphics?.parts && graphics.parts.length > 0)) {
|
|
383
|
+
return exports.Physics3DType.COMPOUND;
|
|
384
|
+
}
|
|
385
|
+
if (graphics?.shape)
|
|
386
|
+
return normalizeType(graphics.shape);
|
|
387
|
+
return exports.Physics3DType.BOX;
|
|
388
|
+
}
|
|
389
|
+
function meshColliderFingerprint(collider, model) {
|
|
390
|
+
if (!model || collider === 'manual')
|
|
391
|
+
return undefined;
|
|
392
|
+
return `${collider}:${model.resource}:${model.scaleX}:${model.scaleY}:${model.scaleZ}`;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function applyBodyOptions(body, options) {
|
|
396
|
+
if (!options)
|
|
397
|
+
return;
|
|
398
|
+
if (options.friction !== undefined) {
|
|
399
|
+
body.material = new CANNON__namespace.Material({
|
|
400
|
+
friction: options.friction,
|
|
401
|
+
restitution: options.restitution ?? 0.3,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
if (options.restitution !== undefined && !body.material) {
|
|
405
|
+
body.material = new CANNON__namespace.Material({ friction: 0.3, restitution: options.restitution });
|
|
406
|
+
}
|
|
407
|
+
if (options.linearDamping !== undefined)
|
|
408
|
+
body.linearDamping = options.linearDamping;
|
|
409
|
+
if (options.angularDamping !== undefined)
|
|
410
|
+
body.angularDamping = options.angularDamping;
|
|
411
|
+
if (options.fixedRotation !== undefined)
|
|
412
|
+
body.fixedRotation = options.fixedRotation;
|
|
413
|
+
body.updateMassProperties();
|
|
414
|
+
}
|
|
415
|
+
function addPlaced(body, type, dims, part) {
|
|
416
|
+
const placed = placedShapesForType(type, dims);
|
|
417
|
+
const extraOffset = part ? offsetFromPart(part) : new CANNON__namespace.Vec3();
|
|
418
|
+
const extraQuat = part ? quaternionFromPart(part) : undefined;
|
|
419
|
+
for (const item of placed) {
|
|
420
|
+
const local = (item.offset ? item.offset.clone() : new CANNON__namespace.Vec3());
|
|
421
|
+
if (extraQuat)
|
|
422
|
+
extraQuat.vmult(local, local);
|
|
423
|
+
const offset = extraOffset.vadd(local);
|
|
424
|
+
const quat = extraQuat && item.quaternion
|
|
425
|
+
? extraQuat.mult(item.quaternion)
|
|
426
|
+
: (extraQuat || item.quaternion);
|
|
427
|
+
body.addShape(item.shape, offset, quat);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
class BodiesFactory {
|
|
431
|
+
create(component, context = {}) {
|
|
432
|
+
const { bodyParams } = component;
|
|
433
|
+
const graphics = context.graphics;
|
|
434
|
+
const model = context.model;
|
|
435
|
+
const collider = resolveCollider(bodyParams, model);
|
|
436
|
+
if (collider !== 'manual') {
|
|
437
|
+
if (!context.modelGroup)
|
|
438
|
+
return null;
|
|
439
|
+
let mass = bodyParams.mass ?? 1;
|
|
440
|
+
if (collider === 'trimesh' && mass !== 0) {
|
|
441
|
+
mass = 0;
|
|
442
|
+
}
|
|
443
|
+
const body = this.createBodyShell(component, mass, context.pose || graphics);
|
|
444
|
+
const ok = addModelCollider(body, context.modelGroup, collider);
|
|
445
|
+
if (!ok)
|
|
446
|
+
return null;
|
|
447
|
+
applyBodyOptions(body, bodyParams.bodyOptions);
|
|
448
|
+
component.meshColliderKey = meshColliderFingerprint(collider, model);
|
|
449
|
+
return body;
|
|
450
|
+
}
|
|
451
|
+
const type = resolveType(bodyParams, graphics);
|
|
452
|
+
const dims = dimsFromParams(bodyParams, {
|
|
453
|
+
width: graphics?.width,
|
|
454
|
+
height: graphics?.height,
|
|
455
|
+
depth: graphics?.depth,
|
|
456
|
+
radius: graphics?.radius,
|
|
457
|
+
segments: graphics?.segments,
|
|
458
|
+
tube: graphics?.tube,
|
|
459
|
+
finite: bodyParams.finite,
|
|
133
460
|
});
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
body.
|
|
461
|
+
const infinitePlane = type === exports.Physics3DType.PLANE && !dims.finite;
|
|
462
|
+
const mass = infinitePlane ? 0 : (bodyParams.mass ?? 1);
|
|
463
|
+
const body = this.createBodyShell(component, mass, context.pose || graphics);
|
|
464
|
+
if (type === exports.Physics3DType.COMPOUND) {
|
|
465
|
+
const parts = bodyParams.parts?.length ? bodyParams.parts : (graphics?.parts || []);
|
|
466
|
+
if (!parts.length) {
|
|
467
|
+
addPlaced(body, exports.Physics3DType.BOX, dims);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
for (const part of parts) {
|
|
471
|
+
const partType = part.type || part.shape || exports.Physics3DType.BOX;
|
|
472
|
+
if (normalizeType(partType) === exports.Physics3DType.COMPOUND)
|
|
473
|
+
continue;
|
|
474
|
+
const partDims = dimsFromParams(part, dims);
|
|
475
|
+
addPlaced(body, partType, partDims, part);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
addPlaced(body, type, dims);
|
|
481
|
+
}
|
|
482
|
+
applyBodyOptions(body, bodyParams.bodyOptions);
|
|
483
|
+
component.meshColliderKey = undefined;
|
|
484
|
+
return body;
|
|
485
|
+
}
|
|
486
|
+
createBodyShell(component, mass, graphics) {
|
|
487
|
+
const body = new CANNON__namespace.Body({ mass });
|
|
488
|
+
const pos = component.bodyParams.position;
|
|
489
|
+
body.position.set(pos?.x ?? graphics?.positionX ?? 0, pos?.y ?? graphics?.positionY ?? 0, pos?.z ?? graphics?.positionZ ?? 0);
|
|
490
|
+
const rot = component.bodyParams.rotation;
|
|
491
|
+
const rx = rot?.x ?? graphics?.rotationX ?? 0;
|
|
492
|
+
const ry = rot?.y ?? graphics?.rotationY ?? 0;
|
|
493
|
+
const rz = rot?.z ?? graphics?.rotationZ ?? 0;
|
|
494
|
+
if (rx || ry || rz) {
|
|
495
|
+
body.quaternion.setFromEuler(rx, ry, rz);
|
|
496
|
+
}
|
|
156
497
|
return body;
|
|
157
498
|
}
|
|
158
499
|
}
|
|
159
500
|
|
|
160
501
|
class Physics3DEngine {
|
|
161
502
|
constructor(game, options) {
|
|
503
|
+
this.pending = new Set();
|
|
504
|
+
this.pendingConstraints = new Set();
|
|
505
|
+
this.constraints = new Set();
|
|
506
|
+
this.contactPairs = new Map();
|
|
162
507
|
this.enabled = false;
|
|
163
508
|
this.game = game;
|
|
164
509
|
this.options = options ?? {};
|
|
@@ -166,10 +511,8 @@ class Physics3DEngine {
|
|
|
166
511
|
}
|
|
167
512
|
start() {
|
|
168
513
|
this.world = new CANNON__namespace.World();
|
|
169
|
-
// Set gravity
|
|
170
514
|
const gravity = this.options.gravity ?? { x: 0, y: -9.82, z: 0 };
|
|
171
515
|
this.world.gravity.set(gravity.x, gravity.y, gravity.z);
|
|
172
|
-
// Configure solver
|
|
173
516
|
if (this.options.solver) {
|
|
174
517
|
const solver = this.world.solver;
|
|
175
518
|
if (this.options.solver.iterations !== undefined) {
|
|
@@ -187,10 +530,14 @@ class Physics3DEngine {
|
|
|
187
530
|
update(e) {
|
|
188
531
|
if (!this.world || !this.enabled)
|
|
189
532
|
return;
|
|
533
|
+
this.flushPending();
|
|
534
|
+
this.rebuildStaleMeshColliders();
|
|
190
535
|
const fixedTimeStep = this.options.fixedTimeStep ?? 1 / 60;
|
|
191
536
|
const maxSubSteps = this.options.maxSubSteps ?? 3;
|
|
192
537
|
const dt = (e.deltaTime || 16.67) / 1000;
|
|
538
|
+
this.flushConstraints();
|
|
193
539
|
this.world.step(fixedTimeStep, dt, maxSubSteps);
|
|
540
|
+
this.emitCollisionActive();
|
|
194
541
|
}
|
|
195
542
|
stop() {
|
|
196
543
|
this.enabled = false;
|
|
@@ -199,8 +546,16 @@ class Physics3DEngine {
|
|
|
199
546
|
this.enabled = true;
|
|
200
547
|
}
|
|
201
548
|
destroy() {
|
|
549
|
+
this.pending.clear();
|
|
550
|
+
this.pendingConstraints.clear();
|
|
551
|
+
this.contactPairs.clear();
|
|
202
552
|
if (this.world) {
|
|
203
|
-
|
|
553
|
+
for (const constraint of this.constraints) {
|
|
554
|
+
if (constraint.constraint)
|
|
555
|
+
this.world.removeConstraint(constraint.constraint);
|
|
556
|
+
constraint.constraint = undefined;
|
|
557
|
+
}
|
|
558
|
+
this.constraints.clear();
|
|
204
559
|
while (this.world.bodies.length > 0) {
|
|
205
560
|
this.world.removeBody(this.world.bodies[0]);
|
|
206
561
|
}
|
|
@@ -208,32 +563,131 @@ class Physics3DEngine {
|
|
|
208
563
|
}
|
|
209
564
|
}
|
|
210
565
|
add(component) {
|
|
211
|
-
const body = this.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
body.component = component;
|
|
566
|
+
const body = this.tryCreate(component);
|
|
567
|
+
if (!body) {
|
|
568
|
+
this.pending.add(component);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
this.attach(component, body);
|
|
218
572
|
}
|
|
219
573
|
change(component) {
|
|
220
|
-
|
|
574
|
+
this.detachConstraintsFor(component);
|
|
575
|
+
this.clearContactsFor(component);
|
|
221
576
|
if (component.body) {
|
|
222
577
|
this.world.removeBody(component.body);
|
|
578
|
+
component.body = undefined;
|
|
223
579
|
}
|
|
224
|
-
|
|
225
|
-
this.
|
|
226
|
-
component.body = newBody;
|
|
227
|
-
newBody.component = component;
|
|
580
|
+
this.pending.delete(component);
|
|
581
|
+
this.add(component);
|
|
228
582
|
}
|
|
229
583
|
remove(component) {
|
|
584
|
+
this.detachConstraintsFor(component);
|
|
585
|
+
this.clearContactsFor(component);
|
|
586
|
+
this.pending.delete(component);
|
|
230
587
|
if (component.body) {
|
|
231
588
|
this.world.removeBody(component.body);
|
|
232
589
|
component.body = undefined;
|
|
233
590
|
}
|
|
591
|
+
component.meshColliderKey = undefined;
|
|
592
|
+
}
|
|
593
|
+
addConstraint(component) {
|
|
594
|
+
this.removeConstraint(component);
|
|
595
|
+
this.pendingConstraints.add(component);
|
|
596
|
+
this.flushConstraints();
|
|
597
|
+
}
|
|
598
|
+
removeConstraint(component) {
|
|
599
|
+
this.pendingConstraints.delete(component);
|
|
600
|
+
this.constraints.delete(component);
|
|
601
|
+
if (component.constraint && this.world) {
|
|
602
|
+
this.world.removeConstraint(component.constraint);
|
|
603
|
+
}
|
|
604
|
+
component.constraint = undefined;
|
|
605
|
+
}
|
|
606
|
+
flushConstraints() {
|
|
607
|
+
if (!this.world)
|
|
608
|
+
return;
|
|
609
|
+
for (const component of [...this.pendingConstraints]) {
|
|
610
|
+
if (!component.gameObject) {
|
|
611
|
+
this.pendingConstraints.delete(component);
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (this.tryAttachConstraint(component)) {
|
|
615
|
+
this.pendingConstraints.delete(component);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
tryCreate(component) {
|
|
620
|
+
const context = this.contextFor(component);
|
|
621
|
+
return this.bodiesFactory.create(component, context);
|
|
622
|
+
}
|
|
623
|
+
attach(component, body) {
|
|
624
|
+
this.world.addBody(body);
|
|
625
|
+
component.body = body;
|
|
626
|
+
component.world = this.world;
|
|
627
|
+
body.component = component;
|
|
628
|
+
}
|
|
629
|
+
contextFor(component) {
|
|
630
|
+
const gameObject = component.gameObject;
|
|
631
|
+
const graphics = gameObject?.getComponent('Graphics3D');
|
|
632
|
+
const model = gameObject?.getComponent('Model3D');
|
|
633
|
+
const transform3d = gameObject?.getComponent('Transform3D');
|
|
634
|
+
const renderer = this.game.getSystem(pluginRenderer3d.Renderer3DSystem);
|
|
635
|
+
const modelGroup = gameObject ? renderer?.threeContext?.models.get(gameObject.id) : undefined;
|
|
636
|
+
const node = gameObject ? renderer?.threeContext?.object3DFor(gameObject.id) : undefined;
|
|
637
|
+
const scene = renderer?.threeContext?.scene;
|
|
638
|
+
let worldPose;
|
|
639
|
+
if (node?.parent && node.parent !== scene) {
|
|
640
|
+
node.updateWorldMatrix(true, false);
|
|
641
|
+
const position = new three.Vector3();
|
|
642
|
+
const euler = new three.Euler();
|
|
643
|
+
node.getWorldPosition(position);
|
|
644
|
+
euler.setFromRotationMatrix(node.matrixWorld);
|
|
645
|
+
worldPose = {
|
|
646
|
+
positionX: position.x,
|
|
647
|
+
positionY: position.y,
|
|
648
|
+
positionZ: position.z,
|
|
649
|
+
rotationX: euler.x,
|
|
650
|
+
rotationY: euler.y,
|
|
651
|
+
rotationZ: euler.z,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
return { graphics, model, modelGroup, pose: worldPose || transform3d || graphics };
|
|
655
|
+
}
|
|
656
|
+
flushPending() {
|
|
657
|
+
if (!this.pending.size)
|
|
658
|
+
return;
|
|
659
|
+
for (const component of [...this.pending]) {
|
|
660
|
+
if (!component.gameObject) {
|
|
661
|
+
this.pending.delete(component);
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
const body = this.tryCreate(component);
|
|
665
|
+
if (body) {
|
|
666
|
+
this.attach(component, body);
|
|
667
|
+
this.pending.delete(component);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
rebuildStaleMeshColliders() {
|
|
672
|
+
if (!this.world)
|
|
673
|
+
return;
|
|
674
|
+
const stale = [];
|
|
675
|
+
for (const body of this.world.bodies) {
|
|
676
|
+
const component = body.component;
|
|
677
|
+
if (!component?.gameObject)
|
|
678
|
+
continue;
|
|
679
|
+
const model = component.gameObject.getComponent('Model3D');
|
|
680
|
+
const collider = resolveCollider(component.bodyParams, model);
|
|
681
|
+
const key = meshColliderFingerprint(collider, model);
|
|
682
|
+
if (!key || key === component.meshColliderKey)
|
|
683
|
+
continue;
|
|
684
|
+
stale.push(component);
|
|
685
|
+
}
|
|
686
|
+
for (const component of stale) {
|
|
687
|
+
this.change(component);
|
|
688
|
+
}
|
|
234
689
|
}
|
|
235
690
|
initCollisionEvents() {
|
|
236
|
-
// beginContact: emitted when two bodies start touching
|
|
237
691
|
this.world.addEventListener('beginContact', (event) => {
|
|
238
692
|
const bodyA = event.bodyA;
|
|
239
693
|
const bodyB = event.bodyB;
|
|
@@ -242,9 +696,10 @@ class Physics3DEngine {
|
|
|
242
696
|
if (componentA && componentB) {
|
|
243
697
|
componentA.emit('collisionStart', componentB.gameObject, componentA.gameObject);
|
|
244
698
|
componentB.emit('collisionStart', componentA.gameObject, componentB.gameObject);
|
|
699
|
+
const pair = this.pairKey(bodyA, bodyB);
|
|
700
|
+
this.contactPairs.set(pair, [bodyA.component, bodyB.component]);
|
|
245
701
|
}
|
|
246
702
|
});
|
|
247
|
-
// endContact: emitted when two bodies stop touching
|
|
248
703
|
this.world.addEventListener('endContact', (event) => {
|
|
249
704
|
const bodyA = event.bodyA;
|
|
250
705
|
const bodyB = event.bodyB;
|
|
@@ -254,8 +709,82 @@ class Physics3DEngine {
|
|
|
254
709
|
componentA.emit('collisionEnd', componentB.gameObject, componentA.gameObject);
|
|
255
710
|
componentB.emit('collisionEnd', componentA.gameObject, componentB.gameObject);
|
|
256
711
|
}
|
|
712
|
+
this.contactPairs.delete(this.pairKey(bodyA, bodyB));
|
|
257
713
|
});
|
|
258
714
|
}
|
|
715
|
+
emitCollisionActive() {
|
|
716
|
+
for (const [componentA, componentB] of this.contactPairs.values()) {
|
|
717
|
+
if (!componentA?.gameObject || !componentB?.gameObject)
|
|
718
|
+
continue;
|
|
719
|
+
componentA.emit('collisionActive', componentB.gameObject, componentA.gameObject);
|
|
720
|
+
componentB.emit('collisionActive', componentA.gameObject, componentB.gameObject);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
pairKey(bodyA, bodyB) {
|
|
724
|
+
return bodyA.id < bodyB.id ? `${bodyA.id}:${bodyB.id}` : `${bodyB.id}:${bodyA.id}`;
|
|
725
|
+
}
|
|
726
|
+
clearContactsFor(component) {
|
|
727
|
+
for (const [key, pair] of this.contactPairs) {
|
|
728
|
+
if (pair[0] === component || pair[1] === component) {
|
|
729
|
+
this.contactPairs.delete(key);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
tryAttachConstraint(component) {
|
|
734
|
+
const physicsA = component.gameObject?.getComponent('Physics3D');
|
|
735
|
+
const target = this.game.gameObjects.find((go) => go.name === component.target);
|
|
736
|
+
const physicsB = target?.getComponent('Physics3D');
|
|
737
|
+
if (!physicsA?.body || !physicsB?.body || physicsA.body === physicsB.body)
|
|
738
|
+
return false;
|
|
739
|
+
const constraint = this.createConstraint(component, physicsA.body, physicsB.body);
|
|
740
|
+
constraint.collideConnected = component.collideConnected;
|
|
741
|
+
this.world.addConstraint(constraint);
|
|
742
|
+
component.constraint = constraint;
|
|
743
|
+
this.constraints.add(component);
|
|
744
|
+
return true;
|
|
745
|
+
}
|
|
746
|
+
createConstraint(component, bodyA, bodyB) {
|
|
747
|
+
const maxForce = component.maxForce;
|
|
748
|
+
const pivotA = new CANNON__namespace.Vec3(component.pivotAX, component.pivotAY, component.pivotAZ);
|
|
749
|
+
const pivotB = new CANNON__namespace.Vec3(component.pivotBX, component.pivotBY, component.pivotBZ);
|
|
750
|
+
const axisA = new CANNON__namespace.Vec3(component.axisAX, component.axisAY, component.axisAZ);
|
|
751
|
+
const axisB = new CANNON__namespace.Vec3(component.axisBX, component.axisBY, component.axisBZ);
|
|
752
|
+
switch (component.type) {
|
|
753
|
+
case 'point':
|
|
754
|
+
return new CANNON__namespace.PointToPointConstraint(bodyA, pivotA, bodyB, pivotB, maxForce);
|
|
755
|
+
case 'lock':
|
|
756
|
+
return new CANNON__namespace.LockConstraint(bodyA, bodyB, { maxForce });
|
|
757
|
+
case 'distance':
|
|
758
|
+
return new CANNON__namespace.DistanceConstraint(bodyA, bodyB, component.distance, maxForce);
|
|
759
|
+
case 'hinge':
|
|
760
|
+
default: {
|
|
761
|
+
const hinge = new CANNON__namespace.HingeConstraint(bodyA, bodyB, {
|
|
762
|
+
pivotA,
|
|
763
|
+
pivotB,
|
|
764
|
+
axisA,
|
|
765
|
+
axisB,
|
|
766
|
+
maxForce,
|
|
767
|
+
collideConnected: component.collideConnected,
|
|
768
|
+
});
|
|
769
|
+
if (component.motor) {
|
|
770
|
+
hinge.enableMotor();
|
|
771
|
+
hinge.setMotorSpeed(component.motorSpeed);
|
|
772
|
+
}
|
|
773
|
+
return hinge;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
detachConstraintsFor(physics) {
|
|
778
|
+
for (const constraint of [...this.constraints]) {
|
|
779
|
+
const physicsA = constraint.gameObject?.getComponent('Physics3D');
|
|
780
|
+
const target = this.game.gameObjects.find((go) => go.name === constraint.target);
|
|
781
|
+
const physicsB = target?.getComponent('Physics3D');
|
|
782
|
+
if (physicsA === physics || physicsB === physics) {
|
|
783
|
+
this.removeConstraint(constraint);
|
|
784
|
+
this.pendingConstraints.add(constraint);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
259
788
|
}
|
|
260
789
|
|
|
261
790
|
let Physics3DSystem$1 = class Physics3DSystem extends engine.System {
|
|
@@ -290,6 +819,7 @@ let Physics3DSystem$1 = class Physics3DSystem extends engine.System {
|
|
|
290
819
|
break;
|
|
291
820
|
}
|
|
292
821
|
case engine.OBSERVER_TYPE.REMOVE: {
|
|
822
|
+
this.engine.remove(changed.component);
|
|
293
823
|
break;
|
|
294
824
|
}
|
|
295
825
|
}
|
|
@@ -333,12 +863,100 @@ Physics3DSystem$1 = tslib.__decorate([
|
|
|
333
863
|
], Physics3DSystem$1);
|
|
334
864
|
var Physics3DSystem = Physics3DSystem$1;
|
|
335
865
|
|
|
866
|
+
let Physics3DConstraintSystem$1 = class Physics3DConstraintSystem extends engine.System {
|
|
867
|
+
constructor() {
|
|
868
|
+
super(...arguments);
|
|
869
|
+
this.name = 'Physics3DConstraintSystem';
|
|
870
|
+
}
|
|
871
|
+
static { this.systemName = 'Physics3DConstraintSystem'; }
|
|
872
|
+
init() {
|
|
873
|
+
const physics = this.game.getSystem(Physics3DSystem);
|
|
874
|
+
if (!physics) {
|
|
875
|
+
console.warn('Physics3DConstraintSystem requires Physics3DSystem');
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
update() {
|
|
879
|
+
const engine = this.engine();
|
|
880
|
+
const changes = this.componentObserver.clear();
|
|
881
|
+
for (const changed of changes) {
|
|
882
|
+
this.componentChanged(changed);
|
|
883
|
+
}
|
|
884
|
+
engine?.flushConstraints();
|
|
885
|
+
}
|
|
886
|
+
componentChanged(changed) {
|
|
887
|
+
if (changed.componentName !== 'Physics3DConstraint')
|
|
888
|
+
return;
|
|
889
|
+
const engine$1 = this.engine();
|
|
890
|
+
if (!engine$1)
|
|
891
|
+
return;
|
|
892
|
+
const component = changed.component;
|
|
893
|
+
if (changed.type === engine.OBSERVER_TYPE.REMOVE) {
|
|
894
|
+
engine$1.removeConstraint(component);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
engine$1.addConstraint(component);
|
|
898
|
+
}
|
|
899
|
+
engine() {
|
|
900
|
+
return this.game.getSystem(Physics3DSystem)?.engine;
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
Physics3DConstraintSystem$1 = tslib.__decorate([
|
|
904
|
+
engine.decorators.componentObserver({
|
|
905
|
+
Physics3DConstraint: [
|
|
906
|
+
'type', 'target',
|
|
907
|
+
'pivotAX', 'pivotAY', 'pivotAZ',
|
|
908
|
+
'pivotBX', 'pivotBY', 'pivotBZ',
|
|
909
|
+
'axisAX', 'axisAY', 'axisAZ',
|
|
910
|
+
'axisBX', 'axisBY', 'axisBZ',
|
|
911
|
+
'distance', 'maxForce', 'collideConnected',
|
|
912
|
+
'motor', 'motorSpeed',
|
|
913
|
+
],
|
|
914
|
+
})
|
|
915
|
+
], Physics3DConstraintSystem$1);
|
|
916
|
+
var Physics3DConstraintSystem = Physics3DConstraintSystem$1;
|
|
917
|
+
|
|
336
918
|
/** Auto-generated by scripts/build-package.mjs — do not edit. */
|
|
919
|
+
Object.assign(Physics3DConstraintSystem, {
|
|
920
|
+
packageName: "@combos-fun/plugin-cannon",
|
|
921
|
+
packageVersion: "0.0.44",
|
|
922
|
+
});
|
|
337
923
|
Object.assign(Physics3DSystem, {
|
|
338
924
|
packageName: "@combos-fun/plugin-cannon",
|
|
339
|
-
packageVersion: "0.0.
|
|
925
|
+
packageVersion: "0.0.44",
|
|
340
926
|
});
|
|
341
927
|
|
|
928
|
+
class Physics3DConstraint extends engine.Component {
|
|
929
|
+
constructor() {
|
|
930
|
+
super(...arguments);
|
|
931
|
+
this.type = 'hinge';
|
|
932
|
+
this.target = '';
|
|
933
|
+
this.pivotAX = 0;
|
|
934
|
+
this.pivotAY = 0;
|
|
935
|
+
this.pivotAZ = 0;
|
|
936
|
+
this.pivotBX = 0;
|
|
937
|
+
this.pivotBY = 0;
|
|
938
|
+
this.pivotBZ = 0;
|
|
939
|
+
this.axisAX = 0;
|
|
940
|
+
this.axisAY = 1;
|
|
941
|
+
this.axisAZ = 0;
|
|
942
|
+
this.axisBX = 0;
|
|
943
|
+
this.axisBY = 1;
|
|
944
|
+
this.axisBZ = 0;
|
|
945
|
+
this.distance = 1;
|
|
946
|
+
this.maxForce = 1e6;
|
|
947
|
+
this.collideConnected = true;
|
|
948
|
+
this.motor = false;
|
|
949
|
+
this.motorSpeed = 0;
|
|
950
|
+
}
|
|
951
|
+
static { this.componentName = 'Physics3DConstraint'; }
|
|
952
|
+
init(obj) {
|
|
953
|
+
if (obj)
|
|
954
|
+
Object.assign(this, obj);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
342
958
|
exports.Physics3D = Physics3D;
|
|
959
|
+
exports.Physics3DConstraint = Physics3DConstraint;
|
|
960
|
+
exports.Physics3DConstraintSystem = Physics3DConstraintSystem;
|
|
343
961
|
exports.Physics3DSystem = Physics3DSystem;
|
|
344
962
|
//# sourceMappingURL=plugin-cannon.cjs.js.map
|