react-three-game 0.0.27 → 0.0.28
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.
|
@@ -108,7 +108,7 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
108
108
|
return _jsxs("group", { ref: ref, children: [_jsx(GameInstanceProvider, { models: loadedModels, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, selectedId: selectedId, editMode: editMode, children: _jsx(GameObjectRenderer, { gameObject: data.root, selectedId: selectedId, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, loadedModels: loadedModels, loadedTextures: loadedTextures, editMode: editMode, parentMatrix: new Matrix4() }) }), editMode && _jsxs(_Fragment, { children: [_jsx(MapControls, { makeDefault: true }), selectedId && selectedObject && (_jsx(TransformControls, { object: selectedObject, mode: transformMode, space: "local", onObjectChange: onTransformChange }))] })] });
|
|
109
109
|
});
|
|
110
110
|
function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loadedModels, loadedTextures, editMode, parentMatrix = new Matrix4(), }) {
|
|
111
|
-
var _a, _b, _c, _d, _e;
|
|
111
|
+
var _a, _b, _c, _d, _e, _f;
|
|
112
112
|
// Early return if gameObject is null or undefined
|
|
113
113
|
if (!gameObject)
|
|
114
114
|
return null;
|
|
@@ -157,7 +157,10 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
|
|
|
157
157
|
const innerGroup = (_jsxs("group", { ref: groupRef, position: transformProps.position, rotation: transformProps.rotation, scale: transformProps.scale, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, children: [core, children] }));
|
|
158
158
|
// --- 7. Wrap with physics if needed (RigidBody as outer parent, no transform) ---
|
|
159
159
|
const physics = (_e = gameObject.components) === null || _e === void 0 ? void 0 : _e.physics;
|
|
160
|
-
if
|
|
160
|
+
// Determine if model is safe/ready for physics. No model => safe; model => only safe once loaded.
|
|
161
|
+
const modelReady = !((_f = gameObject.components) === null || _f === void 0 ? void 0 : _f.model) ||
|
|
162
|
+
!!loadedModels[gameObject.components.model.properties.filename];
|
|
163
|
+
if (physics && !editMode && modelReady) {
|
|
161
164
|
const physicsDef = getComponent('Physics');
|
|
162
165
|
if (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) {
|
|
163
166
|
return (_jsx(physicsDef.View, { properties: physics.properties, children: innerGroup }));
|
|
@@ -3,14 +3,16 @@ import { RigidBody } from "@react-three/rapier";
|
|
|
3
3
|
const selectClass = "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50";
|
|
4
4
|
const labelClass = "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5";
|
|
5
5
|
function PhysicsComponentEditor({ component, onUpdate }) {
|
|
6
|
-
const { type, collider = 'hull' } = component.properties;
|
|
6
|
+
const { type = 'dynamic', collider = 'hull' } = component.properties;
|
|
7
7
|
return (_jsxs("div", { children: [_jsx("label", { className: labelClass, children: "Type" }), _jsxs("select", { className: selectClass, value: type, onChange: e => onUpdate({ type: e.target.value }), children: [_jsx("option", { value: "dynamic", children: "Dynamic" }), _jsx("option", { value: "fixed", children: "Fixed" })] }), _jsx("label", { className: `${labelClass} mt-2`, children: "Collider" }), _jsxs("select", { className: selectClass, value: collider, onChange: e => onUpdate({ collider: e.target.value }), children: [_jsx("option", { value: "hull", children: "Hull (convex)" }), _jsx("option", { value: "trimesh", children: "Trimesh (exact)" }), _jsx("option", { value: "cuboid", children: "Cuboid (box)" }), _jsx("option", { value: "ball", children: "Ball (sphere)" })] })] }));
|
|
8
8
|
}
|
|
9
9
|
function PhysicsComponentView({ properties, editMode, children }) {
|
|
10
10
|
if (editMode)
|
|
11
11
|
return _jsx(_Fragment, { children: children });
|
|
12
12
|
const colliders = properties.collider || (properties.type === 'fixed' ? 'trimesh' : 'hull');
|
|
13
|
-
|
|
13
|
+
// Remount RigidBody when collider/type changes to avoid Rapier hook dependency warnings
|
|
14
|
+
const rbKey = `${properties.type || 'dynamic'}_${colliders}`;
|
|
15
|
+
return (_jsx(RigidBody, { type: properties.type, colliders: colliders, children: children }, rbKey));
|
|
14
16
|
}
|
|
15
17
|
const PhysicsComponent = {
|
|
16
18
|
name: 'Physics',
|
package/package.json
CHANGED
|
@@ -271,7 +271,13 @@ function GameObjectRenderer({
|
|
|
271
271
|
|
|
272
272
|
// --- 7. Wrap with physics if needed (RigidBody as outer parent, no transform) ---
|
|
273
273
|
const physics = gameObject.components?.physics;
|
|
274
|
-
|
|
274
|
+
|
|
275
|
+
// Determine if model is safe/ready for physics. No model => safe; model => only safe once loaded.
|
|
276
|
+
const modelReady =
|
|
277
|
+
!gameObject.components?.model ||
|
|
278
|
+
!!loadedModels[gameObject.components.model.properties.filename];
|
|
279
|
+
|
|
280
|
+
if (physics && !editMode && modelReady) {
|
|
275
281
|
const physicsDef = getComponent('Physics');
|
|
276
282
|
if (physicsDef?.View) {
|
|
277
283
|
return (
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { RigidBody } from "@react-three/rapier";
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
2
3
|
import { Component } from "./ComponentRegistry";
|
|
3
4
|
|
|
4
5
|
const selectClass = "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50";
|
|
5
6
|
const labelClass = "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5";
|
|
6
7
|
|
|
7
|
-
function PhysicsComponentEditor({ component, onUpdate }: { component: any; onUpdate: (props: any) => void }) {
|
|
8
|
-
const { type, collider = 'hull' } = component.properties;
|
|
8
|
+
function PhysicsComponentEditor({ component, onUpdate }: { component: { properties: { type?: 'dynamic' | 'fixed'; collider?: string;[k: string]: any } }; onUpdate: (props: Partial<Record<string, any>>) => void }) {
|
|
9
|
+
const { type = 'dynamic', collider = 'hull' } = component.properties;
|
|
9
10
|
return (
|
|
10
11
|
<div>
|
|
11
12
|
<label className={labelClass}>Type</label>
|
|
@@ -26,9 +27,9 @@ function PhysicsComponentEditor({ component, onUpdate }: { component: any; onUpd
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
interface PhysicsViewProps {
|
|
29
|
-
properties: { type
|
|
30
|
+
properties: { type?: 'dynamic' | 'fixed'; collider?: string };
|
|
30
31
|
editMode?: boolean;
|
|
31
|
-
children?:
|
|
32
|
+
children?: ReactNode;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
function PhysicsComponentView({ properties, editMode, children }: PhysicsViewProps) {
|
|
@@ -36,8 +37,11 @@ function PhysicsComponentView({ properties, editMode, children }: PhysicsViewPro
|
|
|
36
37
|
|
|
37
38
|
const colliders = properties.collider || (properties.type === 'fixed' ? 'trimesh' : 'hull');
|
|
38
39
|
|
|
40
|
+
// Remount RigidBody when collider/type changes to avoid Rapier hook dependency warnings
|
|
41
|
+
const rbKey = `${properties.type || 'dynamic'}_${colliders}`;
|
|
42
|
+
|
|
39
43
|
return (
|
|
40
|
-
<RigidBody type={properties.type} colliders={colliders as any}>
|
|
44
|
+
<RigidBody key={rbKey} type={properties.type} colliders={colliders as any}>
|
|
41
45
|
{children}
|
|
42
46
|
</RigidBody>
|
|
43
47
|
);
|