Skip to content

Commit 23f00ca

Browse files
committed
feat(cannon): clean up cannon usages
1 parent 55a0037 commit 23f00ca

File tree

5 files changed

+61
-75
lines changed

5 files changed

+61
-75
lines changed

libs/cannon/body/src/lib/body.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,21 @@ function injectBody<TShape extends BodyShapeType, TObject extends Object3D>(
5656
const _body = body();
5757
if (!_body) return null;
5858

59-
const { worker, ...rest } = physics.api;
59+
const { worker, ...rest } = physics;
6060
const _worker = worker();
6161
if (!_worker) return null;
6262

6363
return makeBodyApi(_body, _worker, rest);
6464
});
6565

6666
effect((onCleanup) => {
67-
const currentWorker = physics.api.worker();
67+
const currentWorker = physics.worker();
6868
if (!currentWorker) return;
6969

7070
const object = body();
7171

7272
if (!isRefSignal && !object) {
73-
// TODO (signal): find a better way to handle this. no setting signal
73+
// TODO (signal): remove untracked in v19
7474
untracked(() => {
7575
bodyRef.set(resolveRef(ref));
7676
});
@@ -100,9 +100,9 @@ function injectBody<TShape extends BodyShapeType, TObject extends Object3D>(
100100
} else {
101101
prepare(object, props);
102102
}
103-
physics.api.refs[id] = object;
103+
physics.refs[id] = object;
104104
debug?.add(id, props, type);
105-
setupCollision(physics.api.events, props, id);
105+
setupCollision(physics.events, props, id);
106106
// @ts-expect-error - if args is undefined, there's default
107107
return { ...props, args: transform(props.args) };
108108
}),
@@ -125,9 +125,9 @@ function injectBody<TShape extends BodyShapeType, TObject extends Object3D>(
125125

126126
onCleanup(() => {
127127
uuid.forEach((id) => {
128-
delete physics.api.refs[id];
128+
delete physics.refs[id];
129129
debug?.remove(id);
130-
delete physics.api.events[id];
130+
delete physics.events[id];
131131
});
132132
currentWorker.removeBodies({ uuid });
133133
});

libs/cannon/body/src/lib/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
Triplet,
2121
VectorName,
2222
} from '@pmndrs/cannon-worker-api';
23-
import { NgtcCannonEvents, NgtcPhysicsApi } from 'angular-three-cannon';
23+
import { NgtcCannonEvents, NgtcPhysics } from 'angular-three-cannon';
2424
import { Euler, Object3D, Quaternion, Vector3 } from 'three';
2525
import { NgtcWorkerApi } from './types';
2626

@@ -84,7 +84,7 @@ export function setupCollision(
8484
export function makeBodyApi(
8585
body: Object3D,
8686
worker: CannonWorkerAPI,
87-
{ subscriptions, scaleOverrides }: Pick<NgtcPhysicsApi, 'subscriptions' | 'scaleOverrides'>,
87+
{ subscriptions, scaleOverrides }: Pick<NgtcPhysics, 'subscriptions' | 'scaleOverrides'>,
8888
) {
8989
const makeAtomic = <T extends AtomicName>(type: T, index?: number) => {
9090
const op: SetOpName<T> = `set${capitalize(type)}`;

libs/cannon/constraint/src/lib/constraint.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ function injectConstraint<
7272
throw new Error(`[NGT Cannon] injectConstraint was called outside of <ngtc-physics>`);
7373
}
7474

75-
const worker = physics.api.worker;
75+
const worker = physics.worker;
7676

7777
const uuid = makeId();
7878
const bodyARef = isSignal(bodyA) ? bodyA : signal(bodyA);
7979
const bodyBRef = isSignal(bodyB) ? bodyB : signal(bodyB);
8080
const bodyAValue = computed(() => resolveRef(bodyARef()));
8181
const bodyBValue = computed(() => resolveRef(bodyBRef()));
8282

83-
const api = computed(() => {
83+
const constraintApi = computed(() => {
8484
const _worker = worker();
8585
if (!_worker) return null;
8686

@@ -106,7 +106,7 @@ function injectConstraint<
106106
const currentWorker = worker();
107107
if (!currentWorker) return;
108108

109-
const [a, b] = [bodyAValue(), bodyBValue()];
109+
const [a, b, api] = [bodyAValue(), bodyBValue(), untracked(constraintApi)];
110110
if (!a || !b) return;
111111

112112
currentWorker.addConstraint({
@@ -117,13 +117,13 @@ function injectConstraint<
117117

118118
if (disableOnStart && !alreadyDisabled) {
119119
alreadyDisabled = true;
120-
untracked(api)?.disable();
120+
api?.disable();
121121
}
122122

123123
onCleanup(() => currentWorker.removeConstraint({ uuid }));
124124
});
125125

126-
return api;
126+
return constraintApi;
127127
});
128128
}
129129

libs/cannon/debug/src/lib/debug.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@ export class NgtcDebug {
4242

4343
private defaultScene = this.store.select('scene');
4444

45-
private scene = new Scene();
45+
private debuggerScene = new Scene();
4646
private bodies: Body[] = [];
4747
private bodyMap: Record<string, Body> = {};
4848

4949
private cannonDebugger!: ReturnType<typeof CannonDebugger>;
5050

5151
constructor() {
52+
// NOTE: afterNextRender so we only instantiate once after inputs have been resolved
5253
afterNextRender(() => {
53-
this.defaultScene().add(this.scene);
54-
this.cannonDebugger = this.debug().impl(this.scene, { bodies: this.bodies } as World, {
54+
this.defaultScene().add(this.debuggerScene);
55+
this.cannonDebugger = this.debug().impl(this.debuggerScene, { bodies: this.bodies } as World, {
5556
color: this.debug().color,
5657
scale: this.debug().scale,
5758
});
@@ -61,7 +62,7 @@ export class NgtcDebug {
6162
if (!this.cannonDebugger) return;
6263

6364
const enabled = this.debug().enabled;
64-
const refs = this.physics.api.refs;
65+
const refs = this.physics.refs;
6566
for (const uuid in this.bodyMap) {
6667
const ref = refs[uuid];
6768
const body = this.bodyMap[uuid];
@@ -72,7 +73,7 @@ export class NgtcDebug {
7273
}
7374
}
7475

75-
for (const child of this.scene.children) child.visible = enabled;
76+
for (const child of this.debuggerScene.children) child.visible = enabled;
7677
if (enabled) this.cannonDebugger.update();
7778
});
7879
}

libs/cannon/src/lib/physics.ts

Lines changed: 41 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
import {
2-
ChangeDetectionStrategy,
3-
Component,
4-
Signal,
5-
afterNextRender,
6-
effect,
7-
input,
8-
signal,
9-
untracked,
10-
} from '@angular/core';
1+
import { Directive, Injector, afterNextRender, effect, inject, input, signal, untracked } from '@angular/core';
112
import {
123
CannonWorkerAPI,
134
CannonWorkerProps,
@@ -84,15 +75,6 @@ export interface NgtcPhysicsOptions extends CannonWorkerProps {
8475
stepSize?: number;
8576
}
8677

87-
export interface NgtcPhysicsApi {
88-
bodies: { [uuid: string]: number };
89-
events: NgtcCannonEvents;
90-
refs: Refs;
91-
scaleOverrides: ScaleOverrides;
92-
subscriptions: Subscriptions;
93-
worker: Signal<CannonWorkerAPI>;
94-
}
95-
9678
const defaultOptions: NgtcPhysicsOptions = {
9779
allowSleep: false,
9880
axisIndex: 0,
@@ -117,14 +99,7 @@ type NgtsPhysicsUpdatableOptions = Extract<
11799
'gravity' | 'iterations' | 'tolerance' | 'broadphase' | 'axisIndex'
118100
>;
119101

120-
@Component({
121-
selector: 'ngtc-physics',
122-
standalone: true,
123-
template: `
124-
<ng-content />
125-
`,
126-
changeDetection: ChangeDetectionStrategy.OnPush,
127-
})
102+
@Directive({ selector: 'ngtc-physics', standalone: true })
128103
export class NgtcPhysics {
129104
private store = injectStore();
130105

@@ -138,38 +113,48 @@ export class NgtcPhysics {
138113

139114
private invalidate = this.store.select('invalidate');
140115
// @ts-expect-error - worker is not nullable, and we don't want to use ! operator.
141-
private worker = signal<CannonWorkerAPI>(null);
116+
private cannonWorker = signal<CannonWorkerAPI>(null);
142117

143-
api: NgtcPhysicsApi = {
144-
bodies: {},
145-
events: {},
146-
refs: {},
147-
scaleOverrides: {},
148-
subscriptions: {},
149-
worker: this.worker.asReadonly(),
150-
};
118+
bodies: { [uuid: string]: number } = {};
119+
events: NgtcCannonEvents = {};
120+
refs: Refs = {};
121+
scaleOverrides: ScaleOverrides = {};
122+
subscriptions: Subscriptions = {};
123+
worker = this.cannonWorker.asReadonly();
151124

152125
constructor() {
126+
const injector = inject(Injector);
127+
128+
// NOTE: set new cannonworker in afterNextRender
129+
// - so inputs are resolved
130+
// - so the worker is instantiated only once
131+
// - effects are started after worker is instantiated
153132
afterNextRender(() => {
154-
this.worker.set(new CannonWorkerAPI(this.options()));
155-
});
133+
this.cannonWorker.set(new CannonWorkerAPI(this.options()));
156134

157-
effect((onCleanup) => {
158-
const cleanup = this.connectWorkerEffect();
159-
onCleanup(() => cleanup?.());
160-
});
135+
effect(
136+
(onCleanup) => {
137+
const cleanup = this.connectWorkerEffect();
138+
onCleanup(() => cleanup?.());
139+
},
140+
{ injector },
141+
);
161142

162-
effect(() => {
163-
this.updateWorkerStateEffect('axisIndex', this.axisIndex);
164-
this.updateWorkerStateEffect('broadphase', this.broadphase);
165-
this.updateWorkerStateEffect('gravity', this.gravity);
166-
this.updateWorkerStateEffect('iterations', this.iterations);
167-
this.updateWorkerStateEffect('tolerance', this.tolerance);
143+
effect(
144+
() => {
145+
this.updateWorkerStateEffect('axisIndex', this.axisIndex);
146+
this.updateWorkerStateEffect('broadphase', this.broadphase);
147+
this.updateWorkerStateEffect('gravity', this.gravity);
148+
this.updateWorkerStateEffect('iterations', this.iterations);
149+
this.updateWorkerStateEffect('tolerance', this.tolerance);
150+
},
151+
{ injector },
152+
);
168153
});
169154

170155
let timeSinceLastCalled = 0;
171156
injectBeforeRender(({ delta }) => {
172-
const [{ isPaused, maxSubSteps, stepSize }, worker] = [this.options(), this.worker()];
157+
const [{ isPaused, maxSubSteps, stepSize }, worker] = [this.options(), this.cannonWorker()];
173158
if (isPaused || !worker || stepSize == null) return;
174159
timeSinceLastCalled += delta;
175160
worker.step({ maxSubSteps, stepSize, timeSinceLastCalled });
@@ -178,7 +163,7 @@ export class NgtcPhysics {
178163
}
179164

180165
private connectWorkerEffect() {
181-
const worker = this.worker() as NgtcCannonWorker;
166+
const worker = this.cannonWorker() as NgtcCannonWorker;
182167
if (!worker) return;
183168

184169
worker.connect();
@@ -200,29 +185,29 @@ export class NgtcPhysics {
200185
key: TUpdatableKey,
201186
option: () => NgtcPhysicsOptions[TUpdatableKey],
202187
) {
203-
const worker = this.worker();
188+
const worker = this.cannonWorker();
204189
if (!worker) return;
205190
Object.assign(worker, { [key]: option() });
206191
}
207192

208193
private collideHandler({ body, contact: { bi, bj, ...contactRest }, target, ...rest }: WorkerCollideEvent['data']) {
209-
const { events, refs } = this.api;
194+
const { events, refs } = this;
210195
const cb = events[target]?.collide;
211196
if (cb) {
212197
cb({ body: refs[body], contact: { bi: refs[bi], bj: refs[bj], ...contactRest }, target: refs[target], ...rest });
213198
}
214199
}
215200

216201
private collideBeginHandler({ bodyA, bodyB }: WorkerCollideBeginEvent['data']) {
217-
const { events, refs } = this.api;
202+
const { events, refs } = this;
218203
const cbA = events[bodyA]?.collideBegin;
219204
if (cbA) cbA({ body: refs[bodyB], op: 'event', target: refs[bodyA], type: 'collideBegin' });
220205
const cbB = events[bodyB]?.collideBegin;
221206
if (cbB) cbB({ body: refs[bodyA], op: 'event', target: refs[bodyB], type: 'collideBegin' });
222207
}
223208

224209
private collideEndHandler({ bodyA, bodyB }: WorkerCollideEndEvent['data']) {
225-
const { events, refs } = this.api;
210+
const { events, refs } = this;
226211
const cbA = events[bodyA]?.collideEnd;
227212
if (cbA) cbA({ body: refs[bodyB], op: 'event', target: refs[bodyA], type: 'collideEnd' });
228213
const cbB = events[bodyB]?.collideEnd;
@@ -238,7 +223,7 @@ export class NgtcPhysics {
238223
}: WorkerFrameMessage['data']) {
239224
const [{ shouldInvalidate }, { bodies, subscriptions, refs, scaleOverrides }, invalidate] = [
240225
untracked(this.options),
241-
this.api,
226+
this,
242227
this.invalidate(),
243228
];
244229
for (let i = 0; i < uuids.length; i++) {
@@ -270,7 +255,7 @@ export class NgtcPhysics {
270255
}
271256

272257
private rayhitHandler({ body, ray: { uuid, ...rayRest }, ...rest }: WorkerRayhitEvent['data']) {
273-
const { events, refs } = this.api;
258+
const { events, refs } = this;
274259
const cb = events[uuid]?.rayhit;
275260
if (cb) cb({ body: body ? refs[body] : null, ray: { uuid, ...rayRest }, ...rest });
276261
}

0 commit comments

Comments
 (0)