5
5
EmbeddedViewRef ,
6
6
Signal ,
7
7
afterNextRender ,
8
- computed ,
8
+ effect ,
9
9
inject ,
10
10
input ,
11
11
signal ,
@@ -26,8 +26,7 @@ import {
26
26
WorkerFrameMessage ,
27
27
WorkerRayhitEvent ,
28
28
} from '@pmndrs/cannon-worker-api' ;
29
- import { injectBeforeRender , injectStore } from 'angular-three' ;
30
- import { injectAutoEffect } from 'ngxtension/auto-effect' ;
29
+ import { injectBeforeRender , injectStore , pick } from 'angular-three' ;
31
30
import { mergeInputs } from 'ngxtension/inject-inputs' ;
32
31
import { InstancedMesh , Matrix4 , Object3D , Quaternion , QuaternionTuple , Vector3 } from 'three' ;
33
32
@@ -81,7 +80,7 @@ export type NgtcCannonEvents = Record<string, Partial<NgtcCallbackByType<NgtcCan
81
80
82
81
export type ScaleOverrides = Record < string , Vector3 > ;
83
82
84
- export interface NgtcPhysicsInputs extends CannonWorkerProps {
83
+ export interface NgtcPhysicsOptions extends CannonWorkerProps {
85
84
isPaused ?: boolean ;
86
85
maxSubSteps ?: number ;
87
86
shouldInvalidate ?: boolean ;
@@ -97,7 +96,7 @@ export interface NgtcPhysicsApi {
97
96
worker : Signal < CannonWorkerAPI > ;
98
97
}
99
98
100
- const defaultOptions : NgtcPhysicsInputs = {
99
+ const defaultOptions : NgtcPhysicsOptions = {
101
100
allowSleep : false ,
102
101
axisIndex : 0 ,
103
102
broadphase : 'Naive' ,
@@ -116,6 +115,11 @@ const defaultOptions: NgtcPhysicsInputs = {
116
115
tolerance : 0.001 ,
117
116
} ;
118
117
118
+ type NgtsPhysicsUpdatableOptions = Extract <
119
+ keyof NgtcPhysicsOptions ,
120
+ 'gravity' | 'iterations' | 'tolerance' | 'broadphase' | 'axisIndex'
121
+ > ;
122
+
119
123
@Component ( {
120
124
selector : 'ngtc-physics' ,
121
125
standalone : true ,
@@ -125,11 +129,16 @@ const defaultOptions: NgtcPhysicsInputs = {
125
129
changeDetection : ChangeDetectionStrategy . OnPush ,
126
130
} )
127
131
export class NgtcPhysics {
128
- private autoEffect = injectAutoEffect ( ) ;
129
132
private store = injectStore ( ) ;
130
133
131
134
options = input ( defaultOptions , { transform : mergeInputs ( defaultOptions ) } ) ;
132
135
136
+ private axisIndex = pick ( this . options , 'axisIndex' ) ;
137
+ private broadphase = pick ( this . options , 'broadphase' ) ;
138
+ private gravity = pick ( this . options , 'gravity' ) ;
139
+ private iterations = pick ( this . options , 'iterations' ) ;
140
+ private tolerance = pick ( this . options , 'tolerance' ) ;
141
+
133
142
private invalidate = this . store . select ( 'invalidate' ) ;
134
143
// @ts -expect-error - worker is not nullable, and we don't want to use ! operator
135
144
private worker = signal < CannonWorkerAPI > ( null ) ;
@@ -148,12 +157,19 @@ export class NgtcPhysics {
148
157
constructor ( ) {
149
158
afterNextRender ( ( ) => {
150
159
this . worker . set ( new CannonWorkerAPI ( this . options ( ) ) ) ;
151
- this . connectWorker ( ) ;
152
- this . updateWorkerState ( 'axisIndex' ) ;
153
- this . updateWorkerState ( 'broadphase' ) ;
154
- this . updateWorkerState ( 'gravity' ) ;
155
- this . updateWorkerState ( 'iterations' ) ;
156
- this . updateWorkerState ( 'tolerance' ) ;
160
+ } ) ;
161
+
162
+ effect ( ( onCleanup ) => {
163
+ const cleanup = this . connectWorkerEffect ( ) ;
164
+ onCleanup ( ( ) => cleanup ?.( ) ) ;
165
+ } ) ;
166
+
167
+ effect ( ( ) => {
168
+ this . updateWorkerStateEffect ( 'axisIndex' , this . axisIndex ) ;
169
+ this . updateWorkerStateEffect ( 'broadphase' , this . broadphase ) ;
170
+ this . updateWorkerStateEffect ( 'gravity' , this . gravity ) ;
171
+ this . updateWorkerStateEffect ( 'iterations' , this . iterations ) ;
172
+ this . updateWorkerStateEffect ( 'tolerance' , this . tolerance ) ;
157
173
} ) ;
158
174
159
175
let timeSinceLastCalled = 0 ;
@@ -170,35 +186,32 @@ export class NgtcPhysics {
170
186
} ) ;
171
187
}
172
188
173
- private connectWorker ( ) {
174
- this . autoEffect ( ( ) => {
175
- const worker = this . worker ( ) as NgtcCannonWorker ;
176
- if ( ! worker ) return ;
189
+ private connectWorkerEffect ( ) {
190
+ const worker = this . worker ( ) as NgtcCannonWorker ;
191
+ if ( ! worker ) return ;
177
192
178
- worker . connect ( ) ;
179
- worker . init ( ) ;
193
+ worker . connect ( ) ;
194
+ worker . init ( ) ;
180
195
181
- worker . on ( 'collide' , this . collideHandler . bind ( this ) ) ;
182
- worker . on ( 'collideBegin' , this . collideBeginHandler . bind ( this ) ) ;
183
- worker . on ( 'collideEnd' , this . collideEndHandler . bind ( this ) ) ;
184
- worker . on ( 'frame' , this . frameHandler . bind ( this ) ) ;
185
- worker . on ( 'rayhit' , this . rayhitHandler . bind ( this ) ) ;
196
+ worker . on ( 'collide' , this . collideHandler . bind ( this ) ) ;
197
+ worker . on ( 'collideBegin' , this . collideBeginHandler . bind ( this ) ) ;
198
+ worker . on ( 'collideEnd' , this . collideEndHandler . bind ( this ) ) ;
199
+ worker . on ( 'frame' , this . frameHandler . bind ( this ) ) ;
200
+ worker . on ( 'rayhit' , this . rayhitHandler . bind ( this ) ) ;
186
201
187
- return ( ) => {
188
- worker . terminate ( ) ;
189
- worker . removeAllListeners ( ) ;
190
- } ;
191
- } ) ;
202
+ return ( ) => {
203
+ worker . terminate ( ) ;
204
+ worker . removeAllListeners ( ) ;
205
+ } ;
192
206
}
193
207
194
- private updateWorkerState ( key : keyof NgtcPhysicsInputs ) {
195
- const computedValue = computed ( ( ) => this . options ( ) [ key ] ) ;
196
-
197
- this . autoEffect ( ( ) => {
198
- const [ worker , value ] = [ untracked ( this . worker ) , computedValue ( ) ] ;
199
- // @ts -expect-error - we know key is a valid key of CannonWorkerAPI
200
- worker [ key ] = value ;
201
- } ) ;
208
+ private updateWorkerStateEffect < TUpdatableKey extends NgtsPhysicsUpdatableOptions > (
209
+ key : TUpdatableKey ,
210
+ option : ( ) => NgtcPhysicsOptions [ TUpdatableKey ] ,
211
+ ) {
212
+ const worker = this . worker ( ) ;
213
+ if ( ! worker ) return ;
214
+ Object . assign ( worker , { [ key ] : option ( ) } ) ;
202
215
}
203
216
204
217
private collideHandler ( { body, contact : { bi, bj, ...contactRest } , target, ...rest } : WorkerCollideEvent [ 'data' ] ) {
0 commit comments