@series-inc/rundot-3d-engine 0.3.0 → 0.4.0

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.
@@ -1,249 +1,249 @@
1
- # Colliders
2
-
3
- Collision shapes and trigger systems for physics interactions using Rapier3D.
4
-
5
- ## Collider Shapes
6
-
7
- ### Box Collider
8
-
9
- ```typescript
10
- new RigidBodyComponentThree({
11
- shape: ColliderShape.BOX,
12
- size: new THREE.Vector3(width, height, depth)
13
- })
14
- ```
15
-
16
- Best for: Crates, walls, platforms, buildings
17
-
18
- ### Sphere Collider
19
-
20
- ```typescript
21
- new RigidBodyComponentThree({
22
- shape: ColliderShape.SPHERE,
23
- radius: 0.5
24
- })
25
- ```
26
-
27
- Best for: Balls, projectiles, round objects
28
-
29
- ### Capsule Collider
30
-
31
- ```typescript
32
- new RigidBodyComponentThree({
33
- shape: ColliderShape.CAPSULE,
34
- radius: 0.5,
35
- height: 2.0
36
- })
37
- ```
38
-
39
- Best for: Characters, cylinders (smooth movement, no edge catching)
40
-
41
- ## Auto-Fitted Colliders (Bounds)
42
-
43
- Instead of manually specifying collider dimensions, you can automatically fit colliders to mesh bounds:
44
-
45
- ### fitToMesh Option
46
-
47
- The simplest way to auto-fit a collider to a mesh:
48
-
49
- ```typescript
50
- const rigidBody = new RigidBodyComponentThree({
51
- type: RigidBodyType.DYNAMIC,
52
- shape: ColliderShape.BOX,
53
- fitToMesh: true // Automatically calculates size from mesh bounds
54
- })
55
- this.gameObject.addComponent(rigidBody)
56
- ```
57
-
58
- Best for: Any mesh where you want automatic collision sizing
59
-
60
- ### Manual Bounds Calculation
61
-
62
- Calculate bounds manually for more control:
63
-
64
- ```typescript
65
- // Get bounds from GameObject's meshes
66
- const bounds = RigidBodyComponentThree.getMeshBounds(this.gameObject)
67
-
68
- // Create collider with calculated bounds
69
- const rigidBody = new RigidBodyComponentThree({
70
- type: RigidBodyType.STATIC,
71
- shape: ColliderShape.BOX,
72
- size: bounds
73
- })
74
- this.gameObject.addComponent(rigidBody)
75
- ```
76
-
77
- ### Using MeshRenderer Bounds
78
-
79
- Get bounds directly from a MeshRenderer component:
80
-
81
- ```typescript
82
- const renderer = this.gameObject.getComponent(MeshRenderer)
83
- const bounds = renderer?.getBounds()
84
-
85
- if (bounds) {
86
- const rigidBody = RigidBodyComponentThree.fromBounds(bounds, {
87
- type: RigidBodyType.STATIC,
88
- shape: ColliderShape.BOX
89
- })
90
- this.gameObject.addComponent(rigidBody)
91
- }
92
- ```
93
-
94
- ### When to Use Bounds vs Manual Sizing
95
-
96
- **Use Auto-Fitted Bounds When:**
97
- - ✅ Mesh shape closely matches the desired collision shape
98
- - ✅ Accurate collision is more important than performance
99
- - ✅ Prototyping or rapid development
100
- - ✅ Mesh dimensions are unknown or variable
101
-
102
- **Use Manual Primitive Colliders When:**
103
- - ✅ Mesh is complex with many vertices
104
- - ✅ Approximate collision is acceptable
105
- - ✅ Performance is critical (many instances)
106
- - ✅ Simpler collision behavior is desired
107
- - ✅ Collision shape should be different from visual mesh
108
-
109
- See [Mesh Colliders Pattern](../patterns/MeshColliders.md) for detailed examples.
110
-
111
- ## Trigger Colliders (Sensors)
112
-
113
- Triggers detect overlaps without physical collision:
114
-
115
- ```typescript
116
- class PickupZone extends Component {
117
- protected onCreate(): void {
118
- const trigger = new RigidBodyComponentThree({
119
- type: RigidBodyType.STATIC,
120
- shape: ColliderShape.BOX,
121
- size: new THREE.Vector3(2, 2, 2),
122
- isSensor: true // Makes it a trigger
123
- })
124
- this.gameObject.addComponent(trigger)
125
-
126
- trigger.onTriggerEnter((other: GameObject) => {
127
- console.log(`${other.name} entered pickup zone`)
128
- this.collectItem(other)
129
- })
130
-
131
- trigger.onTriggerExit((other: GameObject) => {
132
- console.log(`${other.name} left pickup zone`)
133
- })
134
- }
135
- }
136
- ```
137
-
138
- ## Collision Groups
139
-
140
- Filter which objects collide with each other:
141
-
142
- ```typescript
143
- import { createCollisionGroup } from "@series-ai/rundot-3d-engine/systems"
144
-
145
- // Define groups (16-bit bitmasks)
146
- const PLAYER_GROUP = 0x0001
147
- const ENEMY_GROUP = 0x0002
148
- const PROJECTILE_GROUP = 0x0004
149
-
150
- // Player collides with enemies and projectiles
151
- const playerBody = new RigidBodyComponentThree({
152
- type: RigidBodyType.DYNAMIC,
153
- collisionGroups: createCollisionGroup(
154
- PLAYER_GROUP, // I am player
155
- ENEMY_GROUP | PROJECTILE_GROUP // I collide with these
156
- )
157
- })
158
-
159
- // Enemy collides only with player
160
- const enemyBody = new RigidBodyComponentThree({
161
- type: RigidBodyType.DYNAMIC,
162
- collisionGroups: createCollisionGroup(
163
- ENEMY_GROUP, // I am enemy
164
- PLAYER_GROUP // I collide with player only
165
- )
166
- })
167
- ```
168
-
169
- ## Collision Properties
170
-
171
- ### Restitution (Bounciness)
172
-
173
- ```typescript
174
- restitution: 0.0 // No bounce (clay)
175
- restitution: 0.5 // Medium bounce (wood)
176
- restitution: 0.9 // High bounce (rubber ball)
177
- ```
178
-
179
- ### Friction
180
-
181
- ```typescript
182
- friction: 0.0 // Ice (slippery)
183
- friction: 0.5 // Normal (wood on wood)
184
- friction: 1.0 // High friction (rubber)
185
- ```
186
-
187
- ## Common Patterns
188
-
189
- ### Character Controller
190
-
191
- ```typescript
192
- const character = new GameObject("Player")
193
- character.addComponent(new RigidBodyComponentThree({
194
- type: RigidBodyType.DYNAMIC,
195
- shape: ColliderShape.CAPSULE,
196
- radius: 0.5,
197
- height: 1.8,
198
- mass: 70,
199
- friction: 0.0, // Smooth movement
200
- lockRotationX: true, // No tipping
201
- lockRotationY: true,
202
- lockRotationZ: true,
203
- linearDamping: 0.9 // Quick stop
204
- }))
205
- ```
206
-
207
- ### Projectile
208
-
209
- ```typescript
210
- const bullet = new GameObject("Bullet")
211
- bullet.addComponent(new RigidBodyComponentThree({
212
- type: RigidBodyType.DYNAMIC,
213
- shape: ColliderShape.SPHERE,
214
- radius: 0.1,
215
- mass: 0.01,
216
- restitution: 0.3,
217
- friction: 0.1
218
- }))
219
-
220
- // Apply velocity
221
- const rb = bullet.getComponent(RigidBodyComponentThree)
222
- rb?.setLinearVelocity(new THREE.Vector3(0, 0, 50))
223
- ```
224
-
225
- ### Trigger Zone
226
-
227
- ```typescript
228
- const zone = new GameObject("TriggerZone")
229
- const trigger = new RigidBodyComponentThree({
230
- type: RigidBodyType.STATIC,
231
- shape: ColliderShape.BOX,
232
- size: new THREE.Vector3(10, 5, 10),
233
- isSensor: true
234
- })
235
- zone.addComponent(trigger)
236
-
237
- trigger.onTriggerEnter((other) => {
238
- if (other.name === "Player") {
239
- console.log("Player entered zone!")
240
- }
241
- })
242
- ```
243
-
244
- ## Related Systems
245
-
246
- - [RigidBodyComponent](RigidBodyComponent.md) - Physics bodies
247
- - [PhysicsSystem](PhysicsSystem.md) - Physics simulation
248
- - [Mesh Colliders Pattern](../patterns/MeshColliders.md) - Loading meshes with collision
249
-
1
+ # Colliders
2
+
3
+ Collision shapes and trigger systems for physics interactions using Rapier3D.
4
+
5
+ ## Collider Shapes
6
+
7
+ ### Box Collider
8
+
9
+ ```typescript
10
+ new RigidBodyComponentThree({
11
+ shape: ColliderShape.BOX,
12
+ size: new THREE.Vector3(width, height, depth)
13
+ })
14
+ ```
15
+
16
+ Best for: Crates, walls, platforms, buildings
17
+
18
+ ### Sphere Collider
19
+
20
+ ```typescript
21
+ new RigidBodyComponentThree({
22
+ shape: ColliderShape.SPHERE,
23
+ radius: 0.5
24
+ })
25
+ ```
26
+
27
+ Best for: Balls, projectiles, round objects
28
+
29
+ ### Capsule Collider
30
+
31
+ ```typescript
32
+ new RigidBodyComponentThree({
33
+ shape: ColliderShape.CAPSULE,
34
+ radius: 0.5,
35
+ height: 2.0
36
+ })
37
+ ```
38
+
39
+ Best for: Characters, cylinders (smooth movement, no edge catching)
40
+
41
+ ## Auto-Fitted Colliders (Bounds)
42
+
43
+ Instead of manually specifying collider dimensions, you can automatically fit colliders to mesh bounds:
44
+
45
+ ### fitToMesh Option
46
+
47
+ The simplest way to auto-fit a collider to a mesh:
48
+
49
+ ```typescript
50
+ const rigidBody = new RigidBodyComponentThree({
51
+ type: RigidBodyType.DYNAMIC,
52
+ shape: ColliderShape.BOX,
53
+ fitToMesh: true // Automatically calculates size from mesh bounds
54
+ })
55
+ this.gameObject.addComponent(rigidBody)
56
+ ```
57
+
58
+ Best for: Any mesh where you want automatic collision sizing
59
+
60
+ ### Manual Bounds Calculation
61
+
62
+ Calculate bounds manually for more control:
63
+
64
+ ```typescript
65
+ // Get bounds from GameObject's meshes
66
+ const bounds = RigidBodyComponentThree.getMeshBounds(this.gameObject)
67
+
68
+ // Create collider with calculated bounds
69
+ const rigidBody = new RigidBodyComponentThree({
70
+ type: RigidBodyType.STATIC,
71
+ shape: ColliderShape.BOX,
72
+ size: bounds
73
+ })
74
+ this.gameObject.addComponent(rigidBody)
75
+ ```
76
+
77
+ ### Using MeshRenderer Bounds
78
+
79
+ Get bounds directly from a MeshRenderer component:
80
+
81
+ ```typescript
82
+ const renderer = this.gameObject.getComponent(MeshRenderer)
83
+ const bounds = renderer?.getBounds()
84
+
85
+ if (bounds) {
86
+ const rigidBody = RigidBodyComponentThree.fromBounds(bounds, {
87
+ type: RigidBodyType.STATIC,
88
+ shape: ColliderShape.BOX
89
+ })
90
+ this.gameObject.addComponent(rigidBody)
91
+ }
92
+ ```
93
+
94
+ ### When to Use Bounds vs Manual Sizing
95
+
96
+ **Use Auto-Fitted Bounds When:**
97
+ - ✅ Mesh shape closely matches the desired collision shape
98
+ - ✅ Accurate collision is more important than performance
99
+ - ✅ Prototyping or rapid development
100
+ - ✅ Mesh dimensions are unknown or variable
101
+
102
+ **Use Manual Primitive Colliders When:**
103
+ - ✅ Mesh is complex with many vertices
104
+ - ✅ Approximate collision is acceptable
105
+ - ✅ Performance is critical (many instances)
106
+ - ✅ Simpler collision behavior is desired
107
+ - ✅ Collision shape should be different from visual mesh
108
+
109
+ See [Mesh Colliders Pattern](../patterns/MeshColliders.md) for detailed examples.
110
+
111
+ ## Trigger Colliders (Sensors)
112
+
113
+ Triggers detect overlaps without physical collision:
114
+
115
+ ```typescript
116
+ class PickupZone extends Component {
117
+ protected onCreate(): void {
118
+ const trigger = new RigidBodyComponentThree({
119
+ type: RigidBodyType.STATIC,
120
+ shape: ColliderShape.BOX,
121
+ size: new THREE.Vector3(2, 2, 2),
122
+ isSensor: true // Makes it a trigger
123
+ })
124
+ this.gameObject.addComponent(trigger)
125
+
126
+ trigger.onTriggerEnter((other: GameObject) => {
127
+ console.log(`${other.name} entered pickup zone`)
128
+ this.collectItem(other)
129
+ })
130
+
131
+ trigger.onTriggerExit((other: GameObject) => {
132
+ console.log(`${other.name} left pickup zone`)
133
+ })
134
+ }
135
+ }
136
+ ```
137
+
138
+ ## Collision Groups
139
+
140
+ Filter which objects collide with each other:
141
+
142
+ ```typescript
143
+ import { createCollisionGroup } from "@series-ai/rundot-3d-engine/systems"
144
+
145
+ // Define groups (16-bit bitmasks)
146
+ const PLAYER_GROUP = 0x0001
147
+ const ENEMY_GROUP = 0x0002
148
+ const PROJECTILE_GROUP = 0x0004
149
+
150
+ // Player collides with enemies and projectiles
151
+ const playerBody = new RigidBodyComponentThree({
152
+ type: RigidBodyType.DYNAMIC,
153
+ collisionGroups: createCollisionGroup(
154
+ PLAYER_GROUP, // I am player
155
+ ENEMY_GROUP | PROJECTILE_GROUP // I collide with these
156
+ )
157
+ })
158
+
159
+ // Enemy collides only with player
160
+ const enemyBody = new RigidBodyComponentThree({
161
+ type: RigidBodyType.DYNAMIC,
162
+ collisionGroups: createCollisionGroup(
163
+ ENEMY_GROUP, // I am enemy
164
+ PLAYER_GROUP // I collide with player only
165
+ )
166
+ })
167
+ ```
168
+
169
+ ## Collision Properties
170
+
171
+ ### Restitution (Bounciness)
172
+
173
+ ```typescript
174
+ restitution: 0.0 // No bounce (clay)
175
+ restitution: 0.5 // Medium bounce (wood)
176
+ restitution: 0.9 // High bounce (rubber ball)
177
+ ```
178
+
179
+ ### Friction
180
+
181
+ ```typescript
182
+ friction: 0.0 // Ice (slippery)
183
+ friction: 0.5 // Normal (wood on wood)
184
+ friction: 1.0 // High friction (rubber)
185
+ ```
186
+
187
+ ## Common Patterns
188
+
189
+ ### Character Controller
190
+
191
+ ```typescript
192
+ const character = new GameObject("Player")
193
+ character.addComponent(new RigidBodyComponentThree({
194
+ type: RigidBodyType.DYNAMIC,
195
+ shape: ColliderShape.CAPSULE,
196
+ radius: 0.5,
197
+ height: 1.8,
198
+ mass: 70,
199
+ friction: 0.0, // Smooth movement
200
+ lockRotationX: true, // No tipping
201
+ lockRotationY: true,
202
+ lockRotationZ: true,
203
+ linearDamping: 0.9 // Quick stop
204
+ }))
205
+ ```
206
+
207
+ ### Projectile
208
+
209
+ ```typescript
210
+ const bullet = new GameObject("Bullet")
211
+ bullet.addComponent(new RigidBodyComponentThree({
212
+ type: RigidBodyType.DYNAMIC,
213
+ shape: ColliderShape.SPHERE,
214
+ radius: 0.1,
215
+ mass: 0.01,
216
+ restitution: 0.3,
217
+ friction: 0.1
218
+ }))
219
+
220
+ // Apply velocity
221
+ const rb = bullet.getComponent(RigidBodyComponentThree)
222
+ rb?.setLinearVelocity(new THREE.Vector3(0, 0, 50))
223
+ ```
224
+
225
+ ### Trigger Zone
226
+
227
+ ```typescript
228
+ const zone = new GameObject("TriggerZone")
229
+ const trigger = new RigidBodyComponentThree({
230
+ type: RigidBodyType.STATIC,
231
+ shape: ColliderShape.BOX,
232
+ size: new THREE.Vector3(10, 5, 10),
233
+ isSensor: true
234
+ })
235
+ zone.addComponent(trigger)
236
+
237
+ trigger.onTriggerEnter((other) => {
238
+ if (other.name === "Player") {
239
+ console.log("Player entered zone!")
240
+ }
241
+ })
242
+ ```
243
+
244
+ ## Related Systems
245
+
246
+ - [RigidBodyComponent](RigidBodyComponent.md) - Physics bodies
247
+ - [PhysicsSystem](PhysicsSystem.md) - Physics simulation
248
+ - [Mesh Colliders Pattern](../patterns/MeshColliders.md) - Loading meshes with collision
249
+