@needle-tools/engine 2.36.0-pre → 2.38.0-pre
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/CHANGELOG.md +33 -0
- package/dist/needle-engine.d.ts +248 -151
- package/dist/needle-engine.js +451 -437
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +82 -82
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/debug/debug.d.ts +1 -0
- package/lib/engine/debug/debug.js +3 -0
- package/lib/engine/debug/debug.js.map +1 -1
- package/lib/engine/engine_addressables.d.ts +3 -1
- package/lib/engine/engine_addressables.js +12 -5
- package/lib/engine/engine_addressables.js.map +1 -1
- package/lib/engine/engine_element.js +3 -2
- package/lib/engine/engine_element.js.map +1 -1
- package/lib/engine/engine_element_overlay.js +4 -3
- package/lib/engine/engine_element_overlay.js.map +1 -1
- package/lib/engine/engine_gameobject.js +2 -1
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_input.d.ts +2 -0
- package/lib/engine/engine_input.js +14 -3
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +35 -46
- package/lib/engine/engine_physics.js +479 -386
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_physics.types.d.ts +23 -0
- package/lib/engine/engine_physics.types.js +27 -0
- package/lib/engine/engine_physics.types.js.map +1 -0
- package/lib/engine/engine_serialization_core.d.ts +3 -0
- package/lib/engine/engine_serialization_core.js +5 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +7 -1
- package/lib/engine/engine_setup.js +13 -3
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_types.d.ts +45 -26
- package/lib/engine/engine_types.js +24 -37
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_util_decorator.d.ts +6 -0
- package/lib/engine/engine_util_decorator.js +54 -0
- package/lib/engine/engine_util_decorator.js.map +1 -0
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +1 -1
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_gameobject_data.js +2 -0
- package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
- package/lib/engine-components/Animation.d.ts +7 -5
- package/lib/engine-components/Animation.js +7 -7
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +14 -7
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/BoxHelperComponent.js +1 -0
- package/lib/engine-components/BoxHelperComponent.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +1 -0
- package/lib/engine-components/Camera.js +20 -5
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CharacterController.d.ts +31 -0
- package/lib/engine-components/CharacterController.js +167 -0
- package/lib/engine-components/CharacterController.js.map +1 -0
- package/lib/engine-components/Collider.d.ts +16 -5
- package/lib/engine-components/Collider.js +45 -23
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +6 -15
- package/lib/engine-components/Component.js +7 -112
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/DragControls.js +9 -6
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/Light.d.ts +2 -0
- package/lib/engine-components/Light.js +13 -2
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/NavMesh.d.ts +0 -5
- package/lib/engine-components/NavMesh.js +100 -10
- package/lib/engine-components/NavMesh.js.map +1 -1
- package/lib/engine-components/NestedGltf.js +2 -0
- package/lib/engine-components/NestedGltf.js.map +1 -1
- package/lib/engine-components/Renderer.js +4 -0
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +45 -25
- package/lib/engine-components/RigidBody.js +290 -142
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SmoothFollow.d.ts +2 -1
- package/lib/engine-components/SmoothFollow.js +25 -17
- package/lib/engine-components/SmoothFollow.js.map +1 -1
- package/lib/engine-components/SpatialTrigger.js +1 -1
- package/lib/engine-components/SpatialTrigger.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +1 -0
- package/lib/engine-components/SpectatorCamera.js +9 -2
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SpringJoint.d.ts +0 -13
- package/lib/engine-components/SpringJoint.js +42 -41
- package/lib/engine-components/SpringJoint.js.map +1 -1
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +1 -0
- package/lib/engine-components/WebXR.js +13 -6
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRController.js +12 -6
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +4 -3
- package/lib/engine-components/codegen/components.js +4 -3
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/package.json +3 -4
- package/src/engine/api.ts +2 -1
- package/src/engine/codegen/register_types.js +16 -12
- package/src/engine/debug/debug.ts +4 -0
- package/src/engine/dist/engine_physics.js +739 -0
- package/src/engine/dist/engine_setup.js +777 -0
- package/src/engine/engine_addressables.ts +18 -8
- package/src/engine/engine_element.ts +3 -2
- package/src/engine/engine_element_overlay.ts +4 -3
- package/src/engine/engine_gameobject.ts +4 -4
- package/src/engine/engine_input.ts +12 -3
- package/src/engine/engine_physics.ts +492 -418
- package/src/engine/engine_physics.types.ts +28 -0
- package/src/engine/engine_serialization_core.ts +8 -1
- package/src/engine/engine_setup.ts +31 -18
- package/src/engine/engine_types.ts +83 -56
- package/src/engine/engine_util_decorator.ts +69 -0
- package/src/engine/engine_utils.ts +3 -3
- package/src/engine/extensions/NEEDLE_gameobject_data.ts +2 -0
- package/src/engine-components/Animation.ts +18 -12
- package/src/engine-components/AnimatorController.ts +16 -11
- package/src/engine-components/BoxHelperComponent.ts +1 -0
- package/src/engine-components/Camera.ts +21 -4
- package/src/engine-components/CharacterController.ts +171 -0
- package/src/engine-components/Collider.ts +49 -39
- package/src/engine-components/Component.ts +15 -130
- package/src/engine-components/DragControls.ts +9 -5
- package/src/engine-components/Light.ts +17 -3
- package/src/engine-components/NavMesh.ts +114 -115
- package/src/engine-components/NestedGltf.ts +2 -0
- package/src/engine-components/Renderer.ts +5 -1
- package/src/engine-components/RigidBody.ts +292 -149
- package/src/engine-components/SmoothFollow.ts +21 -18
- package/src/engine-components/SpatialTrigger.ts +1 -1
- package/src/engine-components/SpectatorCamera.ts +10 -2
- package/src/engine-components/SpringJoint.ts +41 -41
- package/src/engine-components/VideoPlayer.ts +1 -2
- package/src/engine-components/WebXR.ts +15 -6
- package/src/engine-components/WebXRController.ts +16 -7
- package/src/engine-components/codegen/components.ts +4 -3
- package/src/engine-components/dist/CharacterController.js +123 -0
- package/src/engine-components/dist/RigidBody.js +458 -0
|
@@ -1,38 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Box3, Layers, Matrix4, Quaternion, Raycaster, Sphere, Vector2, Vector3 } from 'three';
|
|
3
|
-
import cannonDebugger from 'cannon-es-debugger';
|
|
1
|
+
import { Box3, BufferAttribute, BufferGeometry, Layers, LineBasicMaterial, LineSegments, Matrix4, Quaternion, Raycaster, Sphere, Vector2, Vector3 } from 'three';
|
|
4
2
|
import { getParam } from "./engine_utils";
|
|
5
|
-
import { getWorldPosition, getWorldQuaternion, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils";
|
|
6
|
-
import {
|
|
7
|
-
import { InstancingUtil } from './engine_instancing';
|
|
3
|
+
import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils";
|
|
4
|
+
import { Collision, ContactPoint } from './engine_types';
|
|
8
5
|
import { foreachComponent } from './engine_gameobject';
|
|
6
|
+
import RAPIER, { ActiveEvents, Collider, ColliderDesc, EventQueue, RigidBody, RigidBodyType, World } from '@dimforge/rapier3d-compat';
|
|
7
|
+
import { CollisionDetectionMode } from '../engine/engine_physics.types';
|
|
9
8
|
const debugPhysics = getParam("debugphysics");
|
|
9
|
+
const debugColliderPlacement = getParam("debugphysicscolliders");
|
|
10
10
|
const debugCollisions = getParam("debugcollisions");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
drag = 0;
|
|
16
|
-
angularDrag = 0.05;
|
|
17
|
-
sleepThreshold = .01;
|
|
18
|
-
}
|
|
19
|
-
// TODO: refactor to return some kind of handle for adding/removing
|
|
20
|
-
class PhysicsObject {
|
|
21
|
-
obj;
|
|
22
|
-
parent;
|
|
23
|
-
body;
|
|
24
|
-
shapes = [];
|
|
25
|
-
collisonCallback = null;
|
|
26
|
-
_hasRigidbody = false;
|
|
27
|
-
_didSleepLastStep = false;
|
|
28
|
-
constructor(obj, body) {
|
|
29
|
-
this.obj = obj;
|
|
30
|
-
this.parent = obj.parent;
|
|
31
|
-
this.body = body;
|
|
32
|
-
if (this.body)
|
|
33
|
-
this.body[$physicsKey] = obj;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
11
|
+
const $componentKey = Symbol("needle component");
|
|
12
|
+
const $bodyKey = Symbol("physics body");
|
|
13
|
+
const $colliderRigidbody = Symbol("rigidbody");
|
|
14
|
+
// const $removed = Symbol("removed");
|
|
36
15
|
export class RaycastOptions {
|
|
37
16
|
ray = undefined;
|
|
38
17
|
cam = undefined;
|
|
@@ -196,399 +175,513 @@ export class Physics {
|
|
|
196
175
|
return results;
|
|
197
176
|
}
|
|
198
177
|
// physics simulation
|
|
199
|
-
|
|
178
|
+
_tempPosition = new Vector3();
|
|
179
|
+
_tempQuaternion = new Quaternion();
|
|
180
|
+
_tempScale = new Vector3();
|
|
181
|
+
_tempMatrix = new Matrix4();
|
|
182
|
+
static _didLoadPhysicsEngine = false;
|
|
200
183
|
_isUpdatingPhysicsWorld = false;
|
|
184
|
+
get isUpdating() { return this._isUpdatingPhysicsWorld; }
|
|
201
185
|
context;
|
|
202
|
-
world
|
|
186
|
+
world;
|
|
187
|
+
_hasCreatedWorld = false;
|
|
188
|
+
eventQueue;
|
|
189
|
+
collisionHandler;
|
|
190
|
+
// private rigidbodies: Array<IRigidbody | null> = [];
|
|
203
191
|
objects = [];
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
bodies = [];
|
|
193
|
+
// private rigidbodiesLookup: Map<IRigidbody, RigidBody> = new Map<IRigidbody, RigidBody>();
|
|
194
|
+
// private kinematicColliders: Array<IComponent> = [];
|
|
195
|
+
// private rigidbodyLookup: Map<IRigidbody, IComponent[]> = new Map<IRigidbody, IComponent[]>();
|
|
196
|
+
// private objectLookup: Map<Object3D, IRigidbody> = new Map<Object3D, IRigidbody>();
|
|
206
197
|
constructor(context) {
|
|
207
198
|
this.context = context;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// ignore in raycast
|
|
214
|
-
mesh.layers.set(-1);
|
|
215
|
-
};
|
|
216
|
-
cannonDebugger(context.scene, this.world.bodies, opts);
|
|
217
|
-
}
|
|
218
|
-
this.world.addEventListener("beginContact", this.onBeginContact.bind(this));
|
|
219
|
-
this.world.addEventListener("endContact", this.onEndContact.bind(this));
|
|
220
|
-
}
|
|
221
|
-
addPreStepListener(listener) {
|
|
222
|
-
this.world.addEventListener("preStep", listener);
|
|
223
|
-
}
|
|
224
|
-
addPostStepListener(listener) {
|
|
225
|
-
this.world.addEventListener("postStep", listener);
|
|
226
|
-
}
|
|
227
|
-
addConstraint(constraint) {
|
|
228
|
-
this.world.addConstraint(constraint);
|
|
229
|
-
}
|
|
230
|
-
setGravity(vec) {
|
|
231
|
-
this.world.gravity.set(vec.x, vec.y, vec.z);
|
|
232
|
-
}
|
|
233
|
-
multiplyGravity(vec) {
|
|
234
|
-
this.world.gravity.x *= vec.x;
|
|
235
|
-
this.world.gravity.y *= vec.y;
|
|
236
|
-
this.world.gravity.z *= vec.z;
|
|
237
|
-
}
|
|
238
|
-
addBody(go, body) {
|
|
239
|
-
for (let i = 0; i < this.objects.length; i++) {
|
|
240
|
-
const reg = this.objects[i];
|
|
241
|
-
if (reg.obj === go) {
|
|
242
|
-
reg._hasRigidbody = true;
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
199
|
+
}
|
|
200
|
+
async createWorld() {
|
|
201
|
+
if (this._hasCreatedWorld) {
|
|
202
|
+
console.error("Invalid call to create physics world: world is already created");
|
|
203
|
+
return;
|
|
245
204
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this.world
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
205
|
+
this._hasCreatedWorld = true;
|
|
206
|
+
if (!Physics._didLoadPhysicsEngine) {
|
|
207
|
+
await RAPIER.init().then(() => RAPIER);
|
|
208
|
+
Physics._didLoadPhysicsEngine = true;
|
|
209
|
+
}
|
|
210
|
+
const gravity = { x: 0.0, y: -9.81, z: 0.0 };
|
|
211
|
+
this.world = new World(gravity);
|
|
212
|
+
}
|
|
213
|
+
addBoxCollider(collider, center, size) {
|
|
214
|
+
const obj = collider.gameObject;
|
|
215
|
+
const scale = getWorldScale(obj, this._tempPosition).multiply(size);
|
|
216
|
+
scale.multiplyScalar(0.5);
|
|
217
|
+
const desc = ColliderDesc.cuboid(scale.x, scale.y, scale.z);
|
|
218
|
+
this.createCollider(collider, desc, center);
|
|
219
|
+
}
|
|
220
|
+
addSphereCollider(collider, center, radius) {
|
|
221
|
+
const obj = collider.gameObject;
|
|
222
|
+
const scale = getWorldScale(obj, this._tempPosition).multiplyScalar(radius);
|
|
223
|
+
const desc = ColliderDesc.ball(scale.x);
|
|
224
|
+
this.createCollider(collider, desc, center);
|
|
225
|
+
}
|
|
226
|
+
addCapsuleCollider(collider, center, height, radius) {
|
|
227
|
+
const obj = collider.gameObject;
|
|
228
|
+
const scale = getWorldScale(obj, this._tempPosition);
|
|
229
|
+
if (debugPhysics)
|
|
230
|
+
console.log("capsule scale", scale, height, radius);
|
|
231
|
+
const desc = ColliderDesc.capsule(height * .5 * scale.y - radius, radius * scale.x);
|
|
232
|
+
this.createCollider(collider, desc, center);
|
|
233
|
+
}
|
|
234
|
+
addMeshCollider(collider, mesh, convex) {
|
|
235
|
+
const geo = mesh.geometry;
|
|
236
|
+
if (!geo) {
|
|
237
|
+
if (debugPhysics)
|
|
238
|
+
console.warn("Missing mesh geometry", mesh.name);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
let positions = geo.getAttribute("position").array;
|
|
242
|
+
const indices = geo.index?.array;
|
|
243
|
+
// console.log(geo.center())
|
|
244
|
+
// scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
|
|
245
|
+
const scale = getWorldScale(mesh, this._tempPosition);
|
|
246
|
+
if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
|
|
247
|
+
console.warn("Your model is using scaled mesh colliders which is not optimal for performance", mesh.name, Object.assign({}, scale), mesh);
|
|
248
|
+
// showBalloonWarning("Your model is using scaled mesh colliders which is not optimal for performance: " + mesh.name + ", consider using unscaled objects");
|
|
249
|
+
const scaledPositions = new Float32Array(positions.length);
|
|
250
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
251
|
+
scaledPositions[i] = positions[i] * scale.x;
|
|
252
|
+
scaledPositions[i + 1] = positions[i + 1] * scale.y;
|
|
253
|
+
scaledPositions[i + 2] = positions[i + 2] * scale.z;
|
|
260
254
|
}
|
|
255
|
+
positions = scaledPositions;
|
|
256
|
+
}
|
|
257
|
+
const desc = convex ? ColliderDesc.convexMesh(positions) : ColliderDesc.trimesh(positions, indices);
|
|
258
|
+
if (desc) {
|
|
259
|
+
this.createCollider(collider, desc);
|
|
260
|
+
// col.setTranslationWrtParent(new Vector3(0,2,0));
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
263
|
+
createCollider(collider, desc, center) {
|
|
264
|
+
if (!this.world)
|
|
265
|
+
throw new Error("Physics world not initialized");
|
|
266
|
+
const matrix = this._tempMatrix;
|
|
267
|
+
const { rigidBody, useExplicitMassProperties } = this.getRigidbody(collider, this._tempMatrix);
|
|
268
|
+
matrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
|
|
269
|
+
getWorldScale(collider.gameObject, this._tempScale);
|
|
270
|
+
if (center)
|
|
271
|
+
this._tempPosition.add(center).multiply(this._tempScale);
|
|
272
|
+
desc.setTranslation(this._tempPosition.x, this._tempPosition.y, this._tempPosition.z);
|
|
273
|
+
desc.setRotation(this._tempQuaternion);
|
|
274
|
+
desc.setSensor(collider.isTrigger);
|
|
275
|
+
// if we want to use explicit mass properties, we need to set the collider density to 0
|
|
276
|
+
// otherwise rapier will compute the mass properties based on the collider shape and density
|
|
277
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
278
|
+
if (useExplicitMassProperties) {
|
|
279
|
+
// desc.setDensity(0);
|
|
280
|
+
}
|
|
281
|
+
const col = this.world.createCollider(desc, rigidBody);
|
|
282
|
+
col[$componentKey] = collider;
|
|
283
|
+
collider[$bodyKey] = col;
|
|
284
|
+
col.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
|
285
|
+
this.objects.push(collider);
|
|
286
|
+
this.bodies.push(col);
|
|
287
|
+
return col;
|
|
288
|
+
}
|
|
289
|
+
getRigidbody(collider, _matrix) {
|
|
290
|
+
if (!this.world)
|
|
291
|
+
throw new Error("Physics world not initialized");
|
|
292
|
+
let rigidBody = null;
|
|
293
|
+
let useExplicitMassProperties = false;
|
|
294
|
+
if (collider.attachedRigidbody) {
|
|
295
|
+
const rb = collider.attachedRigidbody;
|
|
296
|
+
rigidBody = rb[$bodyKey];
|
|
297
|
+
useExplicitMassProperties = true;
|
|
298
|
+
if (!rigidBody) {
|
|
299
|
+
const kinematic = rb.isKinematic && !debugColliderPlacement;
|
|
300
|
+
if (debugPhysics)
|
|
301
|
+
console.log("Create rigidbody", kinematic);
|
|
302
|
+
const rigidBodyDesc = kinematic ? RAPIER.RigidBodyDesc.kinematicPositionBased() : RAPIER.RigidBodyDesc.dynamic();
|
|
303
|
+
const pos = getWorldPosition(collider.attachedRigidbody.gameObject);
|
|
304
|
+
rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
|
|
305
|
+
rigidBodyDesc.setRotation(getWorldQuaternion(collider.attachedRigidbody.gameObject));
|
|
306
|
+
rigidBody = this.world.createRigidBody(rigidBodyDesc);
|
|
307
|
+
this.bodies.push(rigidBody);
|
|
308
|
+
this.objects.push(rb);
|
|
309
|
+
}
|
|
310
|
+
rigidBody[$componentKey] = rb;
|
|
311
|
+
rb[$bodyKey] = rigidBody;
|
|
312
|
+
this.internalUpdateProperties(rb, rigidBody);
|
|
313
|
+
this.getRigidbodyRelativeMatrix(collider.gameObject, rb.gameObject, _matrix);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
const rigidBodyDesc = RAPIER.RigidBodyDesc.kinematicPositionBased();
|
|
317
|
+
const pos = getWorldPosition(collider.gameObject);
|
|
318
|
+
rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
|
|
319
|
+
rigidBodyDesc.setRotation(getWorldQuaternion(collider.gameObject));
|
|
320
|
+
rigidBody = this.world.createRigidBody(rigidBodyDesc);
|
|
321
|
+
_matrix.identity();
|
|
322
|
+
rigidBody[$componentKey] = null;
|
|
323
|
+
}
|
|
324
|
+
collider[$colliderRigidbody] = rigidBody;
|
|
325
|
+
return { rigidBody: rigidBody, useExplicitMassProperties: useExplicitMassProperties };
|
|
326
|
+
}
|
|
327
|
+
removeBody(obj) {
|
|
328
|
+
const body = obj[$bodyKey];
|
|
329
|
+
obj[$bodyKey] = null;
|
|
330
|
+
if (body && this.world) {
|
|
331
|
+
const index = this.objects.findIndex(o => o === obj);
|
|
332
|
+
if (index >= 0) {
|
|
333
|
+
const body = this.bodies[index];
|
|
334
|
+
this.bodies.splice(index, 1);
|
|
335
|
+
this.objects.splice(index, 1);
|
|
336
|
+
if (body instanceof Collider) {
|
|
337
|
+
const collider = body;
|
|
338
|
+
this.world?.removeCollider(collider, true);
|
|
339
|
+
// remove the rigidbody if it doesnt have colliders anymore
|
|
340
|
+
const rb = collider.parent();
|
|
341
|
+
if (rb && rb.numColliders() <= 0) {
|
|
342
|
+
this.world?.removeRigidBody(rb);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else if (body instanceof RigidBody) {
|
|
346
|
+
// TODO: running this code below causes a crash in rapier
|
|
347
|
+
// const rb = body as RigidBody;
|
|
348
|
+
// console.log("colliders", rb.numColliders())
|
|
349
|
+
// for (let i = 0; i < rb.numColliders(); i++) {
|
|
350
|
+
// const col = rb.collider(i);
|
|
351
|
+
// this.world?.removeCollider(col, true);
|
|
352
|
+
// }
|
|
353
|
+
// console.log("colliders", rb.numColliders(), rb)
|
|
354
|
+
// console.log(rb.handle, rb.userData);
|
|
355
|
+
// if (rb.userData === undefined)
|
|
356
|
+
// this.world?.removeRigidBody(rb);
|
|
269
357
|
}
|
|
270
|
-
|
|
358
|
+
// check if we need to remove the rigidbody too
|
|
359
|
+
// const col = obj as ICollider;
|
|
360
|
+
// if (col.isCollider && col.attachedRigidbody) {
|
|
361
|
+
// const rb = col.attachedRigidbody[$bodyKey] as RigidBody;
|
|
362
|
+
// if (rb && rb.numColliders() <= 0) {
|
|
363
|
+
// // this.world?.removeRigidBody(rb);
|
|
364
|
+
// }
|
|
365
|
+
// }
|
|
271
366
|
}
|
|
272
367
|
}
|
|
273
368
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (
|
|
278
|
-
|
|
279
|
-
if (
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
body.type = Body.DYNAMIC;
|
|
283
|
-
if (settings.drag)
|
|
284
|
-
body.linearDamping = settings.drag;
|
|
285
|
-
if (settings.angularDrag)
|
|
286
|
-
body.angularDamping = settings.angularDrag;
|
|
287
|
-
if (settings.sleepThreshold)
|
|
288
|
-
body.sleepSpeedLimit = settings.sleepThreshold;
|
|
289
|
-
if (body.shapes.length > 0)
|
|
290
|
-
this.world.addBody(body);
|
|
291
|
-
const po = new PhysicsObject(obj, body);
|
|
292
|
-
po._hasRigidbody = true;
|
|
293
|
-
this.objects.push(po);
|
|
294
|
-
if (debugPhysics) {
|
|
295
|
-
console.log("created new body", obj.name, body, body.sleepState, this.world.gravity);
|
|
296
|
-
}
|
|
297
|
-
if (settings.physicsEvents)
|
|
298
|
-
this.registerCollisionEvents(po);
|
|
299
|
-
return body;
|
|
300
|
-
}
|
|
301
|
-
addBoxCollider(obj, trigger, center, size, rb) {
|
|
302
|
-
const scale = this.tempPosition;
|
|
303
|
-
obj.getWorldScale(scale);
|
|
304
|
-
const pos = new Vec3(.5 * scale.x * size.x, .5 * scale.y * size.y, .5 * scale.z * size.z);
|
|
305
|
-
const shape = new Box(pos);
|
|
306
|
-
shape.collisionResponse = !trigger;
|
|
307
|
-
center = center.clone();
|
|
308
|
-
center.multiply(scale);
|
|
309
|
-
const body = this.addShape(obj, shape, center, rb);
|
|
310
|
-
if (body !== null) {
|
|
311
|
-
this.world.addBody(body);
|
|
312
|
-
if (this.isAlreadyRegistered(body))
|
|
313
|
-
return shape;
|
|
314
|
-
const po = new PhysicsObject(obj, body);
|
|
315
|
-
this.objects.push(po);
|
|
316
|
-
}
|
|
317
|
-
return shape;
|
|
318
|
-
}
|
|
319
|
-
addSphereCollider(obj, center, radius, rb) {
|
|
320
|
-
const scale = this.tempPosition;
|
|
321
|
-
obj.getWorldScale(scale);
|
|
322
|
-
const factor = Math.max(scale.x, scale.y, scale.z);
|
|
323
|
-
const shape = new PhysicsSphere(radius * factor);
|
|
324
|
-
// shape.collisionResponse = !trigger;
|
|
325
|
-
center = center.clone();
|
|
326
|
-
center.multiply(scale);
|
|
327
|
-
const body = this.addShape(obj, shape, center, rb);
|
|
328
|
-
if (body !== null) {
|
|
329
|
-
this.world.addBody(body);
|
|
330
|
-
if (this.isAlreadyRegistered(body))
|
|
331
|
-
return shape;
|
|
332
|
-
const po = new PhysicsObject(obj, body);
|
|
333
|
-
this.objects.push(po);
|
|
334
|
-
}
|
|
335
|
-
return shape;
|
|
336
|
-
}
|
|
337
|
-
addMeshCollider(_obj) {
|
|
338
|
-
// see https://github.com/schteppe/js/blob/master/demos/bunny.html
|
|
339
|
-
if (debugPhysics)
|
|
340
|
-
console.warn("TODO mesh collider not yet supported");
|
|
341
|
-
// const geometry: BufferGeometry = obj["geometry"];
|
|
342
|
-
// console.log(geometry);
|
|
343
|
-
// const size = geometry.boundingBox.max.clone();
|
|
344
|
-
// size.sub(geometry.boundingBox.min);
|
|
345
|
-
// console.log(size);
|
|
346
|
-
// this.addBoxCollider(obj, size);
|
|
347
|
-
// const verts = geometry.getAttribute("position").array;
|
|
348
|
-
// const faces = new Array<Array<number>>();
|
|
349
|
-
// console.log(geometry);
|
|
350
|
-
// for (let i = 0; i < geometry.index.array.length; i += 3) {
|
|
351
|
-
// const i0 = geometry.index.array[i];
|
|
352
|
-
// const i1 = geometry.index.array[i + 1];
|
|
353
|
-
// const i2 = geometry.index.array[i + 2];
|
|
354
|
-
// const v0 = new Vector3(verts[i0 * 3], verts[i0 * 3 + 1], verts[i0 * 3 + 2]);
|
|
355
|
-
// const v1 = new Vector3(verts[i1 * 3], verts[i1 * 3 + 1], verts[i1 * 3 + 2]);
|
|
356
|
-
// const v2 = new Vector3(verts[i2 * 3], verts[i2 * 3 + 1], verts[i2 * 3 + 2]);
|
|
357
|
-
// const face = [v0, v1, v2];
|
|
358
|
-
// faces.push(face);
|
|
359
|
-
// }
|
|
360
|
-
// const convex = new ConvexBufferGeometry(faces);
|
|
361
|
-
// var shape = new ConvexPolyhedron({ verts, faces });
|
|
362
|
-
// this.addShape(obj, shape);
|
|
363
|
-
}
|
|
364
|
-
isAlreadyRegistered(body) {
|
|
365
|
-
for (const obj of this.objects) {
|
|
366
|
-
if (obj.body === body)
|
|
367
|
-
return true;
|
|
368
|
-
}
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
tempMat1 = new Matrix4();
|
|
372
|
-
tempMat2 = new Matrix4();
|
|
373
|
-
addShape(obj, shape, center, rb) {
|
|
374
|
-
let body = null;
|
|
375
|
-
if (rb) {
|
|
376
|
-
// if (debugPhysics)
|
|
377
|
-
// console.log("get rb body", rb);
|
|
378
|
-
rb.initialize();
|
|
379
|
-
console.assert(rb.body ? true : false, "rigidbody didn't initialize / produce a physics body", rb);
|
|
380
|
-
body = rb.body;
|
|
369
|
+
updateBody(comp, translation, rotation) {
|
|
370
|
+
if (comp.destroyed || !comp.gameObject)
|
|
371
|
+
return;
|
|
372
|
+
if (!translation && !rotation)
|
|
373
|
+
return;
|
|
374
|
+
if (comp.isCollider === true) {
|
|
375
|
+
// const collider = comp as ICollider;
|
|
376
|
+
console.warn("TODO: implement updating collider position");
|
|
381
377
|
}
|
|
382
378
|
else {
|
|
383
|
-
|
|
384
|
-
body =
|
|
385
|
-
body
|
|
386
|
-
|
|
387
|
-
if (body) {
|
|
388
|
-
// console.log(obj.name, obj.position, obj.rotation)
|
|
389
|
-
// the center is serialized from Unity so we need to move it into threejs space
|
|
390
|
-
// this should probably happen on export for colliders
|
|
391
|
-
center.x *= -1;
|
|
392
|
-
let wp = obj.position;
|
|
393
|
-
let wr = obj.quaternion;
|
|
394
|
-
// console.log(obj.name, wp)
|
|
395
|
-
if (rb && rb.gameObject !== obj) {
|
|
396
|
-
this.tempMat1.copy(obj.matrixWorld);
|
|
397
|
-
this.tempMat2.copy(rb.gameObject.matrixWorld).invert();
|
|
398
|
-
this.tempMat1.premultiply(this.tempMat2);
|
|
399
|
-
this.tempMat1.decompose(wp, wr, this.tempPosition);
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
wp = getWorldPosition(obj);
|
|
403
|
-
const bp = body.position;
|
|
404
|
-
wp.x -= bp.x;
|
|
405
|
-
wp.y -= bp.y;
|
|
406
|
-
wp.z -= bp.z;
|
|
407
|
-
wr = getWorldQuaternion(obj);
|
|
408
|
-
const r = new Quaternion(body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
|
|
409
|
-
wr.multiply(r.invert());
|
|
379
|
+
const rigidbody = comp;
|
|
380
|
+
const body = rigidbody[$bodyKey];
|
|
381
|
+
if (body) {
|
|
382
|
+
this.syncPhysicsBody(rigidbody.gameObject, body, translation, rotation);
|
|
410
383
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
updateProperties(rigidbody) {
|
|
387
|
+
const physicsBody = rigidbody[$bodyKey];
|
|
388
|
+
if (physicsBody) {
|
|
389
|
+
this.internalUpdateProperties(rigidbody, physicsBody);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
internal_getRigidbody(rb) {
|
|
393
|
+
return rb[$bodyKey];
|
|
394
|
+
}
|
|
395
|
+
internalUpdateProperties(rb, rigidbody) {
|
|
396
|
+
// continuous collision detection
|
|
397
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
|
|
398
|
+
rigidbody.enableCcd(rb.collisionDetectionMode !== CollisionDetectionMode.Discrete);
|
|
399
|
+
rigidbody.setLinearDamping(rb.drag);
|
|
400
|
+
rigidbody.setAngularDamping(rb.angularDrag);
|
|
401
|
+
rigidbody.setGravityScale(rb.useGravity ? 1 : 0, true);
|
|
402
|
+
// https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
|
|
403
|
+
// rigidbody.setAdditionalMass(rb.mass, true);
|
|
404
|
+
// for (let i = 0; i < rigidbody.numColliders(); i++) {
|
|
405
|
+
// const collider = rigidbody.collider(i);
|
|
406
|
+
// if (collider) {
|
|
407
|
+
// collider.setMass(rb.mass);
|
|
408
|
+
// // const density = rb.mass / collider.shape.computeMassProperties().mass;
|
|
409
|
+
// }
|
|
410
|
+
// }
|
|
411
|
+
// lock rotations
|
|
412
|
+
rigidbody.setEnabledRotations(!rb.lockRotationX, !rb.lockRotationY, !rb.lockRotationZ, true);
|
|
413
|
+
rigidbody.setEnabledTranslations(!rb.lockPositionX, !rb.lockPositionY, !rb.lockPositionZ, true);
|
|
414
|
+
if (rb.isKinematic) {
|
|
415
|
+
rigidbody.setBodyType(RAPIER.RigidBodyType.KinematicPositionBased);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
rigidbody.setBodyType(RAPIER.RigidBodyType.Dynamic);
|
|
419
|
+
}
|
|
428
420
|
}
|
|
429
421
|
// private _lastStepTime: number | undefined = 0;
|
|
430
|
-
|
|
422
|
+
lines;
|
|
423
|
+
step(_deltaTime) {
|
|
424
|
+
if (!this.world)
|
|
425
|
+
return;
|
|
431
426
|
this._isUpdatingPhysicsWorld = true;
|
|
432
|
-
|
|
433
|
-
|
|
427
|
+
if (!this.eventQueue) {
|
|
428
|
+
this.eventQueue = new EventQueue(false);
|
|
429
|
+
}
|
|
430
|
+
this.world.step(this.eventQueue);
|
|
434
431
|
this._isUpdatingPhysicsWorld = false;
|
|
435
|
-
|
|
436
|
-
|
|
432
|
+
this.updateDebugRendering(this.world);
|
|
433
|
+
}
|
|
434
|
+
updateDebugRendering(world) {
|
|
435
|
+
if (debugPhysics || debugColliderPlacement) {
|
|
436
|
+
if (!this.lines) {
|
|
437
|
+
let material = new LineBasicMaterial({
|
|
438
|
+
color: 0xffffff,
|
|
439
|
+
// vertexColors: THREE.VertexColors
|
|
440
|
+
});
|
|
441
|
+
let geometry = new BufferGeometry();
|
|
442
|
+
this.lines = new LineSegments(geometry, material);
|
|
443
|
+
this.context.scene.add(this.lines);
|
|
444
|
+
}
|
|
445
|
+
const buffers = world.debugRender();
|
|
446
|
+
this.lines.geometry.setAttribute('position', new BufferAttribute(buffers.vertices, 3));
|
|
447
|
+
this.lines.geometry.setAttribute('color', new BufferAttribute(buffers.colors, 4));
|
|
437
448
|
}
|
|
438
449
|
}
|
|
439
|
-
temp = new Vector3();
|
|
440
|
-
tempQuat = new Quaternion();
|
|
441
450
|
postStep() {
|
|
451
|
+
if (!this.world)
|
|
452
|
+
return;
|
|
442
453
|
this._isUpdatingPhysicsWorld = true;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
if (
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
body.quaternion.set(rot.x, rot.y, rot.z, rot.w);
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if ((isNaN(body.position.x) || isNaN(body.position.y) || isNaN(body.position.z))) {
|
|
471
|
-
console.error("body position is NaN on", obj.name, "this usually means some colliders are overlapping", body.previousPosition, obj.position);
|
|
472
|
-
this.world.removeBody(body);
|
|
454
|
+
this.syncObjects();
|
|
455
|
+
this._isUpdatingPhysicsWorld = false;
|
|
456
|
+
if (this.eventQueue && !this.collisionHandler) {
|
|
457
|
+
this.collisionHandler = new PhysicsCollisionHandler(this.world, this.eventQueue);
|
|
458
|
+
}
|
|
459
|
+
if (this.collisionHandler) {
|
|
460
|
+
this.collisionHandler.handleCollisionEvents();
|
|
461
|
+
this.collisionHandler.update();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/** sync rendered objects with physics world (except for colliders without rigidbody) */
|
|
465
|
+
syncObjects() {
|
|
466
|
+
if (debugColliderPlacement)
|
|
467
|
+
return;
|
|
468
|
+
for (let i = 0; i < this.bodies.length; i++) {
|
|
469
|
+
const obj = this.objects[i];
|
|
470
|
+
const body = this.bodies[i];
|
|
471
|
+
// if the collider is not attached to a rigidbody
|
|
472
|
+
// it means that its kinematic so we need to update its position
|
|
473
|
+
const col = obj;
|
|
474
|
+
if (col?.isCollider === true && !col.attachedRigidbody) {
|
|
475
|
+
const rigidbody = body.parent();
|
|
476
|
+
if (rigidbody)
|
|
477
|
+
this.syncPhysicsBody(obj.gameObject, rigidbody, true, true);
|
|
473
478
|
continue;
|
|
474
479
|
}
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
// obj.position.y = pos.y;
|
|
489
|
-
// obj.position.z = pos.z;
|
|
490
|
-
// if (entry.center) {
|
|
491
|
-
// this.rotatedCenter.copy(entry.center);
|
|
492
|
-
// const rot = this.tempQuaternion;
|
|
493
|
-
// rot.copy(obj.quaternion);
|
|
494
|
-
// // obj.getWorldQuaternion(this.tempQuaternion)
|
|
495
|
-
// this.rotatedCenter.applyQuaternion(rot);
|
|
496
|
-
// obj.getWorldScale(this.tempVector);
|
|
497
|
-
// this.rotatedCenter.divide(this.tempVector);
|
|
498
|
-
// obj.position.sub(this.rotatedCenter);
|
|
499
|
-
// }
|
|
480
|
+
// sync
|
|
481
|
+
const pos = body.translation();
|
|
482
|
+
const rot = body.rotation();
|
|
483
|
+
// make sure to keep the collider offset
|
|
484
|
+
const center = obj["center"];
|
|
485
|
+
if (center && center.isVector3) {
|
|
486
|
+
this._tempQuaternion.set(rot.x, rot.y, rot.z, rot.w);
|
|
487
|
+
const offset = this._tempPosition.copy(center).applyQuaternion(this._tempQuaternion);
|
|
488
|
+
const scale = getWorldScale(obj.gameObject);
|
|
489
|
+
offset.multiply(scale);
|
|
490
|
+
pos.x -= offset.x;
|
|
491
|
+
pos.y -= offset.y;
|
|
492
|
+
pos.z -= offset.z;
|
|
500
493
|
}
|
|
494
|
+
setWorldPositionXYZ(obj.gameObject, pos.x, pos.y, pos.z);
|
|
495
|
+
setWorldQuaternionXYZW(obj.gameObject, rot.x, rot.y, rot.z, rot.w);
|
|
501
496
|
}
|
|
502
|
-
this._isUpdatingPhysicsWorld = false;
|
|
503
497
|
}
|
|
504
|
-
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
498
|
+
syncPhysicsBody(obj, body, translation, rotation) {
|
|
499
|
+
// const bodyType = body.bodyType();
|
|
500
|
+
// const previous = physicsBody.translation();
|
|
501
|
+
// const vel = physicsBody.linvel();
|
|
502
|
+
const worldPosition = getWorldPosition(obj, this._tempPosition);
|
|
503
|
+
const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
|
|
504
|
+
const type = body.bodyType();
|
|
505
|
+
switch (type) {
|
|
506
|
+
case RigidBodyType.Fixed:
|
|
507
|
+
case RigidBodyType.KinematicPositionBased:
|
|
508
|
+
case RigidBodyType.KinematicVelocityBased:
|
|
509
|
+
if (translation)
|
|
510
|
+
body.setNextKinematicTranslation(worldPosition);
|
|
511
|
+
if (rotation)
|
|
512
|
+
body.setNextKinematicRotation(worldQuaternion);
|
|
513
|
+
break;
|
|
514
|
+
default:
|
|
515
|
+
if (translation)
|
|
516
|
+
body.setTranslation(worldPosition, false);
|
|
517
|
+
if (rotation)
|
|
518
|
+
body.setRotation(worldQuaternion, false);
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
body.wakeUp();
|
|
522
|
+
// physicsBody.setBodyType(RAPIER.RigidBodyType.Fixed);
|
|
523
|
+
// physicsBody.setLinvel(vel, false);
|
|
524
|
+
// update velocity
|
|
525
|
+
// const pos = physicsBody.translation();
|
|
526
|
+
// pos.x -= previous.x;
|
|
527
|
+
// pos.y -= previous.y;
|
|
528
|
+
// pos.z -= previous.z;
|
|
529
|
+
// // threhold
|
|
530
|
+
// const t = 1;
|
|
531
|
+
// const canUpdateVelocity = Math.abs(pos.x) < t && Math.abs(pos.y) < t && Math.abs(pos.z) < t;
|
|
532
|
+
// if (canUpdateVelocity) {
|
|
533
|
+
// const damping = 1 + this.context.time.deltaTime;
|
|
534
|
+
// vel.x *= damping;
|
|
535
|
+
// vel.y *= damping;
|
|
536
|
+
// vel.z *= damping;
|
|
537
|
+
// vel.x += pos.x;
|
|
538
|
+
// vel.y += pos.y;
|
|
539
|
+
// vel.z += pos.z;
|
|
540
|
+
// console.log(vel);
|
|
541
|
+
// physicsBody.setLinvel(vel, true);
|
|
542
|
+
// }
|
|
543
|
+
// else if(debugPhysics) console.warn("Movement exceeded threshold, not updating velocity", pos);
|
|
544
|
+
// body.setBodyType(bodyType);
|
|
545
|
+
}
|
|
546
|
+
static _matricesBuffer = [];
|
|
547
|
+
getRigidbodyRelativeMatrix(comp, rigidbody, mat, matrices) {
|
|
548
|
+
// collect all matrices to the rigidbody and then build the rigidbody relative matrix
|
|
549
|
+
if (matrices === undefined) {
|
|
550
|
+
matrices = Physics._matricesBuffer;
|
|
551
|
+
matrices.length = 0;
|
|
552
|
+
}
|
|
553
|
+
if (comp === rigidbody) {
|
|
554
|
+
const scale = getWorldScale(comp, this._tempPosition);
|
|
555
|
+
mat.makeScale(scale.x, scale.y, scale.z);
|
|
556
|
+
for (let i = matrices.length - 1; i >= 0; i--) {
|
|
557
|
+
mat.multiply(matrices[i]);
|
|
558
|
+
}
|
|
559
|
+
return mat;
|
|
560
|
+
}
|
|
561
|
+
matrices.push(comp.matrix);
|
|
562
|
+
if (comp.parent) {
|
|
563
|
+
this.getRigidbodyRelativeMatrix(comp.parent, rigidbody, mat, matrices);
|
|
564
|
+
}
|
|
565
|
+
return mat;
|
|
537
566
|
}
|
|
538
|
-
|
|
539
|
-
|
|
567
|
+
}
|
|
568
|
+
/** responsible of processing collision events for the component system */
|
|
569
|
+
class PhysicsCollisionHandler {
|
|
570
|
+
world;
|
|
571
|
+
eventQueue;
|
|
572
|
+
constructor(world, eventQueue) {
|
|
573
|
+
this.world = world;
|
|
574
|
+
this.eventQueue = eventQueue;
|
|
575
|
+
}
|
|
576
|
+
activeCollisions = [];
|
|
577
|
+
activeTriggers = [];
|
|
578
|
+
handleCollisionEvents() {
|
|
579
|
+
if (!this.eventQueue)
|
|
540
580
|
return;
|
|
541
|
-
if (!
|
|
581
|
+
if (!this.world)
|
|
542
582
|
return;
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
583
|
+
this.eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
|
584
|
+
const col1 = this.world.getCollider(handle1);
|
|
585
|
+
const col2 = this.world.getCollider(handle2);
|
|
586
|
+
const colliderComponent1 = col1[$componentKey];
|
|
587
|
+
const colliderComponent2 = col2[$componentKey];
|
|
588
|
+
if (debugCollisions)
|
|
589
|
+
console.log("EVT", colliderComponent1.name, colliderComponent2.name, started, col1, col2);
|
|
590
|
+
if (colliderComponent1 && colliderComponent2) {
|
|
591
|
+
if (started) {
|
|
592
|
+
this.onCollisionStarted(colliderComponent1, col1, colliderComponent2, col2);
|
|
593
|
+
this.onCollisionStarted(colliderComponent2, col2, colliderComponent1, col1);
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
this.onCollisionEnded(colliderComponent1, colliderComponent2);
|
|
597
|
+
this.onCollisionEnded(colliderComponent2, colliderComponent1);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
556
600
|
});
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
601
|
+
}
|
|
602
|
+
update() {
|
|
603
|
+
this.onHandleCollisionStay();
|
|
604
|
+
}
|
|
605
|
+
onCollisionStarted(self, selfBody, other, otherBody) {
|
|
606
|
+
let collision = null;
|
|
607
|
+
// if one is a trigger we dont get collisions but want to raise the trigger events
|
|
608
|
+
if (self.isTrigger || other.isTrigger) {
|
|
609
|
+
foreachComponent(self.gameObject, (c) => {
|
|
610
|
+
if (c.onTriggerEnter) {
|
|
611
|
+
c.onTriggerEnter(other);
|
|
612
|
+
}
|
|
613
|
+
this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
|
|
562
614
|
});
|
|
563
615
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
616
|
+
else {
|
|
617
|
+
const object = self.gameObject;
|
|
618
|
+
// TODO: we dont respect the flip value here!
|
|
619
|
+
this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
|
|
620
|
+
foreachComponent(object, (c) => {
|
|
621
|
+
if (c.onCollisionEnter) {
|
|
622
|
+
if (!collision) {
|
|
623
|
+
const contacts = [];
|
|
624
|
+
const normal = manifold.normal();
|
|
625
|
+
for (let i = 0; i < manifold.numContacts(); i++) {
|
|
626
|
+
const pt1 = manifold.localContactPoint1(i);
|
|
627
|
+
const dist = manifold.contactDist(i);
|
|
628
|
+
if (pt1) {
|
|
629
|
+
const contact = new ContactPoint(pt1, dist, normal);
|
|
630
|
+
contacts.push(contact);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
collision = new Collision(object, other, contacts);
|
|
634
|
+
}
|
|
635
|
+
c.onCollisionEnter.call(c, collision);
|
|
636
|
+
this.activeCollisions.push({ collider: self, component: c, collision });
|
|
637
|
+
}
|
|
580
638
|
});
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
onHandleCollisionStay() {
|
|
643
|
+
for (const active of this.activeCollisions) {
|
|
644
|
+
const c = active.component;
|
|
645
|
+
if (c.activeAndEnabled && c.onCollisionStay) {
|
|
646
|
+
const arg = active.collision;
|
|
647
|
+
c.onCollisionStay(arg);
|
|
581
648
|
}
|
|
582
|
-
}
|
|
649
|
+
}
|
|
650
|
+
for (const active of this.activeTriggers) {
|
|
651
|
+
const c = active.component;
|
|
652
|
+
if (c.activeAndEnabled && c.onTriggerStay) {
|
|
653
|
+
const arg = active.otherCollider;
|
|
654
|
+
c.onTriggerStay(arg);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
583
657
|
}
|
|
584
|
-
|
|
585
|
-
let
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
658
|
+
onCollisionEnded(self, other) {
|
|
659
|
+
for (let i = 0; i < this.activeCollisions.length; i++) {
|
|
660
|
+
const active = this.activeCollisions[i];
|
|
661
|
+
const collider = active.collider;
|
|
662
|
+
if (collider === self && active.collision.collider === other) {
|
|
663
|
+
const c = active.component;
|
|
664
|
+
this.activeCollisions.splice(i, 1);
|
|
665
|
+
i--;
|
|
666
|
+
if (c.activeAndEnabled && c.onCollisionExit) {
|
|
667
|
+
const collision = active.collision;
|
|
668
|
+
c.onCollisionExit(collision);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
for (let i = 0; i < this.activeTriggers.length; i++) {
|
|
673
|
+
const active = this.activeTriggers[i];
|
|
674
|
+
const collider = active.collider;
|
|
675
|
+
if (collider === self && active.otherCollider === other) {
|
|
676
|
+
const c = active.component;
|
|
677
|
+
this.activeTriggers.splice(i, 1);
|
|
678
|
+
i--;
|
|
679
|
+
if (c.activeAndEnabled && c.onTriggerExit) {
|
|
680
|
+
const collision = active.otherCollider;
|
|
681
|
+
c.onTriggerExit(collision);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
592
685
|
}
|
|
593
686
|
}
|
|
594
687
|
//# sourceMappingURL=engine_physics.js.map
|