@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.
Files changed (143) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/needle-engine.d.ts +248 -151
  3. package/dist/needle-engine.js +451 -437
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +82 -82
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/api.d.ts +1 -0
  8. package/lib/engine/api.js +1 -0
  9. package/lib/engine/api.js.map +1 -1
  10. package/lib/engine/debug/debug.d.ts +1 -0
  11. package/lib/engine/debug/debug.js +3 -0
  12. package/lib/engine/debug/debug.js.map +1 -1
  13. package/lib/engine/engine_addressables.d.ts +3 -1
  14. package/lib/engine/engine_addressables.js +12 -5
  15. package/lib/engine/engine_addressables.js.map +1 -1
  16. package/lib/engine/engine_element.js +3 -2
  17. package/lib/engine/engine_element.js.map +1 -1
  18. package/lib/engine/engine_element_overlay.js +4 -3
  19. package/lib/engine/engine_element_overlay.js.map +1 -1
  20. package/lib/engine/engine_gameobject.js +2 -1
  21. package/lib/engine/engine_gameobject.js.map +1 -1
  22. package/lib/engine/engine_input.d.ts +2 -0
  23. package/lib/engine/engine_input.js +14 -3
  24. package/lib/engine/engine_input.js.map +1 -1
  25. package/lib/engine/engine_physics.d.ts +35 -46
  26. package/lib/engine/engine_physics.js +479 -386
  27. package/lib/engine/engine_physics.js.map +1 -1
  28. package/lib/engine/engine_physics.types.d.ts +23 -0
  29. package/lib/engine/engine_physics.types.js +27 -0
  30. package/lib/engine/engine_physics.types.js.map +1 -0
  31. package/lib/engine/engine_serialization_core.d.ts +3 -0
  32. package/lib/engine/engine_serialization_core.js +5 -0
  33. package/lib/engine/engine_serialization_core.js.map +1 -1
  34. package/lib/engine/engine_setup.d.ts +7 -1
  35. package/lib/engine/engine_setup.js +13 -3
  36. package/lib/engine/engine_setup.js.map +1 -1
  37. package/lib/engine/engine_types.d.ts +45 -26
  38. package/lib/engine/engine_types.js +24 -37
  39. package/lib/engine/engine_types.js.map +1 -1
  40. package/lib/engine/engine_util_decorator.d.ts +6 -0
  41. package/lib/engine/engine_util_decorator.js +54 -0
  42. package/lib/engine/engine_util_decorator.js.map +1 -0
  43. package/lib/engine/engine_utils.d.ts +1 -1
  44. package/lib/engine/engine_utils.js +1 -1
  45. package/lib/engine/engine_utils.js.map +1 -1
  46. package/lib/engine/extensions/NEEDLE_gameobject_data.js +2 -0
  47. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  48. package/lib/engine-components/Animation.d.ts +7 -5
  49. package/lib/engine-components/Animation.js +7 -7
  50. package/lib/engine-components/Animation.js.map +1 -1
  51. package/lib/engine-components/AnimatorController.js +14 -7
  52. package/lib/engine-components/AnimatorController.js.map +1 -1
  53. package/lib/engine-components/BoxHelperComponent.js +1 -0
  54. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  55. package/lib/engine-components/Camera.d.ts +1 -0
  56. package/lib/engine-components/Camera.js +20 -5
  57. package/lib/engine-components/Camera.js.map +1 -1
  58. package/lib/engine-components/CharacterController.d.ts +31 -0
  59. package/lib/engine-components/CharacterController.js +167 -0
  60. package/lib/engine-components/CharacterController.js.map +1 -0
  61. package/lib/engine-components/Collider.d.ts +16 -5
  62. package/lib/engine-components/Collider.js +45 -23
  63. package/lib/engine-components/Collider.js.map +1 -1
  64. package/lib/engine-components/Component.d.ts +6 -15
  65. package/lib/engine-components/Component.js +7 -112
  66. package/lib/engine-components/Component.js.map +1 -1
  67. package/lib/engine-components/DragControls.js +9 -6
  68. package/lib/engine-components/DragControls.js.map +1 -1
  69. package/lib/engine-components/Light.d.ts +2 -0
  70. package/lib/engine-components/Light.js +13 -2
  71. package/lib/engine-components/Light.js.map +1 -1
  72. package/lib/engine-components/NavMesh.d.ts +0 -5
  73. package/lib/engine-components/NavMesh.js +100 -10
  74. package/lib/engine-components/NavMesh.js.map +1 -1
  75. package/lib/engine-components/NestedGltf.js +2 -0
  76. package/lib/engine-components/NestedGltf.js.map +1 -1
  77. package/lib/engine-components/Renderer.js +4 -0
  78. package/lib/engine-components/Renderer.js.map +1 -1
  79. package/lib/engine-components/RigidBody.d.ts +45 -25
  80. package/lib/engine-components/RigidBody.js +290 -142
  81. package/lib/engine-components/RigidBody.js.map +1 -1
  82. package/lib/engine-components/SmoothFollow.d.ts +2 -1
  83. package/lib/engine-components/SmoothFollow.js +25 -17
  84. package/lib/engine-components/SmoothFollow.js.map +1 -1
  85. package/lib/engine-components/SpatialTrigger.js +1 -1
  86. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  87. package/lib/engine-components/SpectatorCamera.d.ts +1 -0
  88. package/lib/engine-components/SpectatorCamera.js +9 -2
  89. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  90. package/lib/engine-components/SpringJoint.d.ts +0 -13
  91. package/lib/engine-components/SpringJoint.js +42 -41
  92. package/lib/engine-components/SpringJoint.js.map +1 -1
  93. package/lib/engine-components/VideoPlayer.js.map +1 -1
  94. package/lib/engine-components/WebXR.d.ts +1 -0
  95. package/lib/engine-components/WebXR.js +13 -6
  96. package/lib/engine-components/WebXR.js.map +1 -1
  97. package/lib/engine-components/WebXRController.js +12 -6
  98. package/lib/engine-components/WebXRController.js.map +1 -1
  99. package/lib/engine-components/codegen/components.d.ts +4 -3
  100. package/lib/engine-components/codegen/components.js +4 -3
  101. package/lib/engine-components/codegen/components.js.map +1 -1
  102. package/package.json +3 -4
  103. package/src/engine/api.ts +2 -1
  104. package/src/engine/codegen/register_types.js +16 -12
  105. package/src/engine/debug/debug.ts +4 -0
  106. package/src/engine/dist/engine_physics.js +739 -0
  107. package/src/engine/dist/engine_setup.js +777 -0
  108. package/src/engine/engine_addressables.ts +18 -8
  109. package/src/engine/engine_element.ts +3 -2
  110. package/src/engine/engine_element_overlay.ts +4 -3
  111. package/src/engine/engine_gameobject.ts +4 -4
  112. package/src/engine/engine_input.ts +12 -3
  113. package/src/engine/engine_physics.ts +492 -418
  114. package/src/engine/engine_physics.types.ts +28 -0
  115. package/src/engine/engine_serialization_core.ts +8 -1
  116. package/src/engine/engine_setup.ts +31 -18
  117. package/src/engine/engine_types.ts +83 -56
  118. package/src/engine/engine_util_decorator.ts +69 -0
  119. package/src/engine/engine_utils.ts +3 -3
  120. package/src/engine/extensions/NEEDLE_gameobject_data.ts +2 -0
  121. package/src/engine-components/Animation.ts +18 -12
  122. package/src/engine-components/AnimatorController.ts +16 -11
  123. package/src/engine-components/BoxHelperComponent.ts +1 -0
  124. package/src/engine-components/Camera.ts +21 -4
  125. package/src/engine-components/CharacterController.ts +171 -0
  126. package/src/engine-components/Collider.ts +49 -39
  127. package/src/engine-components/Component.ts +15 -130
  128. package/src/engine-components/DragControls.ts +9 -5
  129. package/src/engine-components/Light.ts +17 -3
  130. package/src/engine-components/NavMesh.ts +114 -115
  131. package/src/engine-components/NestedGltf.ts +2 -0
  132. package/src/engine-components/Renderer.ts +5 -1
  133. package/src/engine-components/RigidBody.ts +292 -149
  134. package/src/engine-components/SmoothFollow.ts +21 -18
  135. package/src/engine-components/SpatialTrigger.ts +1 -1
  136. package/src/engine-components/SpectatorCamera.ts +10 -2
  137. package/src/engine-components/SpringJoint.ts +41 -41
  138. package/src/engine-components/VideoPlayer.ts +1 -2
  139. package/src/engine-components/WebXR.ts +15 -6
  140. package/src/engine-components/WebXRController.ts +16 -7
  141. package/src/engine-components/codegen/components.ts +4 -3
  142. package/src/engine-components/dist/CharacterController.js +123 -0
  143. package/src/engine-components/dist/RigidBody.js +458 -0
@@ -1,38 +1,17 @@
1
- import { Body, Box, Vec3, World, Sphere as PhysicsSphere, Quaternion as PhysicsQuaternion } from 'cannon-es';
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 { $physicsKey, Collision } from './engine_types';
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
- export class BodyOptions {
12
- mass = 1;
13
- kinematic = false;
14
- physicsEvents = false;
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
- get isUpdating() { return this._isUpdatingPhysicsWorld; }
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 = new World();
186
+ world;
187
+ _hasCreatedWorld = false;
188
+ eventQueue;
189
+ collisionHandler;
190
+ // private rigidbodies: Array<IRigidbody | null> = [];
203
191
  objects = [];
204
- tempPosition = new Vector3();
205
- tempQuaternion = new Quaternion();
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
- this.world.gravity.set(0, -9.82, 0);
209
- if (debugPhysics) {
210
- // https://www.npmjs.com/package/cannon-es-debugger
211
- const opts = {};
212
- opts["onInit"] = (_body, mesh, _shape) => {
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
- // dont add the body before it has shapes
247
- // otherwise things like forces appplied in the frame before the shapes exist will be zeroed out
248
- if (body.shapes.length > 0)
249
- this.world.addBody(body);
250
- }
251
- removeBody(go, body, removeCompletely = true) {
252
- this.world.removeBody(body);
253
- for (let i = 0; i < this.objects.length; i++) {
254
- const reg = this.objects[i];
255
- if (reg.obj === go) {
256
- reg._hasRigidbody = false;
257
- if (removeCompletely)
258
- this.objects.splice(i, 1);
259
- break;
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
- removeShape(obj, shape) {
264
- for (const reg of this.objects) {
265
- if (reg.obj === obj) {
266
- if (reg.body) {
267
- reg.body.removeShape(shape);
268
- reg.body.updateMassProperties();
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
- return;
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
- // TODO: make it work with rigibody in parent
275
- createBody(obj, settings) {
276
- const body = this.internalCreateBody(obj, null);
277
- if (settings.mass)
278
- body.mass = settings.mass;
279
- if (settings.kinematic)
280
- body.type = Body.KINEMATIC;
281
- else
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
- // console.log("has no rb", obj);
384
- body = this.internalCreateBody(obj, null);
385
- body.type = Body.KINEMATIC;
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
- // get rotation difference
412
- wp.add(center);
413
- // if (rb) {
414
- // this.tempMat.setPosition(wp);
415
- // this.tempMat.makeRotationFromQuaternion(wr);
416
- // this.tempMat.multiplyMatrices(this.tempMat, rb?.gameObject.matrix);
417
- // this.tempMat.decompose(this.tempPosition, this.tempQuaternion, new Vector3());
418
- // wp.copy(this.tempPosition);
419
- // }
420
- // wp.applyQuaternion(wr);
421
- const pos = new Vec3(wp.x, wp.y, wp.z);
422
- const rot = new PhysicsQuaternion(wr.x, wr.y, wr.z, wr.w);
423
- body.addShape(shape, pos, rot);
424
- body.updateMassProperties();
425
- this.world.addBody(body);
426
- }
427
- return body;
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
- step(deltaTime) {
422
+ lines;
423
+ step(_deltaTime) {
424
+ if (!this.world)
425
+ return;
431
426
  this._isUpdatingPhysicsWorld = true;
432
- deltaTime = Math.min(deltaTime, 1 / 30);
433
- this.world.step(deltaTime);
427
+ if (!this.eventQueue) {
428
+ this.eventQueue = new EventQueue(false);
429
+ }
430
+ this.world.step(this.eventQueue);
434
431
  this._isUpdatingPhysicsWorld = false;
435
- if (debugPhysics && this.context.time.frameCount % 60 === 0) {
436
- // console.log("physics world has " + this.world.bodies.length + " bodies", this.world);
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
- for (let i = 0; i < this.objects.length; i++) {
444
- const entry = this.objects[i];
445
- const body = entry.body;
446
- if (!body || !body.world)
447
- continue;
448
- const obj = entry.obj;
449
- body.sleepTick(this.context.time.time);
450
- if (debugPhysics) {
451
- if (!entry._didSleepLastStep && body.sleepState === Body.SLEEPING) {
452
- console.log("BODY SLEEPING", body);
453
- }
454
- else if (entry._didSleepLastStep && body.sleepState !== Body.SLEEPING) {
455
- console.log("BODY WOKE UP", body);
456
- }
457
- }
458
- entry._didSleepLastStep = body.sleepState === Body.SLEEPING;
459
- // if(body.sleepState === Body.SLEEPING) {
460
- // console.log("SLEEP", body.name);
461
- // }
462
- // if (body.type == Body.KINEMATIC) continue;
463
- if (body.type === Body.KINEMATIC) {
464
- const wp = getWorldPosition(obj, this.temp);
465
- body.position.set(wp.x, wp.y, wp.z);
466
- const rot = getWorldQuaternion(obj, this.tempQuat);
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
- // when reparenting (e.g. attached to controller) I think it doesnt work with previous parent? need to test again, to tired now
476
- if (entry.parent && obj.parent === entry.parent) {
477
- setWorldQuaternionXYZW(obj, body.quaternion.x, body.quaternion.y, body.quaternion.z, body.quaternion.w);
478
- const p = body.position;
479
- setWorldPositionXYZ(obj, p.x, p.y, p.z);
480
- if (body.velocity.length() > body.sleepSpeedLimit) {
481
- InstancingUtil.markDirty(obj);
482
- }
483
- // this.worldToLocal.x = body.position.x;
484
- // this.worldToLocal.y = body.position.y;
485
- // this.worldToLocal.z = body.position.z;
486
- // const pos = entry.parent.worldToLocal(this.worldToLocal);
487
- // obj.position.x = pos.x;
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
- internalCreateBody(obj, shape) {
505
- const body = new Body();
506
- body["_owner"] = obj;
507
- body["_name"] = obj.name;
508
- obj.getWorldPosition(this.tempPosition);
509
- const pos = this.tempPosition;
510
- body.position = new Vec3(pos.x, pos.y, pos.z);
511
- const quat = this.tempQuaternion;
512
- obj.getWorldQuaternion(quat);
513
- body.quaternion = new PhysicsQuaternion(quat.x, quat.y, quat.z, quat.w);
514
- body.type = Body.KINEMATIC;
515
- if (shape) {
516
- body.addShape(shape);
517
- body.updateMassProperties();
518
- }
519
- return body;
520
- }
521
- // private findObject(obj: Object3D): PhysicsObject | null {
522
- // for (let i = 0; i < this.objects.length; i++) {
523
- // const entry = this.objects[i];
524
- // if (entry.obj == obj)
525
- // return entry;
526
- // }
527
- // return null;
528
- // }
529
- registerCollisionEvents(obj) {
530
- if (obj.collisonCallback)
531
- this.unregisterCollisionEvents(obj);
532
- if (!obj.body)
533
- return;
534
- const evt = evt => this.raiseCollisionEvents(obj.obj, evt);
535
- obj.collisonCallback = evt.bind(this);
536
- obj.body.addEventListener("collide", obj.collisonCallback);
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
- unregisterCollisionEvents(obj) {
539
- if (!obj.collisonCallback)
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 (!obj.body)
581
+ if (!this.world)
542
582
  return;
543
- obj.body.removeEventListener("collide", obj.collisonCallback);
544
- }
545
- onBeginContact(_) {
546
- // this is called after the object collide event so we dont really need it
547
- // console.log("START");
548
- }
549
- collisionContext = new CollisionContext();
550
- raiseCollisionEvents(obj, event) {
551
- const collision = new Collision(obj, event, this.collisionContext);
552
- if (debugCollisions)
553
- console.log("collision between", event.contact.bi, event.contact.bj, obj, event);
554
- foreachComponent(obj, (c) => {
555
- c.__internalHandleCollision(collision, false);
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
- // handle triggers
558
- if (collision.collider && !collision.collider.attachedRigidbody && collision.collider.isTrigger) {
559
- const collision2 = new Collision(collision.gameObject, event, this.collisionContext, true);
560
- foreachComponent(collision.gameObject, (c) => {
561
- c.__internalHandleCollision(collision2, true);
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
- onEndContact(args) {
566
- // if(args.bodyB.sleepState !== Body.AWAKE) return;
567
- // console.log("END", BODY_SLEEP_STATES, args.bodyB.sleepState);
568
- const obj1 = args.bodyA[$physicsKey];
569
- const obj2 = args.bodyB[$physicsKey];
570
- // console.log(obj2);
571
- foreachComponent(obj2, (c) => {
572
- c.__internalHandleExitCollisionEvent(obj1, false);
573
- });
574
- // TODO: stop iterating when we found the collider
575
- foreachComponent(obj1, c => {
576
- const collider = c;
577
- if (collider.isCollider && !collider.attachedRigidbody && collider.isTrigger) {
578
- foreachComponent(collider.gameObject, (c) => {
579
- c.__internalHandleExitCollisionEvent(obj2, true);
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 colliderProvider = null;
586
- export function registerColliderProvider(prov) {
587
- colliderProvider = prov;
588
- }
589
- class CollisionContext {
590
- getCollider(obj) {
591
- return colliderProvider.getCollider(obj);
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