angular-three-rapier 4.0.0-next.119 → 4.0.0-next.120
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.
package/README.md
CHANGED
|
@@ -19,17 +19,22 @@ npm install angular-three-rapier @dimforge/rapier3d-compat
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
|
-
import { Component, CUSTOM_ELEMENTS_SCHEMA
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
22
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
23
|
+
import { extend, NgtArgs } from 'angular-three';
|
|
24
|
+
import { NgtrPhysics, NgtrRigidBody } from 'angular-three-rapier';
|
|
25
|
+
import * as THREE from 'three';
|
|
26
|
+
|
|
27
|
+
extend(THREE);
|
|
25
28
|
|
|
26
29
|
@Component({
|
|
27
30
|
selector: 'app-box',
|
|
28
31
|
template: `
|
|
29
|
-
<ngt-
|
|
30
|
-
<ngt-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
<ngt-object3D rigidBody [position]="[0, 5, 0]">
|
|
33
|
+
<ngt-mesh>
|
|
34
|
+
<ngt-box-geometry />
|
|
35
|
+
<ngt-mesh-standard-material color="hotpink" />
|
|
36
|
+
</ngt-mesh>
|
|
37
|
+
</ngt-object3D>
|
|
33
38
|
`,
|
|
34
39
|
imports: [NgtrRigidBody],
|
|
35
40
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
@@ -39,12 +44,14 @@ export class Box {}
|
|
|
39
44
|
@Component({
|
|
40
45
|
selector: 'app-ground',
|
|
41
46
|
template: `
|
|
42
|
-
<ngt-
|
|
43
|
-
<ngt-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
<ngt-object3D rigidBody="fixed" [position]="[0, -1, 0]">
|
|
48
|
+
<ngt-mesh>
|
|
49
|
+
<ngt-box-geometry *args="[20, 1, 20]" />
|
|
50
|
+
<ngt-mesh-standard-material color="gray" />
|
|
51
|
+
</ngt-mesh>
|
|
52
|
+
</ngt-object3D>
|
|
46
53
|
`,
|
|
47
|
-
imports: [NgtrRigidBody],
|
|
54
|
+
imports: [NgtrRigidBody, NgtArgs],
|
|
48
55
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
49
56
|
})
|
|
50
57
|
export class Ground {}
|
|
@@ -52,8 +59,10 @@ export class Ground {}
|
|
|
52
59
|
@Component({
|
|
53
60
|
template: `
|
|
54
61
|
<ngtr-physics [options]="{ gravity: [0, -9.81, 0] }">
|
|
55
|
-
<
|
|
56
|
-
|
|
62
|
+
<ng-template>
|
|
63
|
+
<app-box />
|
|
64
|
+
<app-ground />
|
|
65
|
+
</ng-template>
|
|
57
66
|
</ngtr-physics>
|
|
58
67
|
`,
|
|
59
68
|
imports: [NgtrPhysics, Box, Ground],
|
|
@@ -73,46 +82,298 @@ export class SceneGraph {}
|
|
|
73
82
|
| `interpolate` | Enable transform interpolation | `true` |
|
|
74
83
|
| `updateLoop` | Update loop type: `'follow'` or `'independent'` | `'follow'` |
|
|
75
84
|
|
|
76
|
-
## Rigid Body
|
|
85
|
+
## Rigid Body
|
|
86
|
+
|
|
87
|
+
Use `ngt-object3D` with the `rigidBody` attribute. The rigid body type is specified as the attribute value:
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<!-- Dynamic (default when empty) -->
|
|
91
|
+
<ngt-object3D rigidBody [position]="[0, 5, 0]">
|
|
92
|
+
<ngt-mesh>...</ngt-mesh>
|
|
93
|
+
</ngt-object3D>
|
|
94
|
+
|
|
95
|
+
<!-- Fixed (static) -->
|
|
96
|
+
<ngt-object3D rigidBody="fixed" [position]="[0, -1, 0]">
|
|
97
|
+
<ngt-mesh>...</ngt-mesh>
|
|
98
|
+
</ngt-object3D>
|
|
99
|
+
|
|
100
|
+
<!-- Kinematic -->
|
|
101
|
+
<ngt-object3D rigidBody="kinematicPosition">
|
|
102
|
+
<ngt-mesh>...</ngt-mesh>
|
|
103
|
+
</ngt-object3D>
|
|
104
|
+
```
|
|
77
105
|
|
|
78
|
-
|
|
106
|
+
### Rigid Body Types
|
|
107
|
+
|
|
108
|
+
- `''` or `'dynamic'` - Affected by forces and collisions
|
|
79
109
|
- `'fixed'` - Static, immovable body
|
|
80
110
|
- `'kinematicPosition'` - Controlled by position, affects dynamic bodies
|
|
81
111
|
- `'kinematicVelocity'` - Controlled by velocity, affects dynamic bodies
|
|
82
112
|
|
|
83
|
-
|
|
113
|
+
### Rigid Body Options
|
|
114
|
+
|
|
115
|
+
```html
|
|
116
|
+
<ngt-object3D
|
|
117
|
+
rigidBody
|
|
118
|
+
[options]="{
|
|
119
|
+
colliders: 'ball',
|
|
120
|
+
ccd: true,
|
|
121
|
+
gravityScale: 0.5,
|
|
122
|
+
linearVelocity: [0, 10, 0],
|
|
123
|
+
angularVelocity: [0, 1, 0]
|
|
124
|
+
}"
|
|
125
|
+
>
|
|
126
|
+
...
|
|
127
|
+
</ngt-object3D>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Rigid Body Events
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<ngt-object3D
|
|
134
|
+
rigidBody
|
|
135
|
+
(collisionEnter)="onCollisionEnter($event)"
|
|
136
|
+
(collisionExit)="onCollisionExit($event)"
|
|
137
|
+
(intersectionEnter)="onIntersectionEnter($event)"
|
|
138
|
+
(intersectionExit)="onIntersectionExit($event)"
|
|
139
|
+
(contactForce)="onContactForce($event)"
|
|
140
|
+
(sleep)="onSleep()"
|
|
141
|
+
(wake)="onWake()"
|
|
142
|
+
>
|
|
143
|
+
...
|
|
144
|
+
</ngt-object3D>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Colliders
|
|
84
148
|
|
|
85
|
-
|
|
149
|
+
Colliders use `ngt-object3D` with specific collider attributes. By default, rigid bodies auto-generate colliders from child meshes.
|
|
86
150
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
151
|
+
### Explicit Colliders
|
|
152
|
+
|
|
153
|
+
```html
|
|
154
|
+
<!-- Ball collider -->
|
|
155
|
+
<ngt-object3D [ballCollider]="[0.5]" [position]="[0, 2, 0]" />
|
|
156
|
+
|
|
157
|
+
<!-- Cuboid collider (half-extents) -->
|
|
158
|
+
<ngt-object3D [cuboidCollider]="[1, 0.5, 2]" [position]="[0, 0, 0]" />
|
|
159
|
+
|
|
160
|
+
<!-- Capsule collider (half-height, radius) -->
|
|
161
|
+
<ngt-object3D [capsuleCollider]="[0.5, 0.25]" [position]="[0, 1, 0]" />
|
|
162
|
+
|
|
163
|
+
<!-- Cylinder collider (half-height, radius) -->
|
|
164
|
+
<ngt-object3D [cylinderCollider]="[1, 0.5]" />
|
|
165
|
+
|
|
166
|
+
<!-- Cone collider (half-height, radius) -->
|
|
167
|
+
<ngt-object3D [coneCollider]="[1, 0.5]" />
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Available Collider Directives
|
|
171
|
+
|
|
172
|
+
| Directive | Args | Description |
|
|
173
|
+
| --------------------------- | --------------------------------- | ------------------- |
|
|
174
|
+
| `NgtrBallCollider` | `[radius]` | Sphere shape |
|
|
175
|
+
| `NgtrCuboidCollider` | `[halfW, halfH, halfD]` | Box shape |
|
|
176
|
+
| `NgtrCapsuleCollider` | `[halfHeight, radius]` | Capsule shape |
|
|
177
|
+
| `NgtrCylinderCollider` | `[halfHeight, radius]` | Cylinder shape |
|
|
178
|
+
| `NgtrConeCollider` | `[halfHeight, radius]` | Cone shape |
|
|
179
|
+
| `NgtrConvexHullCollider` | `[vertices]` | Convex hull |
|
|
180
|
+
| `NgtrTrimeshCollider` | `[vertices, indices]` | Triangle mesh |
|
|
181
|
+
| `NgtrHeightfieldCollider` | `[width, height, heights, scale]` | Terrain heightfield |
|
|
182
|
+
| `NgtrRoundCuboidCollider` | `[halfW, halfH, halfD, radius]` | Rounded box |
|
|
183
|
+
| `NgtrRoundCylinderCollider` | `[halfH, radius, borderRadius]` | Rounded cylinder |
|
|
184
|
+
| `NgtrRoundConeCollider` | `[halfH, radius, borderRadius]` | Rounded cone |
|
|
185
|
+
|
|
186
|
+
### Disabling Auto-Colliders
|
|
187
|
+
|
|
188
|
+
```html
|
|
189
|
+
<ngt-object3D rigidBody [options]="{ colliders: false }">
|
|
190
|
+
<!-- Manual colliders only -->
|
|
191
|
+
<ngt-object3D [ballCollider]="[0.5]" />
|
|
192
|
+
</ngt-object3D>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Mesh Collider
|
|
196
|
+
|
|
197
|
+
Generate colliders from mesh geometry:
|
|
198
|
+
|
|
199
|
+
```html
|
|
200
|
+
<ngt-object3D rigidBody [options]="{ colliders: false }">
|
|
201
|
+
<ngt-object3D [meshCollider]="'trimesh'">
|
|
202
|
+
<ngt-mesh>
|
|
203
|
+
<ngt-torus-geometry />
|
|
204
|
+
<ngt-mesh-standard-material />
|
|
205
|
+
</ngt-mesh>
|
|
206
|
+
</ngt-object3D>
|
|
207
|
+
</ngt-object3D>
|
|
208
|
+
```
|
|
95
209
|
|
|
96
210
|
## Joints
|
|
97
211
|
|
|
98
|
-
Create joints between rigid bodies:
|
|
212
|
+
Create joints between rigid bodies using injectable functions:
|
|
99
213
|
|
|
100
214
|
```typescript
|
|
101
|
-
import {
|
|
215
|
+
import { Component, viewChild } from '@angular/core';
|
|
216
|
+
import {
|
|
217
|
+
NgtrRigidBody,
|
|
218
|
+
sphericalJoint,
|
|
219
|
+
revoluteJoint,
|
|
220
|
+
prismaticJoint,
|
|
221
|
+
fixedJoint,
|
|
222
|
+
ropeJoint,
|
|
223
|
+
springJoint,
|
|
224
|
+
} from 'angular-three-rapier';
|
|
102
225
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
226
|
+
@Component({
|
|
227
|
+
template: `
|
|
228
|
+
<ngt-object3D rigidBody="fixed" #bodyA="rigidBody">...</ngt-object3D>
|
|
229
|
+
<ngt-object3D rigidBody #bodyB="rigidBody">...</ngt-object3D>
|
|
230
|
+
`,
|
|
231
|
+
})
|
|
232
|
+
export class JointExample {
|
|
233
|
+
bodyA = viewChild.required<NgtrRigidBody>('bodyA');
|
|
234
|
+
bodyB = viewChild.required<NgtrRigidBody>('bodyB');
|
|
235
|
+
|
|
236
|
+
// Spherical joint (ball-and-socket)
|
|
237
|
+
joint = sphericalJoint(
|
|
238
|
+
() => this.bodyA().rigidBody(),
|
|
239
|
+
() => this.bodyB().rigidBody(),
|
|
240
|
+
{
|
|
241
|
+
data: {
|
|
242
|
+
body1Anchor: [0, -0.5, 0],
|
|
243
|
+
body2Anchor: [0, 0.5, 0],
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Revolute joint (hinge) with limits
|
|
249
|
+
hingeJoint = revoluteJoint(
|
|
250
|
+
() => this.bodyA().rigidBody(),
|
|
251
|
+
() => this.bodyB().rigidBody(),
|
|
252
|
+
{
|
|
253
|
+
data: {
|
|
254
|
+
body1Anchor: [0, 0, 0],
|
|
255
|
+
body2Anchor: [0, 1, 0],
|
|
256
|
+
axis: [0, 1, 0],
|
|
257
|
+
limits: [-Math.PI / 2, Math.PI / 2],
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// Prismatic joint (slider)
|
|
263
|
+
sliderJoint = prismaticJoint(
|
|
264
|
+
() => this.bodyA().rigidBody(),
|
|
265
|
+
() => this.bodyB().rigidBody(),
|
|
266
|
+
{
|
|
267
|
+
data: {
|
|
268
|
+
body1Anchor: [0, 0, 0],
|
|
269
|
+
body2Anchor: [2, 0, 0],
|
|
270
|
+
axis: [1, 0, 0],
|
|
271
|
+
limits: [-1, 1],
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Rope joint (max distance constraint)
|
|
277
|
+
rope = ropeJoint(
|
|
278
|
+
() => this.bodyA().rigidBody(),
|
|
279
|
+
() => this.bodyB().rigidBody(),
|
|
280
|
+
{
|
|
281
|
+
data: {
|
|
282
|
+
body1Anchor: [0, 0, 0],
|
|
283
|
+
body2Anchor: [0, 0, 0],
|
|
284
|
+
length: 5,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// Spring joint
|
|
290
|
+
spring = springJoint(
|
|
291
|
+
() => this.bodyA().rigidBody(),
|
|
292
|
+
() => this.bodyB().rigidBody(),
|
|
293
|
+
{
|
|
294
|
+
data: {
|
|
295
|
+
body1Anchor: [0, 0, 0],
|
|
296
|
+
body2Anchor: [0, 0, 0],
|
|
297
|
+
restLength: 2,
|
|
298
|
+
stiffness: 100,
|
|
299
|
+
damping: 10,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Instanced Rigid Bodies
|
|
307
|
+
|
|
308
|
+
For efficient physics with many identical objects:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { NgtArgs } from 'angular-three';
|
|
312
|
+
import { NgtrInstancedRigidBodies } from 'angular-three-rapier';
|
|
313
|
+
|
|
314
|
+
@Component({
|
|
315
|
+
template: `
|
|
316
|
+
<ngt-object3D [instancedRigidBodies]="instances">
|
|
317
|
+
<ngt-instanced-mesh [count]="instances.length" castShadow>
|
|
318
|
+
<ngt-sphere-geometry *args="[0.5]" />
|
|
319
|
+
<ngt-mesh-standard-material color="orange" />
|
|
320
|
+
</ngt-instanced-mesh>
|
|
321
|
+
</ngt-object3D>
|
|
322
|
+
`,
|
|
323
|
+
imports: [NgtrInstancedRigidBodies, NgtArgs],
|
|
324
|
+
})
|
|
325
|
+
export class Spheres {
|
|
326
|
+
instances = Array.from({ length: 100 }, (_, i) => ({
|
|
327
|
+
key: i,
|
|
328
|
+
position: [Math.random() * 10, Math.random() * 10, 0] as [number, number, number],
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Interaction Groups
|
|
334
|
+
|
|
335
|
+
Filter collisions between objects:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
import { interactionGroups } from 'angular-three-rapier';
|
|
339
|
+
|
|
340
|
+
// Member of group 0, collides with groups 0 and 1
|
|
341
|
+
const groups = interactionGroups([0], [0, 1]);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```html
|
|
345
|
+
<!-- Using directive -->
|
|
346
|
+
<ngt-object3D rigidBody [interactionGroups]="[[0], [0, 1]]">...</ngt-object3D>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Physics Hooks
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { beforePhysicsStep, afterPhysicsStep } from 'angular-three-rapier';
|
|
353
|
+
|
|
354
|
+
@Component({...})
|
|
355
|
+
export class MyComponent {
|
|
356
|
+
constructor() {
|
|
357
|
+
beforePhysicsStep((world) => {
|
|
358
|
+
// Run before each physics step
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
afterPhysicsStep((world) => {
|
|
362
|
+
// Run after each physics step
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
108
366
|
```
|
|
109
367
|
|
|
110
368
|
## Debug Visualization
|
|
111
369
|
|
|
370
|
+
Enable debug rendering via physics options:
|
|
371
|
+
|
|
112
372
|
```html
|
|
113
|
-
<ngtr-physics>
|
|
114
|
-
<
|
|
115
|
-
|
|
373
|
+
<ngtr-physics [options]="{ debug: true }">
|
|
374
|
+
<ng-template>
|
|
375
|
+
<!-- your physics objects -->
|
|
376
|
+
</ng-template>
|
|
116
377
|
</ngtr-physics>
|
|
117
378
|
```
|
|
118
379
|
|
|
@@ -127,7 +388,22 @@ import { NgtrAttractor } from 'angular-three-rapier/addons';
|
|
|
127
388
|
```
|
|
128
389
|
|
|
129
390
|
```html
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
391
|
+
<!-- Attractor with default options -->
|
|
392
|
+
<ngt-object3D attractor />
|
|
393
|
+
|
|
394
|
+
<!-- Attractor with custom options -->
|
|
395
|
+
<ngt-object3D [attractor]="{ strength: 10, range: 20, type: 'linear' }" />
|
|
396
|
+
|
|
397
|
+
<!-- Repeller (negative strength) -->
|
|
398
|
+
<ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
|
|
399
|
+
|
|
400
|
+
<!-- Newtonian gravity -->
|
|
401
|
+
<ngt-object3D
|
|
402
|
+
[attractor]="{
|
|
403
|
+
strength: 1000,
|
|
404
|
+
range: 50,
|
|
405
|
+
type: 'newtonian',
|
|
406
|
+
gravitationalConstant: 0.01
|
|
407
|
+
}"
|
|
408
|
+
/>
|
|
133
409
|
```
|
package/addons/README.md
CHANGED
|
@@ -17,11 +17,14 @@ A directive that creates a gravitational attractor point in the physics world. A
|
|
|
17
17
|
### Basic Usage
|
|
18
18
|
|
|
19
19
|
```html
|
|
20
|
-
<!-- Simple attractor at origin -->
|
|
21
|
-
<ngt-object3D attractor
|
|
20
|
+
<!-- Simple attractor at origin with default options -->
|
|
21
|
+
<ngt-object3D attractor />
|
|
22
|
+
|
|
23
|
+
<!-- Attractor with custom options -->
|
|
24
|
+
<ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
|
|
22
25
|
|
|
23
26
|
<!-- Repeller (negative strength) -->
|
|
24
|
-
<ngt-object3D attractor
|
|
27
|
+
<ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
### Gravity Types
|
|
@@ -30,20 +33,19 @@ The attractor supports three different gravity calculation models:
|
|
|
30
33
|
|
|
31
34
|
```html
|
|
32
35
|
<!-- Static: Constant force regardless of distance -->
|
|
33
|
-
<ngt-object3D attractor
|
|
36
|
+
<ngt-object3D [attractor]="{ type: 'static', strength: 5, range: 20 }" />
|
|
34
37
|
|
|
35
38
|
<!-- Linear: Force increases as objects get closer -->
|
|
36
|
-
<ngt-object3D attractor
|
|
39
|
+
<ngt-object3D [attractor]="{ type: 'linear', strength: 5, range: 20 }" />
|
|
37
40
|
|
|
38
41
|
<!-- Newtonian: Realistic inverse-square law (like real gravity) -->
|
|
39
42
|
<ngt-object3D
|
|
40
|
-
attractor
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}"
|
|
43
|
+
[attractor]="{
|
|
44
|
+
type: 'newtonian',
|
|
45
|
+
strength: 1000,
|
|
46
|
+
range: 50,
|
|
47
|
+
gravitationalConstant: 0.01
|
|
48
|
+
}"
|
|
47
49
|
/>
|
|
48
50
|
```
|
|
49
51
|
|
|
@@ -48,13 +48,11 @@ function attractorDebug(object, options, injector) {
|
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
beforeRender(() => {
|
|
51
|
-
if (!physics['debug']())
|
|
51
|
+
if (!physics['debug']() || !mesh || !normalsHelper)
|
|
52
52
|
return;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
normalsHelper?.update();
|
|
57
|
-
}
|
|
53
|
+
const worldPosition = object.getWorldPosition(_v3);
|
|
54
|
+
mesh.position.copy(worldPosition);
|
|
55
|
+
normalsHelper.update();
|
|
58
56
|
});
|
|
59
57
|
});
|
|
60
58
|
}
|
|
@@ -141,14 +139,17 @@ const defaultOptions = {
|
|
|
141
139
|
*
|
|
142
140
|
* @example
|
|
143
141
|
* ```html
|
|
144
|
-
* <!-- Simple attractor at origin -->
|
|
145
|
-
* <ngt-object3D attractor
|
|
142
|
+
* <!-- Simple attractor at origin with default options -->
|
|
143
|
+
* <ngt-object3D attractor />
|
|
144
|
+
*
|
|
145
|
+
* <!-- Attractor with custom options -->
|
|
146
|
+
* <ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
|
|
146
147
|
*
|
|
147
148
|
* <!-- Repeller (negative strength) -->
|
|
148
|
-
* <ngt-object3D attractor
|
|
149
|
+
* <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
|
|
149
150
|
*
|
|
150
151
|
* <!-- Newtonian gravity -->
|
|
151
|
-
* <ngt-object3D attractor
|
|
152
|
+
* <ngt-object3D [attractor]="{
|
|
152
153
|
* strength: 1000,
|
|
153
154
|
* range: 50,
|
|
154
155
|
* type: 'newtonian',
|
|
@@ -158,7 +159,7 @@ const defaultOptions = {
|
|
|
158
159
|
*/
|
|
159
160
|
class NgtrAttractor {
|
|
160
161
|
position = input([0, 0, 0], ...(ngDevMode ? [{ debugName: "position" }] : []));
|
|
161
|
-
options = input(defaultOptions, { ...(ngDevMode ? { debugName: "options" } : {}), transform: mergeInputs(defaultOptions) });
|
|
162
|
+
options = input(defaultOptions, { ...(ngDevMode ? { debugName: "options" } : {}), alias: 'attractor', transform: mergeInputs(defaultOptions) });
|
|
162
163
|
objectRef = inject(ElementRef);
|
|
163
164
|
collisionGroups = pick(this.options, 'collisionGroups');
|
|
164
165
|
linkedCollisionGroups = linkedSignal(this.collisionGroups, ...(ngDevMode ? [{ debugName: "linkedCollisionGroups" }] : []));
|
|
@@ -185,7 +186,7 @@ class NgtrAttractor {
|
|
|
185
186
|
attractorDebug(this.objectRef.nativeElement, this.options);
|
|
186
187
|
}
|
|
187
188
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NgtrAttractor, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
188
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: NgtrAttractor, isStandalone: true, selector: "ngt-object3D[attractor]", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "
|
|
189
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: NgtrAttractor, isStandalone: true, selector: "ngt-object3D[attractor]", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "attractor", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
189
190
|
{
|
|
190
191
|
provide: COLLISION_GROUPS_HANDLER,
|
|
191
192
|
useFactory: (attractor) => {
|
|
@@ -213,7 +214,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
213
214
|
},
|
|
214
215
|
],
|
|
215
216
|
}]
|
|
216
|
-
}], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "
|
|
217
|
+
}], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "attractor", required: false }] }] } });
|
|
217
218
|
|
|
218
219
|
/**
|
|
219
220
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-three-rapier-addons.mjs","sources":["../../../../libs/rapier/addons/src/lib/attractor-debug.ts","../../../../libs/rapier/addons/src/lib/attractor.ts","../../../../libs/rapier/addons/src/angular-three-rapier-addons.ts"],"sourcesContent":["import { computed, effect, inject, Injector } from '@angular/core';\nimport { beforeRender, injectStore, pick } from 'angular-three';\nimport { NgtrPhysics } from 'angular-three-rapier';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport * as THREE from 'three';\nimport { VertexNormalsHelper } from 'three-stdlib';\nimport { NgtrAttactorOptions } from './attractor';\n\nconst _v3 = new THREE.Vector3();\n\n/**\n * Creates debug visualization for an attractor.\n * Shows a sphere at the attractor position with normals indicating the range.\n * Blue indicates attraction, red indicates repulsion.\n *\n * This is automatically called by NgtrAttractor when physics debug mode is enabled.\n *\n * @param object - The Object3D representing the attractor position\n * @param options - Getter function for attractor options\n * @param injector - Optional injector for dependency injection context\n *\n * @internal\n */\nexport function attractorDebug(object: THREE.Object3D, options: () => NgtrAttactorOptions, injector?: Injector) {\n\treturn assertInjector(attractorDebug, injector, () => {\n\t\tconst physics = inject(NgtrPhysics);\n\t\tconst store = injectStore();\n\n\t\tconst strength = pick(options, 'strength');\n\t\tconst range = pick(options, 'range');\n\t\tconst color = computed(() => (strength() > 0 ? 0x0000ff : 0xff0000));\n\n\t\tlet mesh: THREE.Mesh;\n\t\tlet normalsHelper: VertexNormalsHelper;\n\n\t\teffect((onCleanup) => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tmesh = new THREE.Mesh(\n\t\t\t\tnew THREE.SphereGeometry(0.2, 6, 6),\n\t\t\t\tnew THREE.MeshBasicMaterial({ color: color(), wireframe: true }),\n\t\t\t);\n\n\t\t\tnormalsHelper = new VertexNormalsHelper(mesh, range(), color());\n\t\t\tnormalsHelper.frustumCulled = false;\n\n\t\t\tstore.snapshot.scene.add(mesh);\n\t\t\tstore.snapshot.scene.add(normalsHelper);\n\n\t\t\tonCleanup(() => {\n\t\t\t\tif (mesh) {\n\t\t\t\t\tstore.snapshot.scene.remove(mesh);\n\t\t\t\t}\n\n\t\t\t\tif (normalsHelper) {\n\t\t\t\t\tstore.snapshot.scene.remove(normalsHelper);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tbeforeRender(() => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tif (mesh) {\n\t\t\t\tconst worldPosition = object.getWorldPosition(_v3);\n\t\t\t\tmesh.position.copy(worldPosition);\n\t\t\t\tnormalsHelper?.update();\n\t\t\t}\n\t\t});\n\t});\n}\n","import { Directive, effect, ElementRef, inject, input, linkedSignal, untracked } from '@angular/core';\nimport { InteractionGroups, RigidBody } from '@dimforge/rapier3d-compat';\nimport { applyProps, NgtVector3, pick } from 'angular-three';\nimport { beforePhysicsStep, COLLISION_GROUPS_HANDLER } from 'angular-three-rapier';\nimport { mergeInputs } from 'ngxtension/inject-inputs';\nimport * as THREE from 'three';\nimport { attractorDebug } from './attractor-debug';\n\n/**\n * Force calculation functions for different gravity types.\n * - static: Constant force regardless of distance\n * - linear: Force increases linearly as distance decreases\n * - newtonian: Force follows Newton's law of universal gravitation\n */\nconst calcForceByType = {\n\tstatic: (s: number, m2: number, r: number, d: number, G: number) => s,\n\tlinear: (s: number, m2: number, r: number, d: number, G: number) => s * (d / r),\n\tnewtonian: (s: number, m2: number, r: number, d: number, G: number) => (G * s * m2) / Math.pow(d, 2),\n};\n\nconst _position = new THREE.Vector3();\nconst _vector3 = new THREE.Vector3();\n\n/**\n * Applies attractor force to a rigid body based on its distance from the attractor.\n * Used internally by NgtrAttractor but can be called manually for custom behavior.\n *\n * @param rigidBody - The rigid body to apply the force to\n * @param options - The attractor configuration including position, strength, and type\n *\n * @example\n * ```typescript\n * beforePhysicsStep((world) => {\n * world.bodies.forEach((body) => {\n * if (body.isDynamic()) {\n * applyAttractorForceOnRigidBody(body, {\n * object: attractorMesh,\n * strength: 10,\n * range: 20,\n * type: 'newtonian',\n * gravitationalConstant: 6.673e-11\n * });\n * }\n * });\n * });\n * ```\n */\nexport function applyAttractorForceOnRigidBody(\n\trigidBody: RigidBody,\n\t{\n\t\tobject,\n\t\tstrength,\n\t\trange,\n\t\tgravitationalConstant,\n\t\tcollisionGroups,\n\t\ttype,\n\t}: NgtrAttactorOptions & { object: THREE.Object3D },\n) {\n\tconst rbPosition = rigidBody.translation();\n\t_position.set(rbPosition.x, rbPosition.y, rbPosition.z);\n\n\tconst worldPosition = object.getWorldPosition(new THREE.Vector3());\n\n\tconst distance: number = worldPosition.distanceTo(_position);\n\n\tif (distance < range) {\n\t\tlet force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant);\n\n\t\t// Prevent wild forces when Attractors collide\n\t\tforce = force === Infinity ? strength : force;\n\n\t\t// Naively test if the rigidBody contains a collider in one of the collision groups\n\t\tlet isRigidBodyInCollisionGroup = collisionGroups === undefined;\n\t\tif (collisionGroups !== undefined) {\n\t\t\tfor (let i = 0; i < rigidBody.numColliders(); i++) {\n\t\t\t\tconst collider = rigidBody.collider(i);\n\t\t\t\tconst colliderCollisionGroups = collider.collisionGroups();\n\t\t\t\tif (\n\t\t\t\t\t((collisionGroups >> 16) & colliderCollisionGroups) != 0 &&\n\t\t\t\t\t((colliderCollisionGroups >> 16) & collisionGroups) != 0\n\t\t\t\t) {\n\t\t\t\t\tisRigidBodyInCollisionGroup = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (isRigidBodyInCollisionGroup) {\n\t\t\t_vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);\n\n\t\t\trigidBody.applyImpulse(_vector3, true);\n\t\t}\n\t}\n}\n\n/**\n * Type of gravity calculation for attractors.\n * - `'static'` - Constant force regardless of distance\n * - `'linear'` - Force scales linearly with distance (closer = stronger)\n * - `'newtonian'` - Force follows Newton's law of universal gravitation (inverse square)\n */\nexport type NgtrAttractorGravityType = 'static' | 'linear' | 'newtonian';\n\n/**\n * Configuration options for the attractor directive.\n */\nexport interface NgtrAttactorOptions {\n\t/**\n\t * The strength of the attractor.\n\t * Positive values attract, negative values repel.\n\t *\n\t * @defaultValue 1\n\t */\n\tstrength: number;\n\n\t/**\n\t * The range of the attractor. Will not affect objects outside of this range.\n\t *\n\t * @defaultValue 10\n\t * @min 0\n\t */\n\trange: number;\n\n\t/**\n\t * The type of gravity to use.\n\t * - static: The gravity is constant and does not change over time.\n\t * - linear: The gravity is linearly interpolated the closer the object is to the attractor.\n\t * - newtonian: The gravity is calculated using the newtonian gravity formula.\n\t * @defaultValue \"static\"\n\t */\n\ttype: NgtrAttractorGravityType;\n\n\t/**\n\t * The mass of the attractor. Used when type is `newtonian`.\n\t * @defaultValue 6.673e-11\n\t */\n\tgravitationalConstant: number;\n\n\t/**\n\t * The collision groups that this attractor will apply effects to. If a RigidBody contains one or more colliders that are in one of the mask group, it will be affected by this attractor.\n\t * If not specified, the attractor will apply effects to all RigidBodies.\n\t */\n\tcollisionGroups?: InteractionGroups;\n}\n\nconst defaultOptions: NgtrAttactorOptions = {\n\tstrength: 1,\n\trange: 10,\n\ttype: 'static',\n\tgravitationalConstant: 6.673e-11,\n};\n\n/**\n * Directive that creates a gravitational attractor point in the physics world.\n * All dynamic rigid bodies within range will be attracted (or repelled) towards this point.\n *\n * The attractor can use different gravity models:\n * - Static: constant force\n * - Linear: force increases as objects get closer\n * - Newtonian: realistic inverse-square law\n *\n * @example\n * ```html\n * <!-- Simple attractor at origin -->\n * <ngt-object3D attractor [options]=\"{ strength: 5, range: 20 }\" />\n *\n * <!-- Repeller (negative strength) -->\n * <ngt-object3D attractor [options]=\"{ strength: -10, range: 15 }\" [position]=\"[5, 0, 0]\" />\n *\n * <!-- Newtonian gravity -->\n * <ngt-object3D attractor [options]=\"{\n * strength: 1000,\n * range: 50,\n * type: 'newtonian',\n * gravitationalConstant: 0.01\n * }\" />\n * ```\n */\n@Directive({\n\tselector: 'ngt-object3D[attractor]',\n\tproviders: [\n\t\t{\n\t\t\tprovide: COLLISION_GROUPS_HANDLER,\n\t\t\tuseFactory: (attractor: NgtrAttractor) => {\n\t\t\t\treturn () => (interactionGroups: InteractionGroups) => {\n\t\t\t\t\tattractor.linkedCollisionGroups.set(interactionGroups);\n\t\t\t\t};\n\t\t\t},\n\t\t\tdeps: [NgtrAttractor],\n\t\t},\n\t],\n})\nexport class NgtrAttractor {\n\tposition = input<NgtVector3>([0, 0, 0]);\n\toptions = input(defaultOptions, { transform: mergeInputs(defaultOptions) });\n\n\tprivate objectRef = inject<ElementRef<THREE.Object3D>>(ElementRef);\n\tprivate collisionGroups = pick(this.options, 'collisionGroups');\n\tlinkedCollisionGroups = linkedSignal(this.collisionGroups);\n\n\tconstructor() {\n\t\teffect(() => {\n\t\t\tapplyProps(this.objectRef.nativeElement, { position: this.position() });\n\t\t});\n\n\t\tbeforePhysicsStep((world) => {\n\t\t\tconst { strength, range, type, gravitationalConstant } = untracked(this.options);\n\t\t\tconst collisionGroups = untracked(this.linkedCollisionGroups);\n\t\t\tworld.bodies.forEach((body) => {\n\t\t\t\tif (body.isDynamic()) {\n\t\t\t\t\tapplyAttractorForceOnRigidBody(body, {\n\t\t\t\t\t\tobject: this.objectRef.nativeElement,\n\t\t\t\t\t\tstrength,\n\t\t\t\t\t\trange,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tgravitationalConstant,\n\t\t\t\t\t\tcollisionGroups,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tattractorDebug(this.objectRef.nativeElement, this.options);\n\t}\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"angular-three-rapier-addons.mjs","sources":["../../../../libs/rapier/addons/src/lib/attractor-debug.ts","../../../../libs/rapier/addons/src/lib/attractor.ts","../../../../libs/rapier/addons/src/angular-three-rapier-addons.ts"],"sourcesContent":["import { computed, effect, inject, Injector } from '@angular/core';\nimport { beforeRender, injectStore, pick } from 'angular-three';\nimport { NgtrPhysics } from 'angular-three-rapier';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport * as THREE from 'three';\nimport { VertexNormalsHelper } from 'three-stdlib';\nimport { NgtrAttactorOptions } from './attractor';\n\nconst _v3 = new THREE.Vector3();\n\n/**\n * Creates debug visualization for an attractor.\n * Shows a sphere at the attractor position with normals indicating the range.\n * Blue indicates attraction, red indicates repulsion.\n *\n * This is automatically called by NgtrAttractor when physics debug mode is enabled.\n *\n * @param object - The Object3D representing the attractor position\n * @param options - Getter function for attractor options\n * @param injector - Optional injector for dependency injection context\n *\n * @internal\n */\nexport function attractorDebug(object: THREE.Object3D, options: () => NgtrAttactorOptions, injector?: Injector) {\n\treturn assertInjector(attractorDebug, injector, () => {\n\t\tconst physics = inject(NgtrPhysics);\n\t\tconst store = injectStore();\n\n\t\tconst strength = pick(options, 'strength');\n\t\tconst range = pick(options, 'range');\n\t\tconst color = computed(() => (strength() > 0 ? 0x0000ff : 0xff0000));\n\n\t\tlet mesh: THREE.Mesh;\n\t\tlet normalsHelper: VertexNormalsHelper;\n\n\t\teffect((onCleanup) => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tmesh = new THREE.Mesh(\n\t\t\t\tnew THREE.SphereGeometry(0.2, 6, 6),\n\t\t\t\tnew THREE.MeshBasicMaterial({ color: color(), wireframe: true }),\n\t\t\t);\n\n\t\t\tnormalsHelper = new VertexNormalsHelper(mesh, range(), color());\n\t\t\tnormalsHelper.frustumCulled = false;\n\n\t\t\tstore.snapshot.scene.add(mesh);\n\t\t\tstore.snapshot.scene.add(normalsHelper);\n\n\t\t\tonCleanup(() => {\n\t\t\t\tif (mesh) {\n\t\t\t\t\tstore.snapshot.scene.remove(mesh);\n\t\t\t\t}\n\n\t\t\t\tif (normalsHelper) {\n\t\t\t\t\tstore.snapshot.scene.remove(normalsHelper);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tbeforeRender(() => {\n\t\t\tif (!physics['debug']() || !mesh || !normalsHelper) return;\n\n\t\t\tconst worldPosition = object.getWorldPosition(_v3);\n\t\t\tmesh.position.copy(worldPosition);\n\t\t\tnormalsHelper.update();\n\t\t});\n\t});\n}\n","import { Directive, effect, ElementRef, inject, input, linkedSignal, untracked } from '@angular/core';\nimport { InteractionGroups, RigidBody } from '@dimforge/rapier3d-compat';\nimport { applyProps, NgtVector3, pick } from 'angular-three';\nimport { beforePhysicsStep, COLLISION_GROUPS_HANDLER } from 'angular-three-rapier';\nimport { mergeInputs } from 'ngxtension/inject-inputs';\nimport * as THREE from 'three';\nimport { attractorDebug } from './attractor-debug';\n\n/**\n * Force calculation functions for different gravity types.\n * - static: Constant force regardless of distance\n * - linear: Force increases linearly as distance decreases\n * - newtonian: Force follows Newton's law of universal gravitation\n */\nconst calcForceByType = {\n\tstatic: (s: number, m2: number, r: number, d: number, G: number) => s,\n\tlinear: (s: number, m2: number, r: number, d: number, G: number) => s * (d / r),\n\tnewtonian: (s: number, m2: number, r: number, d: number, G: number) => (G * s * m2) / Math.pow(d, 2),\n};\n\nconst _position = new THREE.Vector3();\nconst _vector3 = new THREE.Vector3();\n\n/**\n * Applies attractor force to a rigid body based on its distance from the attractor.\n * Used internally by NgtrAttractor but can be called manually for custom behavior.\n *\n * @param rigidBody - The rigid body to apply the force to\n * @param options - The attractor configuration including position, strength, and type\n *\n * @example\n * ```typescript\n * beforePhysicsStep((world) => {\n * world.bodies.forEach((body) => {\n * if (body.isDynamic()) {\n * applyAttractorForceOnRigidBody(body, {\n * object: attractorMesh,\n * strength: 10,\n * range: 20,\n * type: 'newtonian',\n * gravitationalConstant: 6.673e-11\n * });\n * }\n * });\n * });\n * ```\n */\nexport function applyAttractorForceOnRigidBody(\n\trigidBody: RigidBody,\n\t{\n\t\tobject,\n\t\tstrength,\n\t\trange,\n\t\tgravitationalConstant,\n\t\tcollisionGroups,\n\t\ttype,\n\t}: NgtrAttactorOptions & { object: THREE.Object3D },\n) {\n\tconst rbPosition = rigidBody.translation();\n\t_position.set(rbPosition.x, rbPosition.y, rbPosition.z);\n\n\tconst worldPosition = object.getWorldPosition(new THREE.Vector3());\n\n\tconst distance: number = worldPosition.distanceTo(_position);\n\n\tif (distance < range) {\n\t\tlet force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant);\n\n\t\t// Prevent wild forces when Attractors collide\n\t\tforce = force === Infinity ? strength : force;\n\n\t\t// Naively test if the rigidBody contains a collider in one of the collision groups\n\t\tlet isRigidBodyInCollisionGroup = collisionGroups === undefined;\n\t\tif (collisionGroups !== undefined) {\n\t\t\tfor (let i = 0; i < rigidBody.numColliders(); i++) {\n\t\t\t\tconst collider = rigidBody.collider(i);\n\t\t\t\tconst colliderCollisionGroups = collider.collisionGroups();\n\t\t\t\tif (\n\t\t\t\t\t((collisionGroups >> 16) & colliderCollisionGroups) != 0 &&\n\t\t\t\t\t((colliderCollisionGroups >> 16) & collisionGroups) != 0\n\t\t\t\t) {\n\t\t\t\t\tisRigidBodyInCollisionGroup = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (isRigidBodyInCollisionGroup) {\n\t\t\t_vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);\n\n\t\t\trigidBody.applyImpulse(_vector3, true);\n\t\t}\n\t}\n}\n\n/**\n * Type of gravity calculation for attractors.\n * - `'static'` - Constant force regardless of distance\n * - `'linear'` - Force scales linearly with distance (closer = stronger)\n * - `'newtonian'` - Force follows Newton's law of universal gravitation (inverse square)\n */\nexport type NgtrAttractorGravityType = 'static' | 'linear' | 'newtonian';\n\n/**\n * Configuration options for the attractor directive.\n */\nexport interface NgtrAttactorOptions {\n\t/**\n\t * The strength of the attractor.\n\t * Positive values attract, negative values repel.\n\t *\n\t * @defaultValue 1\n\t */\n\tstrength: number;\n\n\t/**\n\t * The range of the attractor. Will not affect objects outside of this range.\n\t *\n\t * @defaultValue 10\n\t * @min 0\n\t */\n\trange: number;\n\n\t/**\n\t * The type of gravity to use.\n\t * - static: The gravity is constant and does not change over time.\n\t * - linear: The gravity is linearly interpolated the closer the object is to the attractor.\n\t * - newtonian: The gravity is calculated using the newtonian gravity formula.\n\t * @defaultValue \"static\"\n\t */\n\ttype: NgtrAttractorGravityType;\n\n\t/**\n\t * The mass of the attractor. Used when type is `newtonian`.\n\t * @defaultValue 6.673e-11\n\t */\n\tgravitationalConstant: number;\n\n\t/**\n\t * The collision groups that this attractor will apply effects to. If a RigidBody contains one or more colliders that are in one of the mask group, it will be affected by this attractor.\n\t * If not specified, the attractor will apply effects to all RigidBodies.\n\t */\n\tcollisionGroups?: InteractionGroups;\n}\n\nconst defaultOptions: NgtrAttactorOptions = {\n\tstrength: 1,\n\trange: 10,\n\ttype: 'static',\n\tgravitationalConstant: 6.673e-11,\n};\n\n/**\n * Directive that creates a gravitational attractor point in the physics world.\n * All dynamic rigid bodies within range will be attracted (or repelled) towards this point.\n *\n * The attractor can use different gravity models:\n * - Static: constant force\n * - Linear: force increases as objects get closer\n * - Newtonian: realistic inverse-square law\n *\n * @example\n * ```html\n * <!-- Simple attractor at origin with default options -->\n * <ngt-object3D attractor />\n *\n * <!-- Attractor with custom options -->\n * <ngt-object3D [attractor]=\"{ strength: 5, range: 20 }\" />\n *\n * <!-- Repeller (negative strength) -->\n * <ngt-object3D [attractor]=\"{ strength: -10, range: 15 }\" [position]=\"[5, 0, 0]\" />\n *\n * <!-- Newtonian gravity -->\n * <ngt-object3D [attractor]=\"{\n * strength: 1000,\n * range: 50,\n * type: 'newtonian',\n * gravitationalConstant: 0.01\n * }\" />\n * ```\n */\n@Directive({\n\tselector: 'ngt-object3D[attractor]',\n\tproviders: [\n\t\t{\n\t\t\tprovide: COLLISION_GROUPS_HANDLER,\n\t\t\tuseFactory: (attractor: NgtrAttractor) => {\n\t\t\t\treturn () => (interactionGroups: InteractionGroups) => {\n\t\t\t\t\tattractor.linkedCollisionGroups.set(interactionGroups);\n\t\t\t\t};\n\t\t\t},\n\t\t\tdeps: [NgtrAttractor],\n\t\t},\n\t],\n})\nexport class NgtrAttractor {\n\tposition = input<NgtVector3>([0, 0, 0]);\n\toptions = input(defaultOptions, { alias: 'attractor', transform: mergeInputs(defaultOptions) });\n\n\tprivate objectRef = inject<ElementRef<THREE.Object3D>>(ElementRef);\n\tprivate collisionGroups = pick(this.options, 'collisionGroups');\n\tlinkedCollisionGroups = linkedSignal(this.collisionGroups);\n\n\tconstructor() {\n\t\teffect(() => {\n\t\t\tapplyProps(this.objectRef.nativeElement, { position: this.position() });\n\t\t});\n\n\t\tbeforePhysicsStep((world) => {\n\t\t\tconst { strength, range, type, gravitationalConstant } = untracked(this.options);\n\t\t\tconst collisionGroups = untracked(this.linkedCollisionGroups);\n\t\t\tworld.bodies.forEach((body) => {\n\t\t\t\tif (body.isDynamic()) {\n\t\t\t\t\tapplyAttractorForceOnRigidBody(body, {\n\t\t\t\t\t\tobject: this.objectRef.nativeElement,\n\t\t\t\t\t\tstrength,\n\t\t\t\t\t\trange,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tgravitationalConstant,\n\t\t\t\t\t\tcollisionGroups,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tattractorDebug(this.objectRef.nativeElement, this.options);\n\t}\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -84,14 +84,17 @@ interface NgtrAttactorOptions {
|
|
|
84
84
|
*
|
|
85
85
|
* @example
|
|
86
86
|
* ```html
|
|
87
|
-
* <!-- Simple attractor at origin -->
|
|
88
|
-
* <ngt-object3D attractor
|
|
87
|
+
* <!-- Simple attractor at origin with default options -->
|
|
88
|
+
* <ngt-object3D attractor />
|
|
89
|
+
*
|
|
90
|
+
* <!-- Attractor with custom options -->
|
|
91
|
+
* <ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
|
|
89
92
|
*
|
|
90
93
|
* <!-- Repeller (negative strength) -->
|
|
91
|
-
* <ngt-object3D attractor
|
|
94
|
+
* <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
|
|
92
95
|
*
|
|
93
96
|
* <!-- Newtonian gravity -->
|
|
94
|
-
* <ngt-object3D attractor
|
|
97
|
+
* <ngt-object3D [attractor]="{
|
|
95
98
|
* strength: 1000,
|
|
96
99
|
* range: 50,
|
|
97
100
|
* type: 'newtonian',
|
|
@@ -107,7 +110,7 @@ declare class NgtrAttractor {
|
|
|
107
110
|
linkedCollisionGroups: _angular_core.WritableSignal<number | undefined>;
|
|
108
111
|
constructor();
|
|
109
112
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgtrAttractor, never>;
|
|
110
|
-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgtrAttractor, "ngt-object3D[attractor]", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; "options": { "alias": "
|
|
113
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgtrAttractor, "ngt-object3D[attractor]", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; "options": { "alias": "attractor"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
export { NgtrAttractor, applyAttractorForceOnRigidBody };
|