From 7e0d788c1f20673db978f546dcdfcfc1f73b076d Mon Sep 17 00:00:00 2001 From: Chau Tran Date: Mon, 9 May 2022 21:31:39 -0500 Subject: [PATCH] fix(cannon): strong type object type for physics APIs --- libs/cannon/src/lib/body.ts | 73 +++++++++++++++----------- libs/cannon/src/lib/constraint.ts | 60 ++++++++++++++------- libs/cannon/src/lib/raycast-vehicle.ts | 18 +++---- libs/cannon/src/lib/spring.ts | 15 ++++-- libs/cannon/src/lib/utils.ts | 6 +-- 5 files changed, 107 insertions(+), 65 deletions(-) diff --git a/libs/cannon/src/lib/body.ts b/libs/cannon/src/lib/body.ts index 32a6558db..86ac72cde 100644 --- a/libs/cannon/src/lib/body.ts +++ b/libs/cannon/src/lib/body.ts @@ -81,8 +81,8 @@ export interface NgtPhysicsBodyPublicApi extends WorkerApi { at: (index: number) => WorkerApi; } -export interface NgtPhysicBodyReturn { - ref: Ref; +export interface NgtPhysicBodyReturn { + ref: Ref; api: NgtPhysicsBodyPublicApi; } @@ -91,7 +91,10 @@ type ArgFn = (args: T) => unknown[]; const temp = new THREE.Object3D(); -function applyBodyProps(ref: Ref, props: TBodyProps) { +function applyBodyProps( + ref: Ref, + props: TBodyProps +) { const objectProps: UnknownRecord = {}; if (props.position) { objectProps['position'] = makeVector3(props.position); @@ -160,29 +163,33 @@ export class NgtPhysicBody extends NgtComponentStore { super(); } - usePlane(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Plane', fn, () => [], useOnTemplate, ref); + usePlane(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + return this.useBody('Plane', fn, () => [], useOnTemplate, ref); } - useBox(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + useBox(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { const defaultBoxArgs: NgtTriple = [1, 1, 1]; - return this.useBody('Box', fn, (args = defaultBoxArgs): NgtTriple => args, useOnTemplate, ref); + return this.useBody('Box', fn, (args = defaultBoxArgs): NgtTriple => args, useOnTemplate, ref); } - useCylinder(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Cylinder', fn, (args = [] as []) => args, useOnTemplate, ref); + useCylinder(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + return this.useBody('Cylinder', fn, (args = [] as []) => args, useOnTemplate, ref); } - useHeightfield(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Heightfield', fn, (args) => args, useOnTemplate, ref); + useHeightfield( + fn: GetByIndex, + useOnTemplate = true, + ref?: Ref + ) { + return this.useBody('Heightfield', fn, (args) => args, useOnTemplate, ref); } - useParticle(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Particle', fn, () => [], useOnTemplate, ref); + useParticle(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + return this.useBody('Particle', fn, () => [], useOnTemplate, ref); } - useSphere(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody( + useSphere(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + return this.useBody( 'Sphere', fn, (args: SphereArgs = [1]): SphereArgs => { @@ -194,12 +201,16 @@ export class NgtPhysicBody extends NgtComponentStore { ); } - useTrimesh(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Trimesh', fn, (args) => args, useOnTemplate, ref); + useTrimesh(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { + return this.useBody('Trimesh', fn, (args) => args, useOnTemplate, ref); } - useConvexPolyhedron(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody( + useConvexPolyhedron( + fn: GetByIndex, + useOnTemplate = true, + ref?: Ref + ) { + return this.useBody( 'ConvexPolyhedron', fn, ([vertices, faces, normals, axes, boundingSphereRadius] = []): ConvexPolyhedronArgs => [ @@ -214,26 +225,30 @@ export class NgtPhysicBody extends NgtComponentStore { ); } - useCompoundBody(fn: GetByIndex, useOnTemplate = true, ref?: Ref) { - return this.useBody('Compound', fn, (args) => args as unknown[], useOnTemplate, ref); + useCompoundBody( + fn: GetByIndex, + useOnTemplate = true, + ref?: Ref + ) { + return this.useBody('Compound', fn, (args) => args as unknown[], useOnTemplate, ref); } - private useBody( + private useBody( type: BodyShapeType, getPropsFn: GetByIndex, argsFn: ArgFn, useOnTemplate = true, - instanceRef?: Ref - ): NgtPhysicBodyReturn { + instanceRef?: Ref + ): NgtPhysicBodyReturn { return this.zone.runOutsideAngular(() => { - let ref = instanceRef as Ref; + let ref = instanceRef as Ref; if (!ref) { - ref = new Ref(); + ref = new Ref(); } if (!ref.value && !useOnTemplate) { - ref.set(prepareInstance(new THREE.Object3D(), () => this.store.get())); + ref.set(prepareInstance(new THREE.Object3D() as TObject, () => this.store.get())); } const physicsStore = this.physicsStore; @@ -306,9 +321,7 @@ export class NgtPhysicBody extends NgtComponentStore { worker.removeBodies({ uuid }); }; }) - )( - combineLatest([physicsStore.select((s) => s.worker), ref.pipe(filter((obj): obj is THREE.Object3D => !!obj))]) - ); + )(combineLatest([physicsStore.select((s) => s.worker), ref.pipe(filter((obj): obj is TObject => !!obj))])); }); return { diff --git a/libs/cannon/src/lib/constraint.ts b/libs/cannon/src/lib/constraint.ts index e38a23198..4c27b902e 100644 --- a/libs/cannon/src/lib/constraint.ts +++ b/libs/cannon/src/lib/constraint.ts @@ -33,9 +33,13 @@ type NgtConstraintORHingeApi = T extends Co ? ConstraintApi : HingeConstraintApi; -export interface NgtPhysicConstraintReturn { - bodyA: Ref; - bodyB: Ref; +export interface NgtPhysicConstraintReturn< + T extends 'Hinge' | ConstraintTypes, + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D +> { + bodyA: Ref; + bodyB: Ref; api: NgtConstraintORHingeApi; } @@ -48,38 +52,58 @@ export class NgtPhysicConstraint extends NgtComponentStore { super(); } - usePointToPointConstraint(bodyA: Ref, bodyB: Ref, optns: PointToPointConstraintOpts) { - return this.useConstraint('PointToPoint', bodyA, bodyB, optns); + usePointToPointConstraint< + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D + >(bodyA: Ref, bodyB: Ref, optns: PointToPointConstraintOpts) { + return this.useConstraint<'PointToPoint', TObjectA, TObjectB>('PointToPoint', bodyA, bodyB, optns); } - useConeTwistConstraint(bodyA: Ref, bodyB: Ref, optns: ConeTwistConstraintOpts) { - return this.useConstraint('ConeTwist', bodyA, bodyB, optns); + useConeTwistConstraint< + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D + >(bodyA: Ref, bodyB: Ref, optns: ConeTwistConstraintOpts) { + return this.useConstraint<'ConeTwist', TObjectA, TObjectB>('ConeTwist', bodyA, bodyB, optns); } - useDistanceConstraint(bodyA: Ref, bodyB: Ref, optns: DistanceConstraintOpts) { - return this.useConstraint('Distance', bodyA, bodyB, optns); + useDistanceConstraint< + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D + >(bodyA: Ref, bodyB: Ref, optns: DistanceConstraintOpts) { + return this.useConstraint<'Distance', TObjectA, TObjectB>('Distance', bodyA, bodyB, optns); } - useHingeConstraint(bodyA: Ref, bodyB: Ref, optns: HingeConstraintOpts) { - return this.useConstraint('Hinge', bodyA, bodyB, optns); + useHingeConstraint< + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D + >(bodyA: Ref, bodyB: Ref, optns: HingeConstraintOpts) { + return this.useConstraint<'Hinge', TObjectA, TObjectB>('Hinge', bodyA, bodyB, optns); } - useLockConstraint(bodyA: Ref, bodyB: Ref, optns: LockConstraintOpts) { - return this.useConstraint('Lock', bodyA, bodyB, optns); + useLockConstraint( + bodyA: Ref, + bodyB: Ref, + optns: LockConstraintOpts + ) { + return this.useConstraint<'Lock', TObjectA, TObjectB>('Lock', bodyA, bodyB, optns); } - private useConstraint( + private useConstraint< + TConstraintType extends 'Hinge' | ConstraintTypes, + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D + >( type: TConstraintType, - bodyA: Ref, - bodyB: Ref, + bodyA: Ref, + bodyB: Ref, opts: ConstraintOptns | HingeConstraintOpts = {} - ): NgtPhysicConstraintReturn { + ): NgtPhysicConstraintReturn { return this.zone.runOutsideAngular(() => { const physicsStore = this.physicsStore; const uuid = makeId(); this.onCanvasReady(this.store.ready$, () => { - this.effect<[CannonWorkerAPI, THREE.Object3D, THREE.Object3D]>( + this.effect<[CannonWorkerAPI, TObjectA, TObjectB]>( tapEffect(([worker, a, b]) => { worker.addConstraint({ props: [a.uuid, b.uuid, opts], diff --git a/libs/cannon/src/lib/raycast-vehicle.ts b/libs/cannon/src/lib/raycast-vehicle.ts index 728a0ae6d..903c3e21f 100644 --- a/libs/cannon/src/lib/raycast-vehicle.ts +++ b/libs/cannon/src/lib/raycast-vehicle.ts @@ -25,8 +25,8 @@ export interface NgtPhysicRaycastVehiclePublicApi { remove: () => void; } -export interface NgtPhysicRaycastVehicleReturn { - ref: Ref; +export interface NgtPhysicRaycastVehicleReturn { + ref: Ref; api: NgtPhysicRaycastVehiclePublicApi; } @@ -39,20 +39,20 @@ export class NgtPhysicRaycastVehicle extends NgtComponentStore { super(); } - useRaycastVehicle( + useRaycastVehicle( fn: () => NgtPhysicRaycastVehicleProps, useOnTemplate = true, - instanceRef?: Ref - ): NgtPhysicRaycastVehicleReturn { + instanceRef?: Ref + ): NgtPhysicRaycastVehicleReturn { return this.zone.runOutsideAngular(() => { - let ref = instanceRef as Ref; + let ref = instanceRef as Ref; if (!ref) { ref = new Ref(); } if (!ref.value && !useOnTemplate) { - ref.set(prepare(new THREE.Object3D(), () => this.store.get())); + ref.set(prepare(new THREE.Object3D() as TObject, () => this.store.get())); } const physicsStore = this.physicsStore; @@ -80,9 +80,7 @@ export class NgtPhysicRaycastVehicle extends NgtComponentStore { worker.removeRaycastVehicle({ uuid }); }; }) - )( - combineLatest([physicsStore.select((s) => s.worker), ref.pipe(filter((obj): obj is THREE.Object3D => !!obj))]) - ); + )(combineLatest([physicsStore.select((s) => s.worker), ref.pipe(filter((obj): obj is TObject => !!obj))])); }); return { diff --git a/libs/cannon/src/lib/spring.ts b/libs/cannon/src/lib/spring.ts index 495f43bb5..4a1eede36 100644 --- a/libs/cannon/src/lib/spring.ts +++ b/libs/cannon/src/lib/spring.ts @@ -12,9 +12,12 @@ export interface NgtPhysicSpringApi { remove: () => void; } -export interface NgtPhysicSpringReturn { - bodyA: Ref; - bodyB: Ref; +export interface NgtPhysicSpringReturn< + TObjectA extends THREE.Object3D = THREE.Object3D, + TObjectB extends THREE.Object3D = THREE.Object3D +> { + bodyA: Ref; + bodyB: Ref; api: NgtPhysicSpringApi; } @@ -28,7 +31,11 @@ export class NgtPhysicSpring extends NgtComponentStore { super(); } - useSpring(bodyA: Ref, bodyB: Ref, optns: SpringOptns): NgtPhysicSpringReturn { + useSpring( + bodyA: Ref, + bodyB: Ref, + optns: SpringOptns + ): NgtPhysicSpringReturn { return this.zone.runOutsideAngular(() => { const physicsStore = this.physicsStore; const uuid = makeId(); diff --git a/libs/cannon/src/lib/utils.ts b/libs/cannon/src/lib/utils.ts index 1ffcacc03..5b6e0a1bd 100644 --- a/libs/cannon/src/lib/utils.ts +++ b/libs/cannon/src/lib/utils.ts @@ -11,14 +11,14 @@ import * as THREE from 'three'; export class NgtCannonUtils { static incrementingId = 0; - static getUUID(ref: Ref, index?: number): string | null { + static getUUID(ref: Ref, index?: number): string | null { const suffix = index === undefined ? '' : `/${index}`; if (typeof ref === 'function') return null; return ref && ref.value && `${ref.value.uuid}${suffix}`; } - static subscribe( - ref: Ref, + static subscribe( + ref: Ref, worker: CannonWorkerAPI, subscriptions: Subscriptions, type: T,