Skip to content

Commit dcc5ad5

Browse files
Chau TranChau Tran
Chau Tran
authored and
Chau Tran
committed
feat(cannon): migrate constraint
1 parent fb7e349 commit dcc5ad5

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { Injector, Signal, computed, effect, inject, runInInjectionContext, untracked } from '@angular/core';
2+
import {
3+
ConstraintOptns,
4+
ConstraintTypes,
5+
HingeConstraintOpts,
6+
PointToPointConstraintOpts,
7+
} from '@pmndrs/cannon-worker-api';
8+
import { NgtAnyRecord, NgtInjectedRef, assertInjectionContext, injectNgtRef, is } from 'angular-three';
9+
import { NGTC_PHYSICS_API } from 'angular-three-cannon';
10+
import * as THREE from 'three';
11+
12+
export interface NgtcConstraintApi {
13+
disable: () => void;
14+
enable: () => void;
15+
remove: () => void;
16+
}
17+
18+
export interface NgtcHingeConstraintApi extends NgtcConstraintApi {
19+
disableMotor: () => void;
20+
enableMotor: () => void;
21+
setMotorMaxForce: (value: number) => void;
22+
setMotorSpeed: (value: number) => void;
23+
}
24+
25+
export type NgtcConstraintORHingeApi<T extends 'Hinge' | ConstraintTypes> = T extends ConstraintTypes
26+
? NgtcConstraintApi
27+
: NgtcHingeConstraintApi;
28+
29+
export interface NgtcConstraintReturn<
30+
T extends 'Hinge' | ConstraintTypes,
31+
TObjectA extends THREE.Object3D = THREE.Object3D,
32+
TObjectB extends THREE.Object3D = THREE.Object3D
33+
> {
34+
bodyA: NgtInjectedRef<TObjectA>;
35+
bodyB: NgtInjectedRef<TObjectB>;
36+
api: Signal<NgtcConstraintORHingeApi<T>>;
37+
}
38+
39+
export interface NgtcConstraintOptions<
40+
TConstraintType extends 'Hinge' | ConstraintTypes,
41+
TOptions extends HingeConstraintOpts | ConstraintOptns = TConstraintType extends 'Hinge'
42+
? HingeConstraintOpts
43+
: ConstraintOptns
44+
> {
45+
injector?: Injector;
46+
deps?: () => NgtAnyRecord;
47+
opts?: () => TOptions;
48+
}
49+
50+
export function usePointToPointConstraint<A extends THREE.Object3D, B extends THREE.Object3D>(
51+
bodyA: NgtInjectedRef<A> | A,
52+
bodyB: NgtInjectedRef<B> | B,
53+
opts?: NgtcConstraintOptions<'PointToPoint', PointToPointConstraintOpts>
54+
) {
55+
return injectConstraint('PointToPoint', bodyA, bodyB, opts);
56+
}
57+
export function useConeTwistConstraint<A extends THREE.Object3D, B extends THREE.Object3D>(
58+
bodyA: NgtInjectedRef<A> | A,
59+
bodyB: NgtInjectedRef<B> | B,
60+
opts?: NgtcConstraintOptions<'ConeTwist', PointToPointConstraintOpts>
61+
) {
62+
return injectConstraint('ConeTwist', bodyA, bodyB, opts);
63+
}
64+
export function useDistanceConstraint<A extends THREE.Object3D, B extends THREE.Object3D>(
65+
bodyA: NgtInjectedRef<A> | A,
66+
bodyB: NgtInjectedRef<B> | B,
67+
opts?: NgtcConstraintOptions<'Distance', PointToPointConstraintOpts>
68+
) {
69+
return injectConstraint('Distance', bodyA, bodyB, opts);
70+
}
71+
export function useHingeConstraint<A extends THREE.Object3D, B extends THREE.Object3D>(
72+
bodyA: NgtInjectedRef<A> | A,
73+
bodyB: NgtInjectedRef<B> | B,
74+
opts?: NgtcConstraintOptions<'Hinge', PointToPointConstraintOpts>
75+
) {
76+
return injectConstraint('Hinge', bodyA, bodyB, opts);
77+
}
78+
export function useLockConstraint<A extends THREE.Object3D, B extends THREE.Object3D>(
79+
bodyA: NgtInjectedRef<A> | A,
80+
bodyB: NgtInjectedRef<B> | B,
81+
opts?: NgtcConstraintOptions<'Lock', PointToPointConstraintOpts>
82+
) {
83+
return injectConstraint('Lock', bodyA, bodyB, opts);
84+
}
85+
86+
function injectConstraint<
87+
TConstraintType extends 'Hinge' | ConstraintTypes,
88+
A extends THREE.Object3D,
89+
B extends THREE.Object3D,
90+
TOptions extends HingeConstraintOpts | ConstraintOptns = TConstraintType extends 'Hinge'
91+
? HingeConstraintOpts
92+
: ConstraintOptns
93+
>(
94+
type: TConstraintType,
95+
bodyA: NgtInjectedRef<A> | A,
96+
bodyB: NgtInjectedRef<B> | B,
97+
{
98+
injector,
99+
deps = () => ({}),
100+
opts = () => ({} as TOptions),
101+
}: NgtcConstraintOptions<TConstraintType, TOptions> = {}
102+
): NgtcConstraintReturn<TConstraintType, A, B> {
103+
injector = assertInjectionContext(injectConstraint, injector);
104+
return runInInjectionContext(injector, () => {
105+
const physicsApi = inject(NGTC_PHYSICS_API);
106+
const { worker } = physicsApi();
107+
108+
const uuid = THREE.MathUtils.generateUUID();
109+
110+
const bodyARef = is.ref(bodyA) ? bodyA : injectNgtRef(bodyA);
111+
const bodyBRef = is.ref(bodyB) ? bodyB : injectNgtRef(bodyB);
112+
113+
effect((onCleanup) => {
114+
deps();
115+
if (bodyARef.untracked && bodyBRef.untracked) {
116+
worker.addConstraint({
117+
props: [bodyARef.untracked.uuid, bodyBRef.untracked.uuid, untracked(opts)],
118+
type,
119+
uuid,
120+
});
121+
onCleanup(() => worker.removeConstraint({ uuid }));
122+
}
123+
});
124+
125+
const api = computed(() => {
126+
deps();
127+
const enableDisable = {
128+
disable: () => worker.disableConstraint({ uuid }),
129+
enable: () => worker.enableConstraint({ uuid }),
130+
remove: () => worker.removeConstraint({ uuid }),
131+
};
132+
133+
if (type === 'Hinge') {
134+
return {
135+
...enableDisable,
136+
disableMotor: () => worker.disableConstraintMotor({ uuid }),
137+
enableMotor: () => worker.enableConstraintMotor({ uuid }),
138+
setMotorMaxForce: (value: number) => worker.setConstraintMotorMaxForce({ props: value, uuid }),
139+
setMotorSpeed: (value: number) => worker.setConstraintMotorSpeed({ props: value, uuid }),
140+
} as NgtcConstraintORHingeApi<TConstraintType>;
141+
}
142+
143+
return enableDisable as NgtcConstraintORHingeApi<TConstraintType>;
144+
});
145+
146+
return { bodyA: bodyARef, bodyB: bodyBRef, api };
147+
});
148+
}

libs/cannon/services/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './body';
2+
export * from './constraint';

0 commit comments

Comments
 (0)