react-three-game 0.0.64 → 0.0.66
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/LICENSE +2 -660
- package/README.md +164 -91
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/tools/assetviewer/page.js +6 -6
- package/dist/tools/prefabeditor/EditorContext.d.ts +2 -2
- package/dist/tools/prefabeditor/EditorTree.js +17 -3
- package/dist/tools/prefabeditor/EditorTreeMenus.d.ts +3 -1
- package/dist/tools/prefabeditor/EditorTreeMenus.js +7 -8
- package/dist/tools/prefabeditor/EditorUI.js +3 -7
- package/dist/tools/prefabeditor/GameEvents.d.ts +14 -1
- package/dist/tools/prefabeditor/GameEvents.js +2 -1
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +14 -0
- package/dist/tools/prefabeditor/InstanceProvider.js +198 -34
- package/dist/tools/prefabeditor/PrefabEditor.js +77 -16
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +3 -1
- package/dist/tools/prefabeditor/PrefabRoot.js +88 -120
- package/dist/tools/prefabeditor/components/CameraComponent.js +1 -1
- package/dist/tools/prefabeditor/components/ClickComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/ClickComponent.js +45 -0
- package/dist/tools/prefabeditor/components/ComponentRegistry.js +0 -3
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +3 -3
- package/dist/tools/prefabeditor/components/Input.d.ts +5 -2
- package/dist/tools/prefabeditor/components/Input.js +71 -38
- package/dist/tools/prefabeditor/components/MaterialComponent.js +3 -3
- package/dist/tools/prefabeditor/components/ModelComponent.js +95 -16
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +2 -0
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +77 -10
- package/dist/tools/prefabeditor/components/index.js +2 -0
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/utils.d.ts +7 -1
- package/dist/tools/prefabeditor/utils.js +40 -2
- package/package.json +1 -1
|
@@ -8,25 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
import {
|
|
12
|
-
import { forwardRef, useCallback,
|
|
13
|
-
import { BoxHelper, Euler, Matrix4, Quaternion,
|
|
14
|
-
import { getComponent, registerComponent
|
|
11
|
+
import { useHelper } from "@react-three/drei";
|
|
12
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
13
|
+
import { BoxHelper, Euler, Matrix4, Quaternion, Vector3, } from "three";
|
|
14
|
+
import { getComponent, registerComponent } from "./components/ComponentRegistry";
|
|
15
15
|
import components from "./components";
|
|
16
|
-
import { loadModel } from "../dragdrop";
|
|
17
|
-
import { GameInstance, GameInstanceProvider, useInstanceCheck } from "./InstanceProvider";
|
|
18
|
-
import {
|
|
19
|
-
import { EditorContext } from "./EditorContext";
|
|
16
|
+
import { loadModel, loadTexture } from "../dragdrop";
|
|
17
|
+
import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, useInstanceCheck } from "./InstanceProvider";
|
|
18
|
+
import { decompose } from "./utils";
|
|
20
19
|
components.forEach(registerComponent);
|
|
21
20
|
const IDENTITY = new Matrix4();
|
|
22
|
-
export const PrefabRoot = forwardRef(({ editMode, data,
|
|
23
|
-
var _a, _b, _c, _d;
|
|
24
|
-
// optional editor context
|
|
25
|
-
const editorContext = useContext(EditorContext);
|
|
26
|
-
const transformMode = (_a = editorContext === null || editorContext === void 0 ? void 0 : editorContext.transformMode) !== null && _a !== void 0 ? _a : "translate";
|
|
27
|
-
const snapResolution = (_b = editorContext === null || editorContext === void 0 ? void 0 : editorContext.snapResolution) !== null && _b !== void 0 ? _b : 0;
|
|
28
|
-
const positionSnap = (_c = editorContext === null || editorContext === void 0 ? void 0 : editorContext.positionSnap) !== null && _c !== void 0 ? _c : 0.5;
|
|
29
|
-
const rotationSnap = (_d = editorContext === null || editorContext === void 0 ? void 0 : editorContext.rotationSnap) !== null && _d !== void 0 ? _d : Math.PI / 4;
|
|
21
|
+
export const PrefabRoot = forwardRef(({ editMode, data, selectedId, onSelect, onClick, onSelectedObjectChange, onFocusNode, basePath = "", injectedModels = {}, injectedTextures = {} }, ref) => {
|
|
30
22
|
// prefab root state
|
|
31
23
|
const [models, setModels] = useState({});
|
|
32
24
|
const [textures, setTextures] = useState({});
|
|
@@ -34,28 +26,21 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
34
26
|
const failedTextures = useRef(new Set());
|
|
35
27
|
const objectRefs = useRef({});
|
|
36
28
|
const rigidBodyRefs = useRef(new Map());
|
|
37
|
-
const [selectedObject, setSelectedObject] = useState(null);
|
|
38
29
|
const rootRef = useRef(null);
|
|
39
|
-
const controlsRef = useRef(null);
|
|
40
30
|
const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
|
|
41
31
|
const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
|
|
42
32
|
useImperativeHandle(ref, () => ({
|
|
43
33
|
root: rootRef.current,
|
|
44
34
|
rigidBodyRefs: rigidBodyRefs.current,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const camera = controls === null || controls === void 0 ? void 0 : controls.object;
|
|
49
|
-
if (!object || !controls || !camera)
|
|
50
|
-
return;
|
|
51
|
-
focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
|
|
52
|
-
}
|
|
53
|
-
}), []);
|
|
35
|
+
getObject: (nodeId) => { var _a; return (_a = objectRefs.current[nodeId]) !== null && _a !== void 0 ? _a : null; },
|
|
36
|
+
focusNode: (nodeId) => onFocusNode === null || onFocusNode === void 0 ? void 0 : onFocusNode(nodeId),
|
|
37
|
+
}), [onFocusNode]);
|
|
54
38
|
const registerRef = useCallback((id, obj) => {
|
|
55
39
|
objectRefs.current[id] = obj;
|
|
56
|
-
if (id === selectedId)
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
if (id === selectedId) {
|
|
41
|
+
onSelectedObjectChange === null || onSelectedObjectChange === void 0 ? void 0 : onSelectedObjectChange(obj);
|
|
42
|
+
}
|
|
43
|
+
}, [onSelectedObjectChange, selectedId]);
|
|
59
44
|
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
60
45
|
rigidBodyRefs.current.set(id, rb);
|
|
61
46
|
}, []);
|
|
@@ -68,25 +53,6 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
68
53
|
};
|
|
69
54
|
return () => { console.error = originalError; };
|
|
70
55
|
}, []);
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
var _a;
|
|
73
|
-
setSelectedObject(selectedId ? (_a = objectRefs.current[selectedId]) !== null && _a !== void 0 ? _a : null : null);
|
|
74
|
-
}, [selectedId]);
|
|
75
|
-
const onTransformChange = () => {
|
|
76
|
-
if (!selectedId || !onPrefabChange)
|
|
77
|
-
return;
|
|
78
|
-
const obj = objectRefs.current[selectedId];
|
|
79
|
-
if (!obj)
|
|
80
|
-
return;
|
|
81
|
-
const parentWorld = computeParentWorldMatrix(data.root, selectedId);
|
|
82
|
-
const local = parentWorld.clone().invert().multiply(obj.matrixWorld);
|
|
83
|
-
const { position, rotation, scale } = decompose(local);
|
|
84
|
-
const root = updateNode(data.root, selectedId, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { transform: {
|
|
85
|
-
type: "Transform",
|
|
86
|
-
properties: { position, rotation, scale },
|
|
87
|
-
} }) })));
|
|
88
|
-
onPrefabChange(Object.assign(Object.assign({}, data), { root }));
|
|
89
|
-
};
|
|
90
56
|
useEffect(() => {
|
|
91
57
|
const modelsToLoad = new Set();
|
|
92
58
|
const texturesToLoad = new Set();
|
|
@@ -112,7 +78,6 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
112
78
|
setModels(m => (Object.assign(Object.assign({}, m), { [file]: model })));
|
|
113
79
|
}
|
|
114
80
|
}));
|
|
115
|
-
const loader = new TextureLoader();
|
|
116
81
|
texturesToLoad.forEach(file => {
|
|
117
82
|
if (availableTextures[file] || loading.current.has(file) || failedTextures.current.has(file))
|
|
118
83
|
return;
|
|
@@ -123,17 +88,18 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
123
88
|
: file.startsWith("/")
|
|
124
89
|
? `${basePath}${file}`
|
|
125
90
|
: `${basePath}/${file}`;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
91
|
+
void loadTexture(path).then(result => {
|
|
92
|
+
if (result.success && result.texture) {
|
|
93
|
+
setTextures(t => (Object.assign(Object.assign({}, t), { [file]: result.texture })));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
console.warn(`Failed to load texture: ${path}`, result.error);
|
|
131
97
|
loading.current.delete(file);
|
|
132
98
|
failedTextures.current.add(file);
|
|
133
99
|
});
|
|
134
100
|
});
|
|
135
101
|
}, [data, availableModels, availableTextures, basePath]);
|
|
136
|
-
return (
|
|
102
|
+
return (_jsx("group", { ref: rootRef, children: _jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, children: _jsx(GameObjectRenderer, { gameObject: data.root, selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: onClick, registerRef: registerRef, registerRigidBodyRef: registerRigidBodyRef, loadedModels: availableModels, loadedTextures: availableTextures, editMode: editMode, parentMatrix: IDENTITY }) }) }));
|
|
137
103
|
});
|
|
138
104
|
export function GameObjectRenderer(props) {
|
|
139
105
|
var _a, _b, _c;
|
|
@@ -159,16 +125,18 @@ export function GameObjectRenderer(props) {
|
|
|
159
125
|
: _jsx(StandardNode, Object.assign({}, props), key);
|
|
160
126
|
}
|
|
161
127
|
function isPhysicsProps(v) {
|
|
162
|
-
return (v === null || v === void 0 ? void 0 : v.type) === "fixed" || (v === null || v === void 0 ? void 0 : v.type) === "dynamic";
|
|
128
|
+
return (v === null || v === void 0 ? void 0 : v.type) === "fixed" || (v === null || v === void 0 ? void 0 : v.type) === "dynamic" || (v === null || v === void 0 ? void 0 : v.type) === "kinematicPosition" || (v === null || v === void 0 ? void 0 : v.type) === "kinematicVelocity";
|
|
163
129
|
}
|
|
164
130
|
function InstancedNode({ gameObject, parentMatrix = IDENTITY, editMode, registerRef, selectedId: _selectedId, onSelect, onClick }) {
|
|
165
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
166
|
-
const world = parentMatrix.clone().multiply(compose(gameObject));
|
|
167
|
-
const { position: worldPosition, rotation: worldRotation, scale: worldScale } = decompose(world);
|
|
131
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
168
132
|
const localTransform = getNodeTransformProps(gameObject);
|
|
169
|
-
const
|
|
170
|
-
|
|
133
|
+
const isLocked = Boolean(gameObject.locked);
|
|
134
|
+
const clickable = Object.values((_a = gameObject.components) !== null && _a !== void 0 ? _a : {}).some(component => (component === null || component === void 0 ? void 0 : component.type) === 'Click');
|
|
135
|
+
const physicsProps = isPhysicsProps((_c = (_b = gameObject.components) === null || _b === void 0 ? void 0 : _b.physics) === null || _c === void 0 ? void 0 : _c.properties)
|
|
136
|
+
? (_e = (_d = gameObject.components) === null || _d === void 0 ? void 0 : _d.physics) === null || _e === void 0 ? void 0 : _e.properties
|
|
171
137
|
: undefined;
|
|
138
|
+
const modelUrl = (_h = (_g = (_f = gameObject.components) === null || _f === void 0 ? void 0 : _f.model) === null || _g === void 0 ? void 0 : _g.properties) === null || _h === void 0 ? void 0 : _h.filename;
|
|
139
|
+
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physicsProps), [gameObject, modelUrl, parentMatrix, physicsProps]);
|
|
172
140
|
const groupRef = useRef(null);
|
|
173
141
|
const clickValid = useRef(false);
|
|
174
142
|
useEffect(() => {
|
|
@@ -177,24 +145,24 @@ function InstancedNode({ gameObject, parentMatrix = IDENTITY, editMode, register
|
|
|
177
145
|
return () => registerRef(gameObject.id, null);
|
|
178
146
|
}
|
|
179
147
|
}, [gameObject.id, registerRef, editMode]);
|
|
180
|
-
const modelUrl = (_g = (_f = (_e = gameObject.components) === null || _e === void 0 ? void 0 : _e.model) === null || _f === void 0 ? void 0 : _f.properties) === null || _g === void 0 ? void 0 : _g.filename;
|
|
181
148
|
if (editMode) {
|
|
182
|
-
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale, onPointerDown: (e) => { e.stopPropagation(); clickValid.current = true; }, onPointerMove: () => { clickValid.current = false; }, onPointerUp: (e) => {
|
|
149
|
+
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale, onPointerDown: isLocked ? undefined : (e) => { e.stopPropagation(); clickValid.current = true; }, onPointerMove: isLocked ? undefined : () => { clickValid.current = false; }, onPointerUp: isLocked ? undefined : (e) => {
|
|
183
150
|
if (clickValid.current) {
|
|
184
151
|
e.stopPropagation();
|
|
185
152
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(gameObject.id);
|
|
186
153
|
onClick === null || onClick === void 0 ? void 0 : onClick(e, gameObject);
|
|
187
154
|
}
|
|
188
155
|
clickValid.current = false;
|
|
189
|
-
}, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx(GameInstance, { id: gameObject.id, modelUrl: modelUrl, position:
|
|
156
|
+
}, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id)))] }));
|
|
190
157
|
}
|
|
191
|
-
return (_jsx(
|
|
158
|
+
return (_jsx(_Fragment, { children: instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id))) }));
|
|
192
159
|
}
|
|
193
160
|
function StandardNode({ gameObject, selectedId, onSelect, onClick, registerRef, registerRigidBodyRef, loadedModels, loadedTextures, editMode, parentMatrix = IDENTITY, }) {
|
|
194
161
|
var _a, _b, _c, _d, _e;
|
|
195
162
|
const groupRef = useRef(null);
|
|
196
163
|
const helperRef = useRef(null);
|
|
197
164
|
const clickValid = useRef(false);
|
|
165
|
+
const isLocked = Boolean(gameObject.locked);
|
|
198
166
|
const isSelected = selectedId === gameObject.id;
|
|
199
167
|
const stillInstanced = useInstanceCheck(gameObject.id);
|
|
200
168
|
useHelper(editMode && isSelected ? helperRef : null, BoxHelper, "cyan");
|
|
@@ -236,26 +204,22 @@ function StandardNode({ gameObject, selectedId, onSelect, onClick, registerRef,
|
|
|
236
204
|
loadedTextures,
|
|
237
205
|
editMode,
|
|
238
206
|
});
|
|
239
|
-
const inner = (_jsx("group", { onPointerDown: editMode ? onDown : undefined, onPointerMove: editMode ? () => (clickValid.current = false) : undefined, onPointerUp: editMode ? onUp : undefined, children: renderCompositionNode(gameObject, renderCtx, parentMatrix, childNodes) }));
|
|
207
|
+
const inner = (_jsx("group", { onPointerDown: editMode && !isLocked ? onDown : undefined, onPointerMove: editMode && !isLocked ? () => (clickValid.current = false) : undefined, onPointerUp: editMode && !isLocked ? onUp : undefined, children: renderCompositionNode(gameObject, renderCtx, parentMatrix, childNodes) }));
|
|
240
208
|
if (editMode) {
|
|
241
209
|
return (_jsxs(_Fragment, { children: [_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx("group", { ref: helperRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: gameObject.id, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey)) : null] }));
|
|
242
210
|
}
|
|
243
211
|
if (hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View)) {
|
|
244
212
|
return (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, editMode: editMode, nodeId: gameObject.id, registerRigidBodyRef: registerRigidBodyRef, children: inner }, physicsKey));
|
|
245
213
|
}
|
|
246
|
-
return (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale,
|
|
247
|
-
}
|
|
248
|
-
const CHILD_HOST_COMPONENT_TYPES = new Set(["Environment"]);
|
|
249
|
-
function isChildHostType(type) {
|
|
250
|
-
return CHILD_HOST_COMPONENT_TYPES.has(type);
|
|
214
|
+
return (_jsx("group", { ref: groupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }));
|
|
251
215
|
}
|
|
252
216
|
function getChildHostComponents(gameObject) {
|
|
253
217
|
var _a;
|
|
254
218
|
return Object.entries((_a = gameObject.components) !== null && _a !== void 0 ? _a : {}).flatMap(([key, comp]) => {
|
|
255
|
-
if (!(comp === null || comp === void 0 ? void 0 : comp.type)
|
|
219
|
+
if (!(comp === null || comp === void 0 ? void 0 : comp.type))
|
|
256
220
|
return [];
|
|
257
221
|
const def = getComponent(comp.type);
|
|
258
|
-
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
222
|
+
if (!(def === null || def === void 0 ? void 0 : def.View) || def.nonComposable)
|
|
259
223
|
return [];
|
|
260
224
|
return { key, View: def.View, properties: comp.properties };
|
|
261
225
|
});
|
|
@@ -276,16 +240,58 @@ function compose(node) {
|
|
|
276
240
|
const { position, rotation, scale } = getNodeTransformProps(node);
|
|
277
241
|
return new Matrix4().compose(new Vector3(...position), new Quaternion().setFromEuler(new Euler(...rotation)), new Vector3(...scale));
|
|
278
242
|
}
|
|
279
|
-
function
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const e = new Euler().setFromQuaternion(q);
|
|
243
|
+
function getModelRepeatSettings(node) {
|
|
244
|
+
var _a, _b, _c;
|
|
245
|
+
const properties = (_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.components) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.properties) !== null && _c !== void 0 ? _c : {};
|
|
283
246
|
return {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
scale: [s.x, s.y, s.z],
|
|
247
|
+
repeat: Boolean(properties.repeat),
|
|
248
|
+
repeatAxes: getRepeatAxesFromModelProperties(properties),
|
|
287
249
|
};
|
|
288
250
|
}
|
|
251
|
+
function buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physics) {
|
|
252
|
+
if (!modelUrl)
|
|
253
|
+
return [];
|
|
254
|
+
const transform = getNodeTransformProps(gameObject);
|
|
255
|
+
const repeat = getModelRepeatSettings(gameObject);
|
|
256
|
+
const counts = [1, 1, 1];
|
|
257
|
+
const offsets = [0, 0, 0];
|
|
258
|
+
if (repeat.repeat) {
|
|
259
|
+
for (const entry of repeat.repeatAxes) {
|
|
260
|
+
const axisIndex = entry.axis === 'x' ? 0 : entry.axis === 'y' ? 1 : 2;
|
|
261
|
+
counts[axisIndex] = entry.count;
|
|
262
|
+
offsets[axisIndex] = entry.offset;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const baseTranslation = new Matrix4().makeTranslation(transform.position[0], transform.position[1], transform.position[2]);
|
|
266
|
+
const baseRotation = new Matrix4().makeRotationFromEuler(new Euler(...transform.rotation));
|
|
267
|
+
const baseScale = new Matrix4().makeScale(transform.scale[0], transform.scale[1], transform.scale[2]);
|
|
268
|
+
const offsetMatrix = new Matrix4();
|
|
269
|
+
const worldMatrix = new Matrix4();
|
|
270
|
+
const instances = [];
|
|
271
|
+
for (let x = 0; x < counts[0]; x++) {
|
|
272
|
+
for (let y = 0; y < counts[1]; y++) {
|
|
273
|
+
for (let z = 0; z < counts[2]; z++) {
|
|
274
|
+
offsetMatrix.makeTranslation(x * offsets[0], y * offsets[1], z * offsets[2]);
|
|
275
|
+
worldMatrix.copy(parentMatrix)
|
|
276
|
+
.multiply(baseTranslation)
|
|
277
|
+
.multiply(baseRotation)
|
|
278
|
+
.multiply(offsetMatrix)
|
|
279
|
+
.multiply(baseScale);
|
|
280
|
+
const { position, rotation, scale } = decompose(worldMatrix);
|
|
281
|
+
const isBaseInstance = x === 0 && y === 0 && z === 0;
|
|
282
|
+
instances.push({
|
|
283
|
+
id: isBaseInstance ? gameObject.id : `${gameObject.id}__repeat_${x}_${y}_${z}`,
|
|
284
|
+
modelUrl,
|
|
285
|
+
position,
|
|
286
|
+
rotation,
|
|
287
|
+
scale,
|
|
288
|
+
physics,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return instances;
|
|
294
|
+
}
|
|
289
295
|
function getNodeTransformProps(node) {
|
|
290
296
|
var _a, _b, _c, _d, _e;
|
|
291
297
|
const t = (_b = (_a = node === null || node === void 0 ? void 0 : node.components) === null || _a === void 0 ? void 0 : _a.transform) === null || _b === void 0 ? void 0 : _b.properties;
|
|
@@ -295,20 +301,6 @@ function getNodeTransformProps(node) {
|
|
|
295
301
|
scale: (_e = t === null || t === void 0 ? void 0 : t.scale) !== null && _e !== void 0 ? _e : [1, 1, 1],
|
|
296
302
|
};
|
|
297
303
|
}
|
|
298
|
-
function computeParentWorldMatrix(root, targetId) {
|
|
299
|
-
let result = null;
|
|
300
|
-
const visit = (node, parent) => {
|
|
301
|
-
var _a;
|
|
302
|
-
if (node.id === targetId) {
|
|
303
|
-
result = parent.clone();
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
const world = parent.clone().multiply(compose(node));
|
|
307
|
-
(_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(c => !result && visit(c, world));
|
|
308
|
-
};
|
|
309
|
-
visit(root, IDENTITY);
|
|
310
|
-
return result !== null && result !== void 0 ? result : IDENTITY;
|
|
311
|
-
}
|
|
312
304
|
function renderCompositionSubtree(gameObject, ctx, parentMatrix = IDENTITY) {
|
|
313
305
|
if (!gameObject || gameObject.disabled)
|
|
314
306
|
return null;
|
|
@@ -323,9 +315,7 @@ function renderHostedChildren(gameObject, ctx, parentMatrix) {
|
|
|
323
315
|
}
|
|
324
316
|
function renderCompositionNode(gameObject, ctx, parentMatrix, childNodes) {
|
|
325
317
|
const ownContent = renderNodeOwnContent(gameObject, ctx, parentMatrix);
|
|
326
|
-
|
|
327
|
-
const subtree = _jsxs(_Fragment, { children: [ownContent, siblingContent, childNodes] });
|
|
328
|
-
return wrapWithChildHosts(gameObject, ctx, parentMatrix, subtree);
|
|
318
|
+
return wrapWithChildHosts(gameObject, ctx, parentMatrix, _jsxs(_Fragment, { children: [ownContent, childNodes] }));
|
|
329
319
|
}
|
|
330
320
|
function renderNodeOwnContent(gameObject, ctx, parentMatrix) {
|
|
331
321
|
var _a, _b, _c, _d;
|
|
@@ -361,28 +351,6 @@ function renderNodeOwnContent(gameObject, ctx, parentMatrix) {
|
|
|
361
351
|
}
|
|
362
352
|
return core;
|
|
363
353
|
}
|
|
364
|
-
function renderNodeSiblingComponents(gameObject, ctx, parentMatrix) {
|
|
365
|
-
var _a;
|
|
366
|
-
const contextProps = {
|
|
367
|
-
loadedModels: ctx.loadedModels,
|
|
368
|
-
loadedTextures: ctx.loadedTextures,
|
|
369
|
-
editMode: ctx.editMode,
|
|
370
|
-
isSelected: ctx.selectedId === gameObject.id,
|
|
371
|
-
nodeId: gameObject.id,
|
|
372
|
-
parentMatrix,
|
|
373
|
-
registerRef: ctx.registerRef,
|
|
374
|
-
};
|
|
375
|
-
return Object.entries((_a = gameObject.components) !== null && _a !== void 0 ? _a : {})
|
|
376
|
-
.filter(([key]) => !getNonComposableKeys().includes(key))
|
|
377
|
-
.flatMap(([key, comp]) => {
|
|
378
|
-
if (!(comp === null || comp === void 0 ? void 0 : comp.type) || isChildHostType(comp.type))
|
|
379
|
-
return [];
|
|
380
|
-
const def = getComponent(comp.type);
|
|
381
|
-
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
382
|
-
return [];
|
|
383
|
-
return _jsx(def.View, Object.assign({ properties: comp.properties }, contextProps), key);
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
354
|
function wrapWithChildHosts(gameObject, ctx, parentMatrix, subtree) {
|
|
387
355
|
const contextProps = {
|
|
388
356
|
loadedModels: ctx.loadedModels,
|
|
@@ -34,7 +34,7 @@ function CameraComponentView({ properties, editMode, isSelected }) {
|
|
|
34
34
|
cameraHelper.update();
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
-
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: (instance) => setCamera(instance), makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode && isSelected && cameraHelper && (_jsx("primitive", { object: cameraHelper })), editMode
|
|
37
|
+
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: (instance) => setCamera(instance), makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode && isSelected && cameraHelper && (_jsx("primitive", { object: cameraHelper })), editMode ? (_jsxs("group", { children: [_jsxs("mesh", { children: [_jsx("boxGeometry", { args: [0.3, 0.3, 0.5] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] }), _jsxs("mesh", { position: [0, 0, -0.25], rotation: [Math.PI / 2, 0, 0], children: [_jsx("coneGeometry", { args: [0.08, 0.16, 16] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] })] })) : null] }));
|
|
38
38
|
}
|
|
39
39
|
const CameraComponent = {
|
|
40
40
|
name: 'Camera',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { gameEvents } from '../GameEvents';
|
|
4
|
+
import { FieldGroup } from './Input';
|
|
5
|
+
function ClickComponentEditor() {
|
|
6
|
+
return (_jsx(FieldGroup, { children: _jsx("div", { style: { fontSize: 12, opacity: 0.8 }, children: "Emits a click game event in play mode when this entity is clicked." }) }));
|
|
7
|
+
}
|
|
8
|
+
function ClickComponentView({ children, editMode, nodeId }) {
|
|
9
|
+
const clickValid = useRef(false);
|
|
10
|
+
const emitClick = (event) => {
|
|
11
|
+
if (!nodeId)
|
|
12
|
+
return;
|
|
13
|
+
gameEvents.emit('click', {
|
|
14
|
+
sourceEntityId: nodeId,
|
|
15
|
+
point: [event.point.x, event.point.y, event.point.z],
|
|
16
|
+
button: event.button,
|
|
17
|
+
altKey: event.nativeEvent.altKey,
|
|
18
|
+
ctrlKey: event.nativeEvent.ctrlKey,
|
|
19
|
+
metaKey: event.nativeEvent.metaKey,
|
|
20
|
+
shiftKey: event.nativeEvent.shiftKey,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
if (editMode) {
|
|
24
|
+
return _jsx(_Fragment, { children: children });
|
|
25
|
+
}
|
|
26
|
+
return (_jsx("group", { onPointerDown: (event) => {
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
clickValid.current = true;
|
|
29
|
+
}, onPointerMove: () => {
|
|
30
|
+
clickValid.current = false;
|
|
31
|
+
}, onPointerUp: (event) => {
|
|
32
|
+
if (!clickValid.current)
|
|
33
|
+
return;
|
|
34
|
+
event.stopPropagation();
|
|
35
|
+
emitClick(event);
|
|
36
|
+
clickValid.current = false;
|
|
37
|
+
}, children: children }));
|
|
38
|
+
}
|
|
39
|
+
const ClickComponent = {
|
|
40
|
+
name: 'Click',
|
|
41
|
+
Editor: ClickComponentEditor,
|
|
42
|
+
View: ClickComponentView,
|
|
43
|
+
defaultProperties: {},
|
|
44
|
+
};
|
|
45
|
+
export default ClickComponent;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const REGISTRY = {};
|
|
2
2
|
export function registerComponent(component) {
|
|
3
|
-
if (REGISTRY[component.name]) {
|
|
4
|
-
throw new Error(`Component with name ${component.name} already registered.`);
|
|
5
|
-
}
|
|
6
3
|
REGISTRY[component.name] = component;
|
|
7
4
|
}
|
|
8
5
|
export function getComponent(name) {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useRef, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { useFrame } from "@react-three/fiber";
|
|
4
4
|
import { CameraHelper, Vector3 } from "three";
|
|
5
|
-
import { FieldRenderer,
|
|
5
|
+
import { FieldRenderer, NumberInput } from "./Input";
|
|
6
6
|
const smallLabel = { display: 'block', fontSize: '8px', color: 'rgba(34, 211, 238, 0.5)', marginBottom: 2 };
|
|
7
7
|
const directionalLightDefaults = {
|
|
8
8
|
color: '#ffffff',
|
|
@@ -28,7 +28,7 @@ const directionalLightFields = [
|
|
|
28
28
|
label: 'Shadow Camera',
|
|
29
29
|
render: ({ values, onChangeMultiple }) => {
|
|
30
30
|
var _a, _b, _c, _d, _e, _f;
|
|
31
|
-
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Near" }), _jsx(
|
|
31
|
+
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Near" }), _jsx(NumberInput, { step: 0.1, value: (_a = values.shadowCameraNear) !== null && _a !== void 0 ? _a : 0.1, onChange: v => onChangeMultiple({ shadowCameraNear: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Far" }), _jsx(NumberInput, { step: 1, value: (_b = values.shadowCameraFar) !== null && _b !== void 0 ? _b : 100, onChange: v => onChangeMultiple({ shadowCameraFar: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Top" }), _jsx(NumberInput, { step: 1, value: (_c = values.shadowCameraTop) !== null && _c !== void 0 ? _c : 30, onChange: v => onChangeMultiple({ shadowCameraTop: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Bottom" }), _jsx(NumberInput, { step: 1, value: (_d = values.shadowCameraBottom) !== null && _d !== void 0 ? _d : -30, onChange: v => onChangeMultiple({ shadowCameraBottom: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Left" }), _jsx(NumberInput, { step: 1, value: (_e = values.shadowCameraLeft) !== null && _e !== void 0 ? _e : -30, onChange: v => onChangeMultiple({ shadowCameraLeft: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Right" }), _jsx(NumberInput, { step: 1, value: (_f = values.shadowCameraRight) !== null && _f !== void 0 ? _f : 30, onChange: v => onChangeMultiple({ shadowCameraRight: v }) })] })] }));
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -37,7 +37,7 @@ const directionalLightFields = [
|
|
|
37
37
|
label: 'Target Offset',
|
|
38
38
|
render: ({ value, onChange }) => {
|
|
39
39
|
const offset = value !== null && value !== void 0 ? value : [0, -5, 0];
|
|
40
|
-
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "X" }), _jsx(
|
|
40
|
+
return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "X" }), _jsx(NumberInput, { step: 0.5, value: offset[0], onChange: v => onChange([v, offset[1], offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Y" }), _jsx(NumberInput, { step: 0.5, value: offset[1], onChange: v => onChange([offset[0], v, offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Z" }), _jsx(NumberInput, { step: 0.5, value: offset[2], onChange: v => onChange([offset[0], offset[1], v]) })] })] }));
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
];
|
|
@@ -52,12 +52,15 @@ interface InputProps {
|
|
|
52
52
|
min?: number;
|
|
53
53
|
max?: number;
|
|
54
54
|
style?: React.CSSProperties;
|
|
55
|
-
label?: string;
|
|
56
55
|
}
|
|
57
|
-
export declare function
|
|
56
|
+
export declare function NumberInput({ value, onChange, step, min, max, style }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
58
57
|
export declare function Label({ children }: {
|
|
59
58
|
children: React.ReactNode;
|
|
60
59
|
}): import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export declare function FieldRow({ label, children, }: {
|
|
61
|
+
label: string;
|
|
62
|
+
children: React.ReactNode;
|
|
63
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
61
64
|
export declare function Vector3Input({ label, value, onChange, snap, labelExtra }: {
|
|
62
65
|
label: string;
|
|
63
66
|
value: [number, number, number];
|