react-three-game 0.0.13 → 0.0.15
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 +9 -11
- package/assets/favicon.ico +0 -0
- package/assets/react-three-game-logo.png +0 -0
- package/dist/helpers/index.d.ts +35 -0
- package/dist/helpers/index.js +44 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/shared/GameCanvas.js +13 -13
- package/dist/tools/prefabeditor/EditorTree.js +0 -2
- package/dist/tools/prefabeditor/PrefabEditor.js +0 -2
- package/dist/tools/prefabeditor/PrefabRoot.js +12 -24
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +1 -1
- package/dist/tools/prefabeditor/types.d.ts +2 -2
- package/package.json +4 -1
- package/src/helpers/index.ts +95 -0
- package/src/index.ts +3 -0
- package/src/shared/GameCanvas.tsx +5 -2
- package/src/tools/prefabeditor/EditorTree.tsx +0 -2
- package/src/tools/prefabeditor/PrefabEditor.tsx +0 -2
- package/src/tools/prefabeditor/PrefabRoot.tsx +4 -23
- package/src/tools/prefabeditor/components/PhysicsComponent.tsx +1 -7
- package/src/tools/prefabeditor/components/SpotLightComponent.tsx +0 -2
- package/src/tools/prefabeditor/types.ts +2 -2
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ npm install react-three-game @react-three/fiber @react-three/rapier three
|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
```jsx
|
|
67
|
-
import { GameCanvas, PrefabRoot } from 'react-three-game';
|
|
67
|
+
import { GameCanvas, PrefabRoot, ground } from 'react-three-game';
|
|
68
68
|
|
|
69
69
|
export default function App() {
|
|
70
70
|
return (
|
|
@@ -78,15 +78,13 @@ export default function App() {
|
|
|
78
78
|
transform: { type: "Transform", properties: { position: [0, 0, 0] } }
|
|
79
79
|
},
|
|
80
80
|
children: [
|
|
81
|
-
{
|
|
81
|
+
ground({
|
|
82
82
|
id: "floor",
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
},
|
|
83
|
+
position: [0, -1, 0],
|
|
84
|
+
size: 50,
|
|
85
|
+
texture: "/textures/GreyboxTextures/greybox_light_grid.png",
|
|
86
|
+
repeatCount: [25, 25]
|
|
87
|
+
}),
|
|
90
88
|
{
|
|
91
89
|
id: "player",
|
|
92
90
|
components: {
|
|
@@ -109,8 +107,8 @@ export default function App() {
|
|
|
109
107
|
```typescript
|
|
110
108
|
interface GameObject {
|
|
111
109
|
id: string;
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
hidden?: boolean;
|
|
114
112
|
components: {
|
|
115
113
|
transform?: TransformComponent;
|
|
116
114
|
geometry?: GeometryComponent;
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { GameObject } from "../tools/prefabeditor/types";
|
|
2
|
+
export type Vec3 = [number, number, number];
|
|
3
|
+
export interface GroundOptions {
|
|
4
|
+
/** GameObject id. Defaults to "ground". */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Plane size. Defaults to 50. */
|
|
7
|
+
size?: number;
|
|
8
|
+
/** Transform overrides. */
|
|
9
|
+
position?: Vec3;
|
|
10
|
+
rotation?: Vec3;
|
|
11
|
+
scale?: Vec3;
|
|
12
|
+
/** Material overrides. */
|
|
13
|
+
color?: string;
|
|
14
|
+
texture?: string;
|
|
15
|
+
/** When true, set repeat wrapping. Defaults to true if texture is provided. */
|
|
16
|
+
repeat?: boolean;
|
|
17
|
+
/** Texture repeat counts when repeat=true. Defaults to [25,25]. */
|
|
18
|
+
repeatCount?: [number, number];
|
|
19
|
+
/** Physics body type. Defaults to "fixed". */
|
|
20
|
+
physicsType?: "fixed" | "dynamic" | "kinematic";
|
|
21
|
+
/** Set true to hide the node. */
|
|
22
|
+
hidden?: boolean;
|
|
23
|
+
/** Set true to disable the node. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a ready-to-use plane ground GameObject.
|
|
28
|
+
*
|
|
29
|
+
* Designed to reduce prefab boilerplate:
|
|
30
|
+
* - Transform (rotated to lie flat)
|
|
31
|
+
* - Geometry (plane)
|
|
32
|
+
* - Material (optional texture + repeat)
|
|
33
|
+
* - Physics (fixed by default)
|
|
34
|
+
*/
|
|
35
|
+
export declare function ground(options?: GroundOptions): GameObject;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a ready-to-use plane ground GameObject.
|
|
3
|
+
*
|
|
4
|
+
* Designed to reduce prefab boilerplate:
|
|
5
|
+
* - Transform (rotated to lie flat)
|
|
6
|
+
* - Geometry (plane)
|
|
7
|
+
* - Material (optional texture + repeat)
|
|
8
|
+
* - Physics (fixed by default)
|
|
9
|
+
*/
|
|
10
|
+
export function ground(options = {}) {
|
|
11
|
+
const { id = "ground", size = 50, position = [0, 0, 0], rotation = [-Math.PI / 2, 0, 0], scale = [1, 1, 1], color = "white", texture, repeat = texture ? true : false, repeatCount = [25, 25], physicsType = "fixed", hidden = false, disabled = false, } = options;
|
|
12
|
+
return {
|
|
13
|
+
id,
|
|
14
|
+
disabled,
|
|
15
|
+
hidden,
|
|
16
|
+
components: {
|
|
17
|
+
transform: {
|
|
18
|
+
type: "Transform",
|
|
19
|
+
properties: {
|
|
20
|
+
position,
|
|
21
|
+
rotation,
|
|
22
|
+
scale,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
geometry: {
|
|
26
|
+
type: "Geometry",
|
|
27
|
+
properties: {
|
|
28
|
+
geometryType: "plane",
|
|
29
|
+
args: [size, size],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
material: {
|
|
33
|
+
type: "Material",
|
|
34
|
+
properties: Object.assign(Object.assign({ color }, (texture ? { texture } : {})), (repeat ? { repeat: true, repeatCount } : {})),
|
|
35
|
+
},
|
|
36
|
+
physics: {
|
|
37
|
+
type: "Physics",
|
|
38
|
+
properties: {
|
|
39
|
+
type: physicsType,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
|
|
|
3
3
|
export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
|
|
4
4
|
export { DragDropLoader } from './tools/dragdrop/DragDropLoader';
|
|
5
5
|
export { TextureListViewer, ModelListViewer, SoundListViewer, SharedCanvas, } from './tools/assetviewer/page';
|
|
6
|
+
export * from './helpers';
|
|
6
7
|
export type { Prefab, GameObject } from './tools/prefabeditor/types';
|
package/dist/index.js
CHANGED
|
@@ -4,3 +4,5 @@ export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
|
|
|
4
4
|
export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
|
|
5
5
|
export { DragDropLoader } from './tools/dragdrop/DragDropLoader';
|
|
6
6
|
export { TextureListViewer, ModelListViewer, SoundListViewer, SharedCanvas, } from './tools/assetviewer/page';
|
|
7
|
+
// Helpers
|
|
8
|
+
export * from './helpers';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -18,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
18
19
|
}
|
|
19
20
|
return t;
|
|
20
21
|
};
|
|
21
|
-
import { jsx as _jsx,
|
|
22
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
22
23
|
import { Canvas, extend } from "@react-three/fiber";
|
|
23
24
|
import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
|
|
24
25
|
import { Suspense, useState } from "react";
|
|
@@ -33,16 +34,15 @@ extend({
|
|
|
33
34
|
export default function GameCanvas(_a) {
|
|
34
35
|
var { loader = false, children } = _a, props = __rest(_a, ["loader", "children"]);
|
|
35
36
|
const [frameloop, setFrameloop] = useState("never");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}, children: _jsx(Suspense, { children: children }) }), loader ? _jsx(Loader, {}) : null] });
|
|
37
|
+
return _jsx(_Fragment, { children: _jsxs(Canvas, { style: { touchAction: 'none' }, shadows: { type: PCFShadowMap, }, frameloop: frameloop, gl: (_a) => __awaiter(this, [_a], void 0, function* ({ canvas }) {
|
|
38
|
+
const renderer = new WebGPURenderer(Object.assign({ canvas: canvas,
|
|
39
|
+
// @ts-expect-error futuristic
|
|
40
|
+
shadowMap: true, antialias: true }, props));
|
|
41
|
+
yield renderer.init().then(() => {
|
|
42
|
+
setFrameloop("always");
|
|
43
|
+
});
|
|
44
|
+
return renderer;
|
|
45
|
+
}), camera: {
|
|
46
|
+
position: [0, 1, 5],
|
|
47
|
+
}, children: [_jsx(Suspense, { children: children }), loader ? _jsx(Loader, {}) : null] }) });
|
|
48
48
|
}
|
|
@@ -49,13 +49,6 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
49
49
|
setSelectedObject(null);
|
|
50
50
|
}
|
|
51
51
|
}, [selectedId]);
|
|
52
|
-
// const [transformMode, setTransformMode] = useState<"translate" | "rotate" | "scale">("translate"); // Removed local state
|
|
53
|
-
const updateNode = (updater) => {
|
|
54
|
-
if (!selectedId || !onPrefabChange)
|
|
55
|
-
return;
|
|
56
|
-
const newRoot = updatePrefabNode(data.root, selectedId, updater);
|
|
57
|
-
onPrefabChange(Object.assign(Object.assign({}, data), { root: newRoot }));
|
|
58
|
-
};
|
|
59
52
|
const onTransformChange = () => {
|
|
60
53
|
if (!selectedId || !onPrefabChange)
|
|
61
54
|
return;
|
|
@@ -75,17 +68,14 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
75
68
|
localMatrix.decompose(lp, lq, ls);
|
|
76
69
|
const le = new Euler().setFromQuaternion(lq);
|
|
77
70
|
// 4. Write back LOCAL transform into the prefab node
|
|
78
|
-
const newRoot = updatePrefabNode(data.root, selectedId, (node) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
}, geometry: (_a = node.components) === null || _a === void 0 ? void 0 : _a.geometry, material: (_b = node.components) === null || _b === void 0 ? void 0 : _b.material, model: (_c = node.components) === null || _c === void 0 ? void 0 : _c.model }) }));
|
|
88
|
-
});
|
|
71
|
+
const newRoot = updatePrefabNode(data.root, selectedId, (node) => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node === null || node === void 0 ? void 0 : node.components), { transform: {
|
|
72
|
+
type: "Transform",
|
|
73
|
+
properties: {
|
|
74
|
+
position: [lp.x, lp.y, lp.z],
|
|
75
|
+
rotation: [le.x, le.y, le.z],
|
|
76
|
+
scale: [ls.x, ls.y, ls.z],
|
|
77
|
+
},
|
|
78
|
+
} }) })));
|
|
89
79
|
onPrefabChange(Object.assign(Object.assign({}, data), { root: newRoot }));
|
|
90
80
|
};
|
|
91
81
|
useEffect(() => {
|
|
@@ -161,7 +151,7 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
|
|
|
161
151
|
}
|
|
162
152
|
clickValid.current = false;
|
|
163
153
|
};
|
|
164
|
-
if (
|
|
154
|
+
if (gameObject.disabled === true || gameObject.hidden === true)
|
|
165
155
|
return null;
|
|
166
156
|
// --- 2. If instanced, short-circuit to a tiny clean branch ---
|
|
167
157
|
const isInstanced = !!((_c = (_b = (_a = gameObject.components) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c.instanced);
|
|
@@ -173,11 +163,9 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
|
|
|
173
163
|
// --- 5. Render children (always relative transforms) ---
|
|
174
164
|
const children = ((_d = gameObject.children) !== null && _d !== void 0 ? _d : []).map((child) => (_jsx(GameObjectRenderer, { gameObject: child, selectedId: selectedId, onSelect: onSelect, registerRef: registerRef, loadedModels: loadedModels, loadedTextures: loadedTextures, editMode: editMode, parentMatrix: worldMatrix }, child.id)));
|
|
175
165
|
// --- 4. Wrap with physics if needed ---
|
|
176
|
-
|
|
177
|
-
const content = (_jsxs(_Fragment, { children: [core, children] }));
|
|
178
|
-
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, content, ctx);
|
|
166
|
+
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
|
|
179
167
|
// --- 6. Final group wrapper ---
|
|
180
|
-
return (
|
|
168
|
+
return (_jsxs("group", { ref: (el) => registerRef(gameObject.id, el), position: transformProps.position, rotation: transformProps.rotation, scale: transformProps.scale, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, children: [physicsWrapped, children] }));
|
|
181
169
|
}
|
|
182
170
|
// Helper: render an instanced GameInstance (terminal node)
|
|
183
171
|
function renderInstancedNode(gameObject, worldMatrix, ctx) {
|
|
@@ -242,7 +230,7 @@ function wrapPhysicsIfNeeded(gameObject, content, ctx) {
|
|
|
242
230
|
const physicsDef = getComponent('Physics');
|
|
243
231
|
if (!physicsDef || !physicsDef.View)
|
|
244
232
|
return content;
|
|
245
|
-
return (_jsx(physicsDef.View, { properties: Object.assign(Object.assign({}, physics.properties), { id: gameObject.id }),
|
|
233
|
+
return (_jsx(physicsDef.View, { properties: Object.assign(Object.assign({}, physics.properties), { id: gameObject.id }), editMode: ctx.editMode, children: content }));
|
|
246
234
|
}
|
|
247
235
|
export default PrefabRoot;
|
|
248
236
|
function getNodeTransformProps(node) {
|
|
@@ -3,10 +3,10 @@ function PhysicsComponentEditor({ component, onUpdate }) {
|
|
|
3
3
|
return _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Type" }), _jsxs("select", { className: "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", value: component.properties.type, onChange: e => onUpdate({ type: e.target.value }), children: [_jsx("option", { value: "dynamic", children: "Dynamic" }), _jsx("option", { value: "fixed", children: "Fixed" })] })] });
|
|
4
4
|
}
|
|
5
5
|
import { RigidBody } from "@react-three/rapier";
|
|
6
|
-
function PhysicsComponentView({ properties, children,
|
|
6
|
+
function PhysicsComponentView({ properties, children, editMode }) {
|
|
7
7
|
if (editMode)
|
|
8
8
|
return children;
|
|
9
|
-
return (_jsx(RigidBody, {
|
|
9
|
+
return (_jsx(RigidBody, { type: properties.type, colliders: "cuboid", children: children }));
|
|
10
10
|
}
|
|
11
11
|
const PhysicsComponent = {
|
|
12
12
|
name: 'Physics',
|
|
@@ -22,7 +22,7 @@ function SpotLightView({ properties }) {
|
|
|
22
22
|
const penumbra = (_d = properties.penumbra) !== null && _d !== void 0 ? _d : 0.5;
|
|
23
23
|
const distance = (_e = properties.distance) !== null && _e !== void 0 ? _e : 100;
|
|
24
24
|
const castShadow = (_f = properties.castShadow) !== null && _f !== void 0 ? _f : true;
|
|
25
|
-
return (_jsx(_Fragment, { children: _jsx("spotLight", { color: color, intensity: intensity, angle: angle, penumbra: penumbra, distance: distance, castShadow: castShadow
|
|
25
|
+
return (_jsx(_Fragment, { children: _jsx("spotLight", { color: color, intensity: intensity, angle: angle, penumbra: penumbra, distance: distance, castShadow: castShadow }) }));
|
|
26
26
|
}
|
|
27
27
|
const SpotLightComponent = {
|
|
28
28
|
name: 'SpotLight',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-three-game",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Batteries included React Three Fiber game engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -15,8 +15,11 @@
|
|
|
15
15
|
"author": "prnth",
|
|
16
16
|
"license": "VPL",
|
|
17
17
|
"type": "module",
|
|
18
|
+
"workspaces": ["docs"],
|
|
18
19
|
"peerDependencies": {
|
|
19
20
|
"@react-three/fiber": "^9.0.0",
|
|
21
|
+
"@react-three/drei": "^10.0.0",
|
|
22
|
+
"@react-three/rapier": "^2.0.0",
|
|
20
23
|
"react": "^18.0.0 || ^19.0.0",
|
|
21
24
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
22
25
|
"three": "^0.181.0"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { GameObject } from "../tools/prefabeditor/types";
|
|
2
|
+
|
|
3
|
+
export type Vec3 = [number, number, number];
|
|
4
|
+
|
|
5
|
+
export interface GroundOptions {
|
|
6
|
+
/** GameObject id. Defaults to "ground". */
|
|
7
|
+
id?: string;
|
|
8
|
+
|
|
9
|
+
/** Plane size. Defaults to 50. */
|
|
10
|
+
size?: number;
|
|
11
|
+
|
|
12
|
+
/** Transform overrides. */
|
|
13
|
+
position?: Vec3;
|
|
14
|
+
rotation?: Vec3;
|
|
15
|
+
scale?: Vec3;
|
|
16
|
+
|
|
17
|
+
/** Material overrides. */
|
|
18
|
+
color?: string;
|
|
19
|
+
texture?: string;
|
|
20
|
+
/** When true, set repeat wrapping. Defaults to true if texture is provided. */
|
|
21
|
+
repeat?: boolean;
|
|
22
|
+
/** Texture repeat counts when repeat=true. Defaults to [25,25]. */
|
|
23
|
+
repeatCount?: [number, number];
|
|
24
|
+
|
|
25
|
+
/** Physics body type. Defaults to "fixed". */
|
|
26
|
+
physicsType?: "fixed" | "dynamic" | "kinematic";
|
|
27
|
+
|
|
28
|
+
/** Set true to hide the node. */
|
|
29
|
+
hidden?: boolean;
|
|
30
|
+
/** Set true to disable the node. */
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a ready-to-use plane ground GameObject.
|
|
36
|
+
*
|
|
37
|
+
* Designed to reduce prefab boilerplate:
|
|
38
|
+
* - Transform (rotated to lie flat)
|
|
39
|
+
* - Geometry (plane)
|
|
40
|
+
* - Material (optional texture + repeat)
|
|
41
|
+
* - Physics (fixed by default)
|
|
42
|
+
*/
|
|
43
|
+
export function ground(options: GroundOptions = {}): GameObject {
|
|
44
|
+
const {
|
|
45
|
+
id = "ground",
|
|
46
|
+
size = 50,
|
|
47
|
+
position = [0, 0, 0],
|
|
48
|
+
rotation = [-Math.PI / 2, 0, 0],
|
|
49
|
+
scale = [1, 1, 1],
|
|
50
|
+
color = "white",
|
|
51
|
+
texture,
|
|
52
|
+
repeat = texture ? true : false,
|
|
53
|
+
repeatCount = [25, 25],
|
|
54
|
+
physicsType = "fixed",
|
|
55
|
+
hidden = false,
|
|
56
|
+
disabled = false,
|
|
57
|
+
} = options;
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
id,
|
|
61
|
+
disabled,
|
|
62
|
+
hidden,
|
|
63
|
+
components: {
|
|
64
|
+
transform: {
|
|
65
|
+
type: "Transform",
|
|
66
|
+
properties: {
|
|
67
|
+
position,
|
|
68
|
+
rotation,
|
|
69
|
+
scale,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
geometry: {
|
|
73
|
+
type: "Geometry",
|
|
74
|
+
properties: {
|
|
75
|
+
geometryType: "plane",
|
|
76
|
+
args: [size, size],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
material: {
|
|
80
|
+
type: "Material",
|
|
81
|
+
properties: {
|
|
82
|
+
color,
|
|
83
|
+
...(texture ? { texture } : {}),
|
|
84
|
+
...(repeat ? { repeat: true, repeatCount } : {}),
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
physics: {
|
|
88
|
+
type: "Physics",
|
|
89
|
+
properties: {
|
|
90
|
+
type: physicsType,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { Canvas, extend } from "@react-three/fiber";
|
|
2
4
|
import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
|
|
3
5
|
import { Suspense, useState } from "react";
|
|
@@ -16,10 +18,10 @@ extend({
|
|
|
16
18
|
|
|
17
19
|
export default function GameCanvas({ loader = false, children, ...props }: { loader?: boolean, children: React.ReactNode, props?: WebGPURendererParameters }) {
|
|
18
20
|
const [frameloop, setFrameloop] = useState<"never" | "always">("never");
|
|
19
|
-
const [loading, setLoading] = useState(true);
|
|
20
21
|
|
|
21
22
|
return <>
|
|
22
23
|
<Canvas
|
|
24
|
+
style={{ touchAction: 'none' }}
|
|
23
25
|
shadows={{ type: PCFShadowMap, }}
|
|
24
26
|
frameloop={frameloop}
|
|
25
27
|
gl={async ({ canvas }) => {
|
|
@@ -42,7 +44,8 @@ export default function GameCanvas({ loader = false, children, ...props }: { loa
|
|
|
42
44
|
<Suspense>
|
|
43
45
|
{children}
|
|
44
46
|
</Suspense>
|
|
47
|
+
|
|
48
|
+
{loader ? <Loader /> : null}
|
|
45
49
|
</Canvas>
|
|
46
|
-
{loader ? <Loader /> : null}
|
|
47
50
|
</>;
|
|
48
51
|
}
|
|
@@ -39,8 +39,6 @@ export default function EditorTree({ prefabData, setPrefabData, selectedId, setS
|
|
|
39
39
|
const handleAddChild = (parentId: string) => {
|
|
40
40
|
const newNode: GameObject = {
|
|
41
41
|
id: crypto.randomUUID(),
|
|
42
|
-
enabled: true,
|
|
43
|
-
visible: true,
|
|
44
42
|
components: {
|
|
45
43
|
transform: {
|
|
46
44
|
type: "Transform",
|
|
@@ -59,15 +59,6 @@ export const PrefabRoot = forwardRef<Group, {
|
|
|
59
59
|
}
|
|
60
60
|
}, [selectedId]);
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
// const [transformMode, setTransformMode] = useState<"translate" | "rotate" | "scale">("translate"); // Removed local state
|
|
64
|
-
|
|
65
|
-
const updateNode = (updater: (node: GameObjectType) => GameObjectType) => {
|
|
66
|
-
if (!selectedId || !onPrefabChange) return;
|
|
67
|
-
const newRoot = updatePrefabNode(data.root, selectedId, updater);
|
|
68
|
-
onPrefabChange({ ...data, root: newRoot });
|
|
69
|
-
};
|
|
70
|
-
|
|
71
62
|
const onTransformChange = () => {
|
|
72
63
|
if (!selectedId || !onPrefabChange) return;
|
|
73
64
|
const obj = objectRefs.current[selectedId];
|
|
@@ -103,9 +94,6 @@ export const PrefabRoot = forwardRef<Group, {
|
|
|
103
94
|
scale: [ls.x, ls.y, ls.z] as [number, number, number],
|
|
104
95
|
},
|
|
105
96
|
},
|
|
106
|
-
geometry: node.components?.geometry,
|
|
107
|
-
material: node.components?.material,
|
|
108
|
-
model: node.components?.model,
|
|
109
97
|
},
|
|
110
98
|
}));
|
|
111
99
|
|
|
@@ -170,7 +158,7 @@ export const PrefabRoot = forwardRef<Group, {
|
|
|
170
158
|
loadedModels={loadedModels}
|
|
171
159
|
loadedTextures={loadedTextures}
|
|
172
160
|
editMode={editMode}
|
|
173
|
-
parentMatrix={new Matrix4()}
|
|
161
|
+
parentMatrix={new Matrix4()}
|
|
174
162
|
/>
|
|
175
163
|
</GameInstanceProvider>
|
|
176
164
|
|
|
@@ -245,7 +233,7 @@ function GameObjectRenderer({
|
|
|
245
233
|
clickValid.current = false;
|
|
246
234
|
};
|
|
247
235
|
|
|
248
|
-
if (
|
|
236
|
+
if (gameObject.disabled === true || gameObject.hidden === true) return null;
|
|
249
237
|
|
|
250
238
|
// --- 2. If instanced, short-circuit to a tiny clean branch ---
|
|
251
239
|
const isInstanced = !!gameObject.components?.model?.properties?.instanced;
|
|
@@ -272,14 +260,7 @@ function GameObjectRenderer({
|
|
|
272
260
|
));
|
|
273
261
|
|
|
274
262
|
// --- 4. Wrap with physics if needed ---
|
|
275
|
-
|
|
276
|
-
const content = (
|
|
277
|
-
<>
|
|
278
|
-
{core}
|
|
279
|
-
{children}
|
|
280
|
-
</>
|
|
281
|
-
);
|
|
282
|
-
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, content, ctx);
|
|
263
|
+
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
|
|
283
264
|
|
|
284
265
|
// --- 6. Final group wrapper ---
|
|
285
266
|
return (
|
|
@@ -293,6 +274,7 @@ function GameObjectRenderer({
|
|
|
293
274
|
onPointerUp={handlePointerUp}
|
|
294
275
|
>
|
|
295
276
|
{physicsWrapped}
|
|
277
|
+
{children}
|
|
296
278
|
</group>
|
|
297
279
|
);
|
|
298
280
|
}
|
|
@@ -404,7 +386,6 @@ function wrapPhysicsIfNeeded(gameObject: GameObjectType, content: React.ReactNod
|
|
|
404
386
|
return (
|
|
405
387
|
<physicsDef.View
|
|
406
388
|
properties={{ ...physics.properties, id: gameObject.id }}
|
|
407
|
-
registerRef={ctx.registerRef}
|
|
408
389
|
editMode={ctx.editMode}
|
|
409
390
|
>
|
|
410
391
|
{content}
|
|
@@ -16,17 +16,11 @@ function PhysicsComponentEditor({ component, onUpdate }: { component: any; onUpd
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import { RigidBody } from "@react-three/rapier";
|
|
19
|
-
import { Object3D } from "three";
|
|
20
|
-
import { useRef } from "react";
|
|
21
19
|
|
|
22
|
-
function PhysicsComponentView({ properties, children,
|
|
20
|
+
function PhysicsComponentView({ properties, children, editMode }: any) {
|
|
23
21
|
if (editMode) return children;
|
|
24
22
|
return (
|
|
25
23
|
<RigidBody
|
|
26
|
-
ref={el => registerRef && registerRef(properties.id, el as unknown as Object3D)}
|
|
27
|
-
position={transform?.position}
|
|
28
|
-
rotation={transform?.rotation}
|
|
29
|
-
scale={transform?.scale}
|
|
30
24
|
type={properties.type}
|
|
31
25
|
colliders="cuboid"
|
|
32
26
|
>
|