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 (physics && !editMode) {
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
- return (_jsx(RigidBody, { type: properties.type, colliders: colliders, children: children }));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-three-game",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "description": "Batteries included React Three Fiber game engine",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -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
- if (physics && !editMode) {
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: 'dynamic' | 'fixed'; collider?: string };
30
+ properties: { type?: 'dynamic' | 'fixed'; collider?: string };
30
31
  editMode?: boolean;
31
- children?: React.ReactNode;
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
  );