@dice-o-rolla/dice-physics-rapier 0.1.0 → 0.2.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.
@@ -1,5 +1,5 @@
1
1
  import type { Vector3Like } from '@dice-o-rolla/dice-core';
2
- import type { CreatePhysicsDieOptions, PhysicsDieHandle, PhysicsWorld, TrayOptions } from '@dice-o-rolla/dice-physics';
2
+ import type { CreatePhysicsDieOptions, PhysicsCollisionEvent, PhysicsImpactEvent, PhysicsDieHandle, PhysicsWorld, TrayOptions } from '@dice-o-rolla/dice-physics';
3
3
  export interface RapierPhysicsWorldOptions {
4
4
  readonly gravity?: Vector3Like;
5
5
  }
@@ -10,6 +10,9 @@ export declare class RapierPhysicsWorld implements PhysicsWorld {
10
10
  createDie(options: CreatePhysicsDieOptions): PhysicsDieHandle;
11
11
  configureTray(options: TrayOptions): void;
12
12
  setGravity(gravity: Vector3Like): void;
13
+ setCollisionEventsEnabled(enabled: boolean): void;
14
+ drainCollisionEvents(): readonly PhysicsCollisionEvent[];
15
+ drainImpactEvents(): readonly PhysicsImpactEvent[];
13
16
  step(dtSeconds: number): void;
14
17
  removeDie(id: string): void;
15
18
  clear(): void;
@@ -6,13 +6,18 @@ const DEFAULT_GRAVITY = { x: 0, y: -9.81, z: 0 };
6
6
  export class RapierPhysicsWorld {
7
7
  #rapier;
8
8
  #world;
9
+ #eventQueue;
9
10
  #dice = new Map();
11
+ #colliderDice = new Map();
12
+ #dieColliders = new Map();
10
13
  #trayBody;
14
+ #collisionEventsEnabled = false;
11
15
  #destroyed = false;
12
16
  constructor(rapier, gravity) {
13
17
  assertVector(gravity, 'gravity');
14
18
  this.#rapier = rapier;
15
19
  this.#world = new rapier.World(gravity);
20
+ this.#eventQueue = new rapier.EventQueue(true);
16
21
  }
17
22
  static async create(options = {}) {
18
23
  const rapier = await initializeRapier();
@@ -37,9 +42,15 @@ export class RapierPhysicsWorld {
37
42
  .setCanSleep(true)
38
43
  .setCcdEnabled(true);
39
44
  const colliderDescriptor = createConvexHullCollider(this.#rapier, options.collider, options.scale, options.mass, options.material);
45
+ colliderDescriptor.setActiveEvents(this.#collisionEventsEnabled
46
+ ? this.#rapier.ActiveEvents.COLLISION_EVENTS |
47
+ this.#rapier.ActiveEvents.CONTACT_FORCE_EVENTS
48
+ : this.#rapier.ActiveEvents.NONE);
40
49
  const body = this.#world.createRigidBody(bodyDescriptor);
41
50
  try {
42
- this.#world.createCollider(colliderDescriptor, body);
51
+ const collider = this.#world.createCollider(colliderDescriptor, body);
52
+ this.#colliderDice.set(collider.handle, options.id);
53
+ this.#dieColliders.set(options.id, collider.handle);
43
54
  }
44
55
  catch (error) {
45
56
  this.#world.removeRigidBody(body);
@@ -82,17 +93,70 @@ export class RapierPhysicsWorld {
82
93
  assertVector(gravity, 'gravity');
83
94
  this.#world.gravity = { x: gravity.x, y: gravity.y, z: gravity.z };
84
95
  }
96
+ setCollisionEventsEnabled(enabled) {
97
+ this.#assertAlive();
98
+ this.#collisionEventsEnabled = enabled;
99
+ const activeEvents = enabled
100
+ ? this.#rapier.ActiveEvents.COLLISION_EVENTS | this.#rapier.ActiveEvents.CONTACT_FORCE_EVENTS
101
+ : this.#rapier.ActiveEvents.NONE;
102
+ for (const die of this.#dice.values()) {
103
+ for (let index = 0; index < die.body.numColliders(); index += 1) {
104
+ die.body.collider(index).setActiveEvents(activeEvents);
105
+ }
106
+ }
107
+ this.#eventQueue.clear();
108
+ }
109
+ drainCollisionEvents() {
110
+ this.#assertAlive();
111
+ const events = [];
112
+ this.#eventQueue.drainCollisionEvents((firstHandle, secondHandle, started) => {
113
+ const first = this.#colliderDice.get(firstHandle);
114
+ const second = this.#colliderDice.get(secondHandle);
115
+ const dieId = first ?? second;
116
+ if (dieId === undefined)
117
+ return;
118
+ const otherDieId = first === undefined || second === undefined ? undefined : second;
119
+ events.push(Object.freeze({
120
+ dieId,
121
+ ...(otherDieId === undefined ? {} : { otherDieId }),
122
+ started,
123
+ }));
124
+ });
125
+ return Object.freeze(events);
126
+ }
127
+ drainImpactEvents() {
128
+ this.#assertAlive();
129
+ const events = [];
130
+ this.#eventQueue.drainContactForceEvents((contact) => {
131
+ const first = this.#colliderDice.get(contact.collider1());
132
+ const second = this.#colliderDice.get(contact.collider2());
133
+ const dieId = first ?? second;
134
+ if (dieId === undefined)
135
+ return;
136
+ const otherDieId = first === undefined || second === undefined ? undefined : second;
137
+ events.push(Object.freeze({
138
+ dieId,
139
+ ...(otherDieId === undefined ? {} : { otherDieId }),
140
+ force: contact.totalForceMagnitude(),
141
+ }));
142
+ });
143
+ return Object.freeze(events);
144
+ }
85
145
  step(dtSeconds) {
86
146
  this.#assertAlive();
87
147
  assertPositive(dtSeconds, 'dtSeconds');
88
148
  this.#world.timestep = dtSeconds;
89
- this.#world.step();
149
+ this.#world.step(this.#collisionEventsEnabled ? this.#eventQueue : undefined);
90
150
  }
91
151
  removeDie(id) {
92
152
  this.#assertAlive();
93
153
  const die = this.#dice.get(id);
94
154
  if (die === undefined)
95
155
  return;
156
+ const colliderHandle = this.#dieColliders.get(id);
157
+ if (colliderHandle !== undefined)
158
+ this.#colliderDice.delete(colliderHandle);
159
+ this.#dieColliders.delete(id);
96
160
  this.#world.removeRigidBody(die.body);
97
161
  die.invalidate();
98
162
  this.#dice.delete(id);
@@ -104,12 +168,16 @@ export class RapierPhysicsWorld {
104
168
  die.invalidate();
105
169
  }
106
170
  this.#dice.clear();
171
+ this.#colliderDice.clear();
172
+ this.#dieColliders.clear();
173
+ this.#eventQueue.clear();
107
174
  }
108
175
  destroy() {
109
176
  if (this.#destroyed)
110
177
  return;
111
178
  this.clear();
112
179
  this.#removeTray();
180
+ this.#eventQueue.free();
113
181
  this.#world.free();
114
182
  this.#destroyed = true;
115
183
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dice-o-rolla/dice-physics-rapier",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Rapier 3D physics backend for physical dice simulation.",
5
5
  "keywords": [
6
6
  "dice",
@@ -8,7 +8,16 @@
8
8
  "rapier",
9
9
  "wasm"
10
10
  ],
11
+ "homepage": "https://github.com/creepiest-space/dice-o-rolla#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/creepiest-space/dice-o-rolla/issues"
14
+ },
11
15
  "license": "Apache-2.0",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/creepiest-space/dice-o-rolla.git",
19
+ "directory": "packages/dice-physics-rapier"
20
+ },
12
21
  "files": [
13
22
  "dist",
14
23
  "README.md",
@@ -31,8 +40,8 @@
31
40
  "registry": "https://registry.npmjs.org/"
32
41
  },
33
42
  "dependencies": {
34
- "@dice-o-rolla/dice-core": "0.1.0",
35
- "@dice-o-rolla/dice-physics": "0.1.0",
43
+ "@dice-o-rolla/dice-core": "0.2.0",
44
+ "@dice-o-rolla/dice-physics": "0.2.0",
36
45
  "@dimforge/rapier3d-compat": "^0.20.0"
37
46
  },
38
47
  "engines": {