@rapierphysicsplugin/client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/__tests__/clock-sync.test.d.ts +2 -0
  2. package/dist/__tests__/clock-sync.test.d.ts.map +1 -0
  3. package/dist/__tests__/clock-sync.test.js +63 -0
  4. package/dist/__tests__/clock-sync.test.js.map +1 -0
  5. package/dist/__tests__/interpolator.test.d.ts +2 -0
  6. package/dist/__tests__/interpolator.test.d.ts.map +1 -0
  7. package/dist/__tests__/interpolator.test.js +82 -0
  8. package/dist/__tests__/interpolator.test.js.map +1 -0
  9. package/dist/__tests__/state-reconciler.test.d.ts +2 -0
  10. package/dist/__tests__/state-reconciler.test.d.ts.map +1 -0
  11. package/dist/__tests__/state-reconciler.test.js +86 -0
  12. package/dist/__tests__/state-reconciler.test.js.map +1 -0
  13. package/dist/clock-sync.d.ts +17 -0
  14. package/dist/clock-sync.d.ts.map +1 -0
  15. package/dist/clock-sync.js +63 -0
  16. package/dist/clock-sync.js.map +1 -0
  17. package/dist/index.d.ts +10 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +8 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/input-manager.d.ts +18 -0
  22. package/dist/input-manager.d.ts.map +1 -0
  23. package/dist/input-manager.js +62 -0
  24. package/dist/input-manager.js.map +1 -0
  25. package/dist/interpolator.d.ts +35 -0
  26. package/dist/interpolator.d.ts.map +1 -0
  27. package/dist/interpolator.js +198 -0
  28. package/dist/interpolator.js.map +1 -0
  29. package/dist/networked-rapier-plugin.d.ts +82 -0
  30. package/dist/networked-rapier-plugin.d.ts.map +1 -0
  31. package/dist/networked-rapier-plugin.js +698 -0
  32. package/dist/networked-rapier-plugin.js.map +1 -0
  33. package/dist/rapier-body-ops.d.ts +27 -0
  34. package/dist/rapier-body-ops.d.ts.map +1 -0
  35. package/dist/rapier-body-ops.js +208 -0
  36. package/dist/rapier-body-ops.js.map +1 -0
  37. package/dist/rapier-collision-ops.d.ts +6 -0
  38. package/dist/rapier-collision-ops.d.ts.map +1 -0
  39. package/dist/rapier-collision-ops.js +200 -0
  40. package/dist/rapier-collision-ops.js.map +1 -0
  41. package/dist/rapier-constraint-ops.d.ts +29 -0
  42. package/dist/rapier-constraint-ops.d.ts.map +1 -0
  43. package/dist/rapier-constraint-ops.js +286 -0
  44. package/dist/rapier-constraint-ops.js.map +1 -0
  45. package/dist/rapier-plugin.d.ts +145 -0
  46. package/dist/rapier-plugin.d.ts.map +1 -0
  47. package/dist/rapier-plugin.js +263 -0
  48. package/dist/rapier-plugin.js.map +1 -0
  49. package/dist/rapier-shape-ops.d.ts +21 -0
  50. package/dist/rapier-shape-ops.d.ts.map +1 -0
  51. package/dist/rapier-shape-ops.js +314 -0
  52. package/dist/rapier-shape-ops.js.map +1 -0
  53. package/dist/rapier-types.d.ts +58 -0
  54. package/dist/rapier-types.d.ts.map +1 -0
  55. package/dist/rapier-types.js +4 -0
  56. package/dist/rapier-types.js.map +1 -0
  57. package/dist/state-reconciler.d.ts +28 -0
  58. package/dist/state-reconciler.d.ts.map +1 -0
  59. package/dist/state-reconciler.js +119 -0
  60. package/dist/state-reconciler.js.map +1 -0
  61. package/dist/sync-client.d.ts +110 -0
  62. package/dist/sync-client.d.ts.map +1 -0
  63. package/dist/sync-client.js +514 -0
  64. package/dist/sync-client.js.map +1 -0
  65. package/package.json +21 -0
  66. package/src/__tests__/clock-sync.test.ts +72 -0
  67. package/src/__tests__/interpolator.test.ts +98 -0
  68. package/src/__tests__/state-reconciler.test.ts +102 -0
  69. package/src/clock-sync.ts +77 -0
  70. package/src/index.ts +9 -0
  71. package/src/input-manager.ts +72 -0
  72. package/src/interpolator.ts +256 -0
  73. package/src/networked-rapier-plugin.ts +909 -0
  74. package/src/rapier-body-ops.ts +251 -0
  75. package/src/rapier-collision-ops.ts +229 -0
  76. package/src/rapier-constraint-ops.ts +327 -0
  77. package/src/rapier-plugin.ts +364 -0
  78. package/src/rapier-shape-ops.ts +369 -0
  79. package/src/rapier-types.ts +60 -0
  80. package/src/state-reconciler.ts +151 -0
  81. package/src/sync-client.ts +640 -0
  82. package/tsconfig.json +12 -0
  83. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,251 @@
1
+ import type RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Vector3, Quaternion, PhysicsMotionType } from '@babylonjs/core';
3
+ import type {
4
+ PhysicsBody,
5
+ PhysicsMassProperties,
6
+ TransformNode,
7
+ } from '@babylonjs/core';
8
+ import type { RapierPluginState } from './rapier-types.js';
9
+
10
+ export function initBody(
11
+ state: RapierPluginState,
12
+ body: PhysicsBody,
13
+ motionType: PhysicsMotionType,
14
+ position: Vector3,
15
+ orientation: Quaternion,
16
+ ): void {
17
+ let bodyDesc: RAPIER.RigidBodyDesc;
18
+ switch (motionType) {
19
+ case PhysicsMotionType.DYNAMIC:
20
+ bodyDesc = state.rapier.RigidBodyDesc.dynamic();
21
+ break;
22
+ case PhysicsMotionType.STATIC:
23
+ bodyDesc = state.rapier.RigidBodyDesc.fixed();
24
+ break;
25
+ case PhysicsMotionType.ANIMATED:
26
+ bodyDesc = state.rapier.RigidBodyDesc.kinematicPositionBased();
27
+ break;
28
+ default:
29
+ bodyDesc = state.rapier.RigidBodyDesc.dynamic();
30
+ }
31
+
32
+ bodyDesc.setTranslation(position.x, position.y, position.z);
33
+ bodyDesc.setRotation(new state.rapier.Quaternion(orientation.x, orientation.y, orientation.z, orientation.w));
34
+
35
+ const rigidBody = state.world.createRigidBody(bodyDesc);
36
+ state.bodyToRigidBody.set(body, rigidBody);
37
+ state.bodyToColliders.set(body, []);
38
+ }
39
+
40
+ export function disposeBody(state: RapierPluginState, body: PhysicsBody): void {
41
+ const rb = state.bodyToRigidBody.get(body);
42
+ if (rb) {
43
+ const colliders = state.bodyToColliders.get(body) ?? [];
44
+ for (const col of colliders) {
45
+ state.colliderHandleToBody.delete(col.handle);
46
+ }
47
+
48
+ state.world.removeRigidBody(rb);
49
+ state.bodyToRigidBody.delete(body);
50
+ state.bodyToColliders.delete(body);
51
+ state.bodyCollisionObservables.delete(body);
52
+ state.bodyCollisionEndedObservables.delete(body);
53
+ state.collisionCallbackEnabled.delete(body);
54
+ state.collisionEndedCallbackEnabled.delete(body);
55
+
56
+ const shape = state.bodyToShape.get(body);
57
+ if (shape) {
58
+ state.shapeToBody.delete(shape);
59
+ }
60
+ state.bodyToShape.delete(body);
61
+ state.bodyEventMask.delete(body);
62
+ }
63
+ }
64
+
65
+ export function syncBody(state: RapierPluginState, body: PhysicsBody): void {
66
+ const rb = state.bodyToRigidBody.get(body);
67
+ if (!rb) return;
68
+ const tn = body.transformNode;
69
+ if (!tn) return;
70
+
71
+ const pos = rb.translation();
72
+ const rot = rb.rotation();
73
+ tn.position.set(pos.x, pos.y, pos.z);
74
+ tn.rotationQuaternion = tn.rotationQuaternion ?? new Quaternion();
75
+ tn.rotationQuaternion.set(rot.x, rot.y, rot.z, rot.w);
76
+ }
77
+
78
+ export function syncTransform(state: RapierPluginState, body: PhysicsBody, transformNode: TransformNode): void {
79
+ const rb = state.bodyToRigidBody.get(body);
80
+ if (!rb) return;
81
+
82
+ const pos = rb.translation();
83
+ const rot = rb.rotation();
84
+ transformNode.position.set(pos.x, pos.y, pos.z);
85
+ transformNode.rotationQuaternion = transformNode.rotationQuaternion ?? new Quaternion();
86
+ transformNode.rotationQuaternion.set(rot.x, rot.y, rot.z, rot.w);
87
+ }
88
+
89
+ export function setMotionType(state: RapierPluginState, body: PhysicsBody, motionType: PhysicsMotionType): void {
90
+ const rb = state.bodyToRigidBody.get(body);
91
+ if (!rb) return;
92
+
93
+ switch (motionType) {
94
+ case PhysicsMotionType.DYNAMIC:
95
+ rb.setBodyType(state.rapier.RigidBodyType.Dynamic, true);
96
+ break;
97
+ case PhysicsMotionType.STATIC:
98
+ rb.setBodyType(state.rapier.RigidBodyType.Fixed, true);
99
+ break;
100
+ case PhysicsMotionType.ANIMATED:
101
+ rb.setBodyType(state.rapier.RigidBodyType.KinematicPositionBased, true);
102
+ break;
103
+ }
104
+ }
105
+
106
+ export function getMotionType(state: RapierPluginState, body: PhysicsBody): PhysicsMotionType {
107
+ const rb = state.bodyToRigidBody.get(body);
108
+ if (!rb) return PhysicsMotionType.STATIC;
109
+
110
+ if (rb.isDynamic()) return PhysicsMotionType.DYNAMIC;
111
+ if (rb.isKinematic()) return PhysicsMotionType.ANIMATED;
112
+ return PhysicsMotionType.STATIC;
113
+ }
114
+
115
+ export function computeMassProperties(state: RapierPluginState, body: PhysicsBody): PhysicsMassProperties {
116
+ const rb = state.bodyToRigidBody.get(body);
117
+ if (!rb) return { mass: 1, centerOfMass: Vector3.Zero(), inertia: Vector3.One(), inertiaOrientation: Quaternion.Identity() };
118
+ const com = rb.localCom();
119
+ const inertia = rb.principalInertia();
120
+ const inertiaFrame = rb.principalInertiaLocalFrame();
121
+ return {
122
+ mass: rb.mass(),
123
+ centerOfMass: new Vector3(com.x, com.y, com.z),
124
+ inertia: new Vector3(inertia.x, inertia.y, inertia.z),
125
+ inertiaOrientation: new Quaternion(inertiaFrame.x, inertiaFrame.y, inertiaFrame.z, inertiaFrame.w),
126
+ };
127
+ }
128
+
129
+ export function setMassProperties(state: RapierPluginState, body: PhysicsBody, massProps: PhysicsMassProperties): void {
130
+ const rb = state.bodyToRigidBody.get(body);
131
+ if (!rb) return;
132
+
133
+ const mass = massProps.mass ?? 0;
134
+ const com = massProps.centerOfMass ?? Vector3.Zero();
135
+ const inertia = massProps.inertia ?? Vector3.Zero();
136
+ const inertiaOrientation = massProps.inertiaOrientation ?? Quaternion.Identity();
137
+
138
+ rb.setAdditionalMassProperties(
139
+ mass,
140
+ new state.rapier.Vector3(com.x, com.y, com.z),
141
+ new state.rapier.Vector3(inertia.x, inertia.y, inertia.z),
142
+ new state.rapier.Quaternion(inertiaOrientation.x, inertiaOrientation.y, inertiaOrientation.z, inertiaOrientation.w),
143
+ true
144
+ );
145
+ }
146
+
147
+ export function getMassProperties(state: RapierPluginState, body: PhysicsBody): PhysicsMassProperties {
148
+ const rb = state.bodyToRigidBody.get(body);
149
+ if (!rb) return { mass: 1, centerOfMass: Vector3.Zero(), inertia: Vector3.One(), inertiaOrientation: Quaternion.Identity() };
150
+ const com = rb.localCom();
151
+ const inertia = rb.principalInertia();
152
+ const inertiaFrame = rb.principalInertiaLocalFrame();
153
+ return {
154
+ mass: rb.mass(),
155
+ centerOfMass: new Vector3(com.x, com.y, com.z),
156
+ inertia: new Vector3(inertia.x, inertia.y, inertia.z),
157
+ inertiaOrientation: new Quaternion(inertiaFrame.x, inertiaFrame.y, inertiaFrame.z, inertiaFrame.w),
158
+ };
159
+ }
160
+
161
+ export function setLinearDamping(state: RapierPluginState, body: PhysicsBody, damping: number): void {
162
+ const rb = state.bodyToRigidBody.get(body);
163
+ if (rb) rb.setLinearDamping(damping);
164
+ }
165
+
166
+ export function getLinearDamping(state: RapierPluginState, body: PhysicsBody): number {
167
+ const rb = state.bodyToRigidBody.get(body);
168
+ return rb?.linearDamping() ?? 0;
169
+ }
170
+
171
+ export function setAngularDamping(state: RapierPluginState, body: PhysicsBody, damping: number): void {
172
+ const rb = state.bodyToRigidBody.get(body);
173
+ if (rb) rb.setAngularDamping(damping);
174
+ }
175
+
176
+ export function getAngularDamping(state: RapierPluginState, body: PhysicsBody): number {
177
+ const rb = state.bodyToRigidBody.get(body);
178
+ return rb?.angularDamping() ?? 0;
179
+ }
180
+
181
+ export function setLinearVelocity(state: RapierPluginState, body: PhysicsBody, linVel: Vector3): void {
182
+ const rb = state.bodyToRigidBody.get(body);
183
+ if (rb) rb.setLinvel(new state.rapier.Vector3(linVel.x, linVel.y, linVel.z), true);
184
+ }
185
+
186
+ export function getLinearVelocityToRef(state: RapierPluginState, body: PhysicsBody, linVel: Vector3): void {
187
+ const rb = state.bodyToRigidBody.get(body);
188
+ if (rb) {
189
+ const v = rb.linvel();
190
+ linVel.set(v.x, v.y, v.z);
191
+ }
192
+ }
193
+
194
+ export function setAngularVelocity(state: RapierPluginState, body: PhysicsBody, angVel: Vector3): void {
195
+ const rb = state.bodyToRigidBody.get(body);
196
+ if (rb) rb.setAngvel(new state.rapier.Vector3(angVel.x, angVel.y, angVel.z), true);
197
+ }
198
+
199
+ export function getAngularVelocityToRef(state: RapierPluginState, body: PhysicsBody, angVel: Vector3): void {
200
+ const rb = state.bodyToRigidBody.get(body);
201
+ if (rb) {
202
+ const v = rb.angvel();
203
+ angVel.set(v.x, v.y, v.z);
204
+ }
205
+ }
206
+
207
+ export function applyImpulse(state: RapierPluginState, body: PhysicsBody, impulse: Vector3, location: Vector3): void {
208
+ const rb = state.bodyToRigidBody.get(body);
209
+ if (!rb) return;
210
+
211
+ rb.applyImpulseAtPoint(
212
+ new state.rapier.Vector3(impulse.x, impulse.y, impulse.z),
213
+ new state.rapier.Vector3(location.x, location.y, location.z),
214
+ true
215
+ );
216
+ }
217
+
218
+ export function applyAngularImpulse(state: RapierPluginState, body: PhysicsBody, angularImpulse: Vector3): void {
219
+ const rb = state.bodyToRigidBody.get(body);
220
+ if (!rb) return;
221
+ rb.applyTorqueImpulse(new state.rapier.Vector3(angularImpulse.x, angularImpulse.y, angularImpulse.z), true);
222
+ }
223
+
224
+ export function applyForce(state: RapierPluginState, body: PhysicsBody, force: Vector3, location: Vector3): void {
225
+ const rb = state.bodyToRigidBody.get(body);
226
+ if (!rb) return;
227
+
228
+ rb.addForceAtPoint(
229
+ new state.rapier.Vector3(force.x, force.y, force.z),
230
+ new state.rapier.Vector3(location.x, location.y, location.z),
231
+ true
232
+ );
233
+ }
234
+
235
+ export function setGravityFactor(state: RapierPluginState, body: PhysicsBody, factor: number): void {
236
+ const rb = state.bodyToRigidBody.get(body);
237
+ if (rb) rb.setGravityScale(factor, true);
238
+ }
239
+
240
+ export function getGravityFactor(state: RapierPluginState, body: PhysicsBody): number {
241
+ const rb = state.bodyToRigidBody.get(body);
242
+ return rb?.gravityScale() ?? 1;
243
+ }
244
+
245
+ export function setTargetTransform(state: RapierPluginState, body: PhysicsBody, position: Vector3, rotation: Quaternion): void {
246
+ const rb = state.bodyToRigidBody.get(body);
247
+ if (!rb) return;
248
+
249
+ rb.setNextKinematicTranslation(new state.rapier.Vector3(position.x, position.y, position.z));
250
+ rb.setNextKinematicRotation(new state.rapier.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w));
251
+ }
@@ -0,0 +1,229 @@
1
+ import type RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Vector3, PhysicsEventType } from '@babylonjs/core';
3
+ import type {
4
+ PhysicsBody,
5
+ IPhysicsCollisionEvent,
6
+ IBasePhysicsCollisionEvent,
7
+ Nullable,
8
+ } from '@babylonjs/core';
9
+ import type { CollisionEventData } from '@rapierphysicsplugin/shared';
10
+ import type { RapierPluginState } from './rapier-types.js';
11
+
12
+ export function processCollisionEvents(
13
+ state: RapierPluginState,
14
+ eventQueue: RAPIER.EventQueue,
15
+ ): void {
16
+ eventQueue.drainCollisionEvents((handle1: number, handle2: number, started: boolean) => {
17
+ const body1 = state.colliderHandleToBody.get(handle1);
18
+ const body2 = state.colliderHandleToBody.get(handle2);
19
+ if (!body1 || !body2) return;
20
+
21
+ const collider1 = state.world.getCollider(handle1);
22
+ const collider2 = state.world.getCollider(handle2);
23
+ if (!collider1 || !collider2) return;
24
+
25
+ const isSensor = collider1.isSensor() || collider2.isSensor();
26
+
27
+ if (isSensor) {
28
+ const eventType = started ? PhysicsEventType.TRIGGER_ENTERED : PhysicsEventType.TRIGGER_EXITED;
29
+ const baseEvent1: IBasePhysicsCollisionEvent = {
30
+ collider: body1,
31
+ collidedAgainst: body2,
32
+ colliderIndex: 0,
33
+ collidedAgainstIndex: 0,
34
+ type: eventType,
35
+ };
36
+ const baseEvent2: IBasePhysicsCollisionEvent = {
37
+ collider: body2,
38
+ collidedAgainst: body1,
39
+ colliderIndex: 0,
40
+ collidedAgainstIndex: 0,
41
+ type: eventType,
42
+ };
43
+
44
+ state.onTriggerCollisionObservable.notifyObservers(baseEvent1);
45
+
46
+ if (state.collisionCallbackEnabled.has(body1)) {
47
+ const triggerEvent: IPhysicsCollisionEvent = { ...baseEvent1, point: null, normal: null, distance: 0, impulse: 0 };
48
+ state.bodyCollisionObservables.get(body1)?.notifyObservers(triggerEvent);
49
+ }
50
+ if (state.collisionCallbackEnabled.has(body2)) {
51
+ const triggerEvent: IPhysicsCollisionEvent = { ...baseEvent2, point: null, normal: null, distance: 0, impulse: 0 };
52
+ state.bodyCollisionObservables.get(body2)?.notifyObservers(triggerEvent);
53
+ }
54
+ } else if (started) {
55
+ let point: Nullable<Vector3> = null;
56
+ let normal: Nullable<Vector3> = null;
57
+ let impulse = 0;
58
+
59
+ state.world.contactPair(collider1, collider2, (manifold, flipped) => {
60
+ const n = manifold.normal();
61
+ normal = flipped
62
+ ? new Vector3(-n.x, -n.y, -n.z)
63
+ : new Vector3(n.x, n.y, n.z);
64
+
65
+ if (manifold.numContacts() > 0) {
66
+ const cp = manifold.localContactPoint1(0);
67
+ if (cp) {
68
+ const t = collider1.translation();
69
+ point = new Vector3(cp.x + t.x, cp.y + t.y, cp.z + t.z);
70
+ }
71
+ impulse = manifold.contactImpulse(0);
72
+ }
73
+ });
74
+
75
+ const eventType = PhysicsEventType.COLLISION_STARTED;
76
+ const fullEvent1: IPhysicsCollisionEvent = {
77
+ collider: body1,
78
+ collidedAgainst: body2,
79
+ colliderIndex: 0,
80
+ collidedAgainstIndex: 0,
81
+ type: eventType,
82
+ point,
83
+ normal,
84
+ distance: 0,
85
+ impulse,
86
+ };
87
+ const fullEvent2: IPhysicsCollisionEvent = {
88
+ collider: body2,
89
+ collidedAgainst: body1,
90
+ colliderIndex: 0,
91
+ collidedAgainstIndex: 0,
92
+ type: eventType,
93
+ point,
94
+ normal: normal ? (normal as Vector3).negate() : null,
95
+ distance: 0,
96
+ impulse,
97
+ };
98
+
99
+ state.onCollisionObservable.notifyObservers(fullEvent1);
100
+
101
+ if (state.collisionCallbackEnabled.has(body1)) {
102
+ state.bodyCollisionObservables.get(body1)?.notifyObservers(fullEvent1);
103
+ }
104
+ if (state.collisionCallbackEnabled.has(body2)) {
105
+ state.bodyCollisionObservables.get(body2)?.notifyObservers(fullEvent2);
106
+ }
107
+ } else {
108
+ const eventType = PhysicsEventType.COLLISION_FINISHED;
109
+ const baseEvent1: IBasePhysicsCollisionEvent = {
110
+ collider: body1,
111
+ collidedAgainst: body2,
112
+ colliderIndex: 0,
113
+ collidedAgainstIndex: 0,
114
+ type: eventType,
115
+ };
116
+ const baseEvent2: IBasePhysicsCollisionEvent = {
117
+ collider: body2,
118
+ collidedAgainst: body1,
119
+ colliderIndex: 0,
120
+ collidedAgainstIndex: 0,
121
+ type: eventType,
122
+ };
123
+
124
+ state.onCollisionEndedObservable.notifyObservers(baseEvent1);
125
+
126
+ if (state.collisionEndedCallbackEnabled.has(body1)) {
127
+ state.bodyCollisionEndedObservables.get(body1)?.notifyObservers(baseEvent1);
128
+ }
129
+ if (state.collisionEndedCallbackEnabled.has(body2)) {
130
+ state.bodyCollisionEndedObservables.get(body2)?.notifyObservers(baseEvent2);
131
+ }
132
+ }
133
+ });
134
+ }
135
+
136
+ export function injectCollisionEvents(state: RapierPluginState, events: CollisionEventData[]): void {
137
+ for (const event of events) {
138
+ const bodyA = state.bodyIdToPhysicsBody.get(event.bodyIdA);
139
+ const bodyB = state.bodyIdToPhysicsBody.get(event.bodyIdB);
140
+ if (!bodyA || !bodyB) continue;
141
+
142
+ const point = event.point ? new Vector3(event.point.x, event.point.y, event.point.z) : null;
143
+ const normal = event.normal ? new Vector3(event.normal.x, event.normal.y, event.normal.z) : null;
144
+
145
+ const eventType = PhysicsEventType[event.type as keyof typeof PhysicsEventType];
146
+
147
+ const baseEventA: IBasePhysicsCollisionEvent = {
148
+ collider: bodyA,
149
+ collidedAgainst: bodyB,
150
+ colliderIndex: 0,
151
+ collidedAgainstIndex: 0,
152
+ type: eventType,
153
+ };
154
+
155
+ const baseEventB: IBasePhysicsCollisionEvent = {
156
+ collider: bodyB,
157
+ collidedAgainst: bodyA,
158
+ colliderIndex: 0,
159
+ collidedAgainstIndex: 0,
160
+ type: eventType,
161
+ };
162
+
163
+ switch (event.type) {
164
+ case 'COLLISION_STARTED': {
165
+ const fullEventA: IPhysicsCollisionEvent = {
166
+ ...baseEventA,
167
+ point,
168
+ normal,
169
+ distance: 0,
170
+ impulse: event.impulse,
171
+ };
172
+ const fullEventB: IPhysicsCollisionEvent = {
173
+ ...baseEventB,
174
+ point,
175
+ normal: normal ? normal.negate() : null,
176
+ distance: 0,
177
+ impulse: event.impulse,
178
+ };
179
+
180
+ state.onCollisionObservable.notifyObservers(fullEventA);
181
+
182
+ if (state.collisionCallbackEnabled.has(bodyA)) {
183
+ state.bodyCollisionObservables.get(bodyA)?.notifyObservers(fullEventA);
184
+ }
185
+ if (state.collisionCallbackEnabled.has(bodyB)) {
186
+ state.bodyCollisionObservables.get(bodyB)?.notifyObservers(fullEventB);
187
+ }
188
+ break;
189
+ }
190
+ case 'COLLISION_FINISHED': {
191
+ state.onCollisionEndedObservable.notifyObservers(baseEventA);
192
+
193
+ if (state.collisionEndedCallbackEnabled.has(bodyA)) {
194
+ state.bodyCollisionEndedObservables.get(bodyA)?.notifyObservers(baseEventA);
195
+ }
196
+ if (state.collisionEndedCallbackEnabled.has(bodyB)) {
197
+ state.bodyCollisionEndedObservables.get(bodyB)?.notifyObservers(baseEventB);
198
+ }
199
+ break;
200
+ }
201
+ case 'TRIGGER_ENTERED':
202
+ case 'TRIGGER_EXITED': {
203
+ state.onTriggerCollisionObservable.notifyObservers(baseEventA);
204
+
205
+ if (state.collisionCallbackEnabled.has(bodyA)) {
206
+ const triggerEventA: IPhysicsCollisionEvent = {
207
+ ...baseEventA,
208
+ point: null,
209
+ normal: null,
210
+ distance: 0,
211
+ impulse: 0,
212
+ };
213
+ state.bodyCollisionObservables.get(bodyA)?.notifyObservers(triggerEventA);
214
+ }
215
+ if (state.collisionCallbackEnabled.has(bodyB)) {
216
+ const triggerEventB: IPhysicsCollisionEvent = {
217
+ ...baseEventB,
218
+ point: null,
219
+ normal: null,
220
+ distance: 0,
221
+ impulse: 0,
222
+ };
223
+ state.bodyCollisionObservables.get(bodyB)?.notifyObservers(triggerEventB);
224
+ }
225
+ break;
226
+ }
227
+ }
228
+ }
229
+ }