react-three-game 0.0.51 → 0.0.52
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/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +3 -1
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +25 -2
- package/package.json +1 -1
- package/react-three-game-skill/react-three-game/SKILL.md +4 -2
- package/react-three-game-skill/react-three-game/rules/ADVANCED_PHYSICS.md +17 -1
- package/src/tools/prefabeditor/components/PhysicsComponent.tsx +31 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { RigidBodyOptions } from "@react-three/rapier";
|
|
2
2
|
import { Component } from "./ComponentRegistry";
|
|
3
|
-
export type PhysicsProps = RigidBodyOptions
|
|
3
|
+
export type PhysicsProps = RigidBodyOptions & {
|
|
4
|
+
activeCollisionTypes?: 'all' | undefined;
|
|
5
|
+
};
|
|
4
6
|
declare const PhysicsComponent: Component;
|
|
5
7
|
export default PhysicsComponent;
|
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
-
import { RigidBody } from "@react-three/rapier";
|
|
13
|
+
import { RigidBody, useRapier } from "@react-three/rapier";
|
|
14
14
|
import { useRef, useEffect, useCallback } from 'react';
|
|
15
15
|
import { FieldRenderer } from "./Input";
|
|
16
16
|
import { gameEvents, getEntityIdFromRigidBody } from "../GameEvents";
|
|
@@ -82,14 +82,24 @@ const physicsFields = [
|
|
|
82
82
|
type: 'boolean',
|
|
83
83
|
label: 'Sensor (Trigger Only)',
|
|
84
84
|
},
|
|
85
|
+
{
|
|
86
|
+
name: 'activeCollisionTypes',
|
|
87
|
+
type: 'select',
|
|
88
|
+
label: 'Collision Detection',
|
|
89
|
+
options: [
|
|
90
|
+
{ value: '', label: 'Default (Dynamic only)' },
|
|
91
|
+
{ value: 'all', label: 'All (includes kinematic & fixed)' },
|
|
92
|
+
],
|
|
93
|
+
},
|
|
85
94
|
];
|
|
86
95
|
function PhysicsComponentEditor({ component, onUpdate }) {
|
|
87
96
|
return (_jsx(FieldRenderer, { fields: physicsFields, values: component.properties, onChange: (props) => onUpdate(Object.assign(Object.assign({}, component), { properties: Object.assign(Object.assign({}, component.properties), props) })) }));
|
|
88
97
|
}
|
|
89
98
|
function PhysicsComponentView({ properties, children, position, rotation, scale, editMode, nodeId, registerRigidBodyRef }) {
|
|
90
|
-
const { type, colliders, sensor } = properties, otherProps = __rest(properties, ["type", "colliders", "sensor"]);
|
|
99
|
+
const { type, colliders, sensor, activeCollisionTypes } = properties, otherProps = __rest(properties, ["type", "colliders", "sensor", "activeCollisionTypes"]);
|
|
91
100
|
const colliderType = colliders || (type === 'fixed' ? 'trimesh' : 'hull');
|
|
92
101
|
const rigidBodyRef = useRef(null);
|
|
102
|
+
const { rapier } = useRapier();
|
|
93
103
|
// Register RigidBody ref when it's available
|
|
94
104
|
useEffect(() => {
|
|
95
105
|
if (nodeId && registerRigidBodyRef && rigidBodyRef.current) {
|
|
@@ -101,6 +111,19 @@ function PhysicsComponentView({ properties, children, position, rotation, scale,
|
|
|
101
111
|
}
|
|
102
112
|
};
|
|
103
113
|
}, [nodeId, registerRigidBodyRef]);
|
|
114
|
+
// Configure active collision types for kinematic/sensor bodies
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (activeCollisionTypes === 'all' && rigidBodyRef.current) {
|
|
117
|
+
const rb = rigidBodyRef.current;
|
|
118
|
+
// Apply to all colliders on this rigid body
|
|
119
|
+
for (let i = 0; i < rb.numColliders(); i++) {
|
|
120
|
+
const collider = rb.collider(i);
|
|
121
|
+
collider.setActiveCollisionTypes(rapier.ActiveCollisionTypes.DEFAULT |
|
|
122
|
+
rapier.ActiveCollisionTypes.KINEMATIC_FIXED |
|
|
123
|
+
rapier.ActiveCollisionTypes.KINEMATIC_KINEMATIC);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}, [activeCollisionTypes, rapier, type, colliders]);
|
|
104
127
|
// Event handlers for physics interactions
|
|
105
128
|
const handleIntersectionEnter = useCallback((payload) => {
|
|
106
129
|
if (!nodeId)
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ Agents can programmatically generate 3D assets:
|
|
|
22
22
|
```tsx
|
|
23
23
|
import { useRef, useEffect } from 'react';
|
|
24
24
|
import { PrefabEditor, exportGLBData } from 'react-three-game';
|
|
25
|
-
import type { PrefabEditorRef } from 'react-three-game'
|
|
25
|
+
import type { PrefabEditorRef } from 'react-three-game'
|
|
26
26
|
|
|
27
27
|
const jsonPrefab = {
|
|
28
28
|
root: {
|
|
@@ -116,7 +116,7 @@ Scenes are defined as JSON prefabs with a root node containing children:
|
|
|
116
116
|
| Transform | `Transform` | `position: [x,y,z]`, `rotation: [x,y,z]` (radians), `scale: [x,y,z]` |
|
|
117
117
|
| Geometry | `Geometry` | `geometryType`: box/sphere/plane/cylinder, `args`: dimension array |
|
|
118
118
|
| Material | `Material` | `color`, `texture?`, `metalness?`, `roughness?`, `repeat?`, `repeatCount?` |
|
|
119
|
-
| Physics | `Physics` | `type`: dynamic/fixed/kinematicPosition/kinematicVelocity, `mass?`, `restitution?`, `friction?`, `linearDamping?`, `angularDamping?`, `gravityScale?`, plus any Rapier RigidBody props - [See advanced physics guide](./rules/ADVANCED_PHYSICS.md) |
|
|
119
|
+
| Physics | `Physics` | `type`: dynamic/fixed/kinematicPosition/kinematicVelocity, `mass?`, `restitution?`, `friction?`, `linearDamping?`, `angularDamping?`, `gravityScale?`, `sensor?`, `activeCollisionTypes?: 'all'` (enable kinematic/fixed collision detection), plus any Rapier RigidBody props - [See advanced physics guide](./rules/ADVANCED_PHYSICS.md) |
|
|
120
120
|
| Model | `Model` | `filename` (GLB/FBX path), `instanced?` for GPU batching |
|
|
121
121
|
| SpotLight | `SpotLight` | `color`, `intensity`, `angle`, `penumbra`, `distance?`, `castShadow?` |
|
|
122
122
|
| DirectionalLight | `DirectionalLight` | `color`, `intensity`, `castShadow?`, `targetOffset?: [x,y,z]` |
|
|
@@ -414,6 +414,8 @@ Physics components automatically emit these events:
|
|
|
414
414
|
| `collision:enter` | A collision starts | `{ sourceEntityId, targetEntityId, targetRigidBody }` |
|
|
415
415
|
| `collision:exit` | A collision ends | `{ sourceEntityId, targetEntityId, targetRigidBody }` |
|
|
416
416
|
|
|
417
|
+
**Collision filtering**: By default, kinematic/fixed bodies don't detect each other. For kinematic sensors or projectiles to detect walls/floors, add `"activeCollisionTypes": "all"` to the Physics properties.
|
|
418
|
+
|
|
417
419
|
See [Advanced Physics](./rules/ADVANCED_PHYSICS.md) for sensor setup and collision handling patterns.
|
|
418
420
|
|
|
419
421
|
### TypeScript: Typed Custom Events
|
|
@@ -49,7 +49,8 @@ Complete reference for `Physics` component properties:
|
|
|
49
49
|
| `enabledTranslations` | `[bool, bool, bool]` | `[true, true, true]` | Lock per axis (X, Y, Z) |
|
|
50
50
|
| `enabledRotations` | `[bool, bool, bool]` | `[true, true, true]` | Lock rotation per axis |
|
|
51
51
|
| `ccd` | `boolean` | `false` | Continuous collision detection (fast objects) |
|
|
52
|
-
| `sensor` | `boolean` | `false` | Trigger only, no collision response
|
|
52
|
+
| `sensor` | `boolean` | `false` | Trigger only, no collision response |
|
|
53
|
+
| `activeCollisionTypes` | `'all'` | - | Enable kinematic/fixed collision detection (default: dynamic only) |
|
|
53
54
|
| `collisionGroups` | `number` | - | Rapier collision groups bitfield |
|
|
54
55
|
| `solverGroups` | `number` | - | Rapier solver groups bitfield |
|
|
55
56
|
|
|
@@ -367,6 +368,21 @@ Set `sensor: true` in the Physics component:
|
|
|
367
368
|
}
|
|
368
369
|
```
|
|
369
370
|
|
|
371
|
+
**Kinematic/Fixed Collision Detection**: By default, sensors only detect `dynamic` bodies. For kinematic sensors (like bullets) or to detect kinematic players, add `"activeCollisionTypes": "all"`:
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"physics": {
|
|
376
|
+
"type": "Physics",
|
|
377
|
+
"properties": {
|
|
378
|
+
"type": "kinematicPosition",
|
|
379
|
+
"sensor": true,
|
|
380
|
+
"activeCollisionTypes": "all" // Detects walls, floors, kinematic bodies
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
370
386
|
### Physics Event Payload
|
|
371
387
|
|
|
372
388
|
All physics events include:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RigidBody, RapierRigidBody } from "@react-three/rapier";
|
|
1
|
+
import { RigidBody, RapierRigidBody, useRapier } from "@react-three/rapier";
|
|
2
2
|
import type { RigidBodyOptions, CollisionPayload, IntersectionEnterPayload, IntersectionExitPayload } from "@react-three/rapier";
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
import { useRef, useEffect, useCallback } from 'react';
|
|
@@ -7,7 +7,9 @@ import { FieldRenderer, FieldDefinition } from "./Input";
|
|
|
7
7
|
import { ComponentData } from "../types";
|
|
8
8
|
import { gameEvents, getEntityIdFromRigidBody } from "../GameEvents";
|
|
9
9
|
|
|
10
|
-
export type PhysicsProps = RigidBodyOptions
|
|
10
|
+
export type PhysicsProps = RigidBodyOptions & {
|
|
11
|
+
activeCollisionTypes?: 'all' | undefined;
|
|
12
|
+
};
|
|
11
13
|
|
|
12
14
|
const physicsFields: FieldDefinition[] = [
|
|
13
15
|
{
|
|
@@ -77,6 +79,15 @@ const physicsFields: FieldDefinition[] = [
|
|
|
77
79
|
type: 'boolean',
|
|
78
80
|
label: 'Sensor (Trigger Only)',
|
|
79
81
|
},
|
|
82
|
+
{
|
|
83
|
+
name: 'activeCollisionTypes',
|
|
84
|
+
type: 'select',
|
|
85
|
+
label: 'Collision Detection',
|
|
86
|
+
options: [
|
|
87
|
+
{ value: '', label: 'Default (Dynamic only)' },
|
|
88
|
+
{ value: 'all', label: 'All (includes kinematic & fixed)' },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
80
91
|
];
|
|
81
92
|
|
|
82
93
|
function PhysicsComponentEditor({ component, onUpdate }: { component: ComponentData; onUpdate: (newComp: any) => void }) {
|
|
@@ -101,9 +112,10 @@ interface PhysicsViewProps {
|
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
function PhysicsComponentView({ properties, children, position, rotation, scale, editMode, nodeId, registerRigidBodyRef }: PhysicsViewProps) {
|
|
104
|
-
const { type, colliders, sensor, ...otherProps } = properties;
|
|
115
|
+
const { type, colliders, sensor, activeCollisionTypes, ...otherProps } = properties;
|
|
105
116
|
const colliderType = colliders || (type === 'fixed' ? 'trimesh' : 'hull');
|
|
106
117
|
const rigidBodyRef = useRef<RapierRigidBody>(null);
|
|
118
|
+
const { rapier } = useRapier();
|
|
107
119
|
|
|
108
120
|
// Register RigidBody ref when it's available
|
|
109
121
|
useEffect(() => {
|
|
@@ -117,6 +129,22 @@ function PhysicsComponentView({ properties, children, position, rotation, scale,
|
|
|
117
129
|
};
|
|
118
130
|
}, [nodeId, registerRigidBodyRef]);
|
|
119
131
|
|
|
132
|
+
// Configure active collision types for kinematic/sensor bodies
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (activeCollisionTypes === 'all' && rigidBodyRef.current) {
|
|
135
|
+
const rb = rigidBodyRef.current;
|
|
136
|
+
// Apply to all colliders on this rigid body
|
|
137
|
+
for (let i = 0; i < rb.numColliders(); i++) {
|
|
138
|
+
const collider = rb.collider(i);
|
|
139
|
+
collider.setActiveCollisionTypes(
|
|
140
|
+
rapier.ActiveCollisionTypes.DEFAULT |
|
|
141
|
+
rapier.ActiveCollisionTypes.KINEMATIC_FIXED |
|
|
142
|
+
rapier.ActiveCollisionTypes.KINEMATIC_KINEMATIC
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}, [activeCollisionTypes, rapier, type, colliders]);
|
|
147
|
+
|
|
120
148
|
// Event handlers for physics interactions
|
|
121
149
|
const handleIntersectionEnter = useCallback((payload: IntersectionEnterPayload) => {
|
|
122
150
|
if (!nodeId) return;
|