react-three-game 0.0.92 → 0.0.93
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 +68 -33
- package/dist/helpers/index.d.ts +0 -3
- package/dist/helpers/index.js +1 -8
- package/dist/index.d.ts +5 -8
- package/dist/index.js +3 -4
- package/dist/tools/prefabeditor/EditorTree.js +2 -2
- package/dist/tools/prefabeditor/GameEvents.d.ts +6 -12
- package/dist/tools/prefabeditor/GameEvents.js +0 -8
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +6 -4
- package/dist/tools/prefabeditor/InstanceProvider.js +84 -199
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +18 -6
- package/dist/tools/prefabeditor/PrefabEditor.js +55 -39
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +15 -8
- package/dist/tools/prefabeditor/PrefabRoot.js +141 -117
- package/dist/tools/prefabeditor/assetRuntime.d.ts +13 -11
- package/dist/tools/prefabeditor/assetRuntime.js +15 -15
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +1 -1
- package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +3 -3
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/ModelComponent.js +1 -1
- package/dist/tools/prefabeditor/components/PointLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SoundComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/index.js +0 -2
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/usePointerEvents.d.ts +3 -3
- package/dist/tools/prefabeditor/usePointerEvents.js +5 -5
- package/package.json +1 -3
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +0 -26
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +0 -302
- package/dist/tools/prefabeditor/scene.d.ts +0 -70
- package/dist/tools/prefabeditor/scene.js +0 -237
|
@@ -3,7 +3,7 @@ import { useHelper } from "@react-three/drei";
|
|
|
3
3
|
import { useRef, useEffect, useState } from "react";
|
|
4
4
|
import { useFrame } from "@react-three/fiber";
|
|
5
5
|
import { CameraHelper } from "three";
|
|
6
|
-
import {
|
|
6
|
+
import { useCurrentNode } from "../assetRuntime";
|
|
7
7
|
import { BooleanField, ColorField, NumberField, NumberInput, Vector3Input } from "./Input";
|
|
8
8
|
import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
|
|
9
9
|
import { colors } from "../styles";
|
|
@@ -102,7 +102,7 @@ function DirectionalLightComponentEditor({ component, onUpdate }) {
|
|
|
102
102
|
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(Vector3Input, { label: "Target Offset", value: values.targetOffset, onChange: targetOffset => onUpdate({ targetOffset }), snap: 0.5 })] }), _jsxs(LightSection, { title: "Shadow", children: [_jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: values, onChange: onUpdate, fallback: false }), values.castShadow ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "shadowAutoUpdate", label: "Auto Update", values: values, onChange: onUpdate, fallback: true }), _jsx(NumberField, { name: "shadowMapSize", label: "Map Size", values: values, onChange: onUpdate, min: 128, step: 128, fallback: 512 }), _jsx(ShadowBiasField, { name: "shadowBias", label: "Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(ShadowBiasField, { name: "shadowNormalBias", label: "Normal Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(NumberField, { name: "shadowCameraNear", label: "Near", values: values, onChange: onUpdate, min: 0.001, step: 0.1, fallback: 0.5 }), _jsx(NumberField, { name: "shadowCameraFar", label: "Far", values: values, onChange: onUpdate, min: 0.1, step: 1, fallback: 500 }), _jsx(ShadowFrustumField, { values: values, onChange: onUpdate })] })) : null] })] }));
|
|
103
103
|
}
|
|
104
104
|
function DirectionalLightView({ properties, children }) {
|
|
105
|
-
const { editMode, isSelected } =
|
|
105
|
+
const { editMode, isSelected } = useCurrentNode();
|
|
106
106
|
const merged = mergeWithDefaults(directionalLightDefaults, properties);
|
|
107
107
|
const color = merged.color;
|
|
108
108
|
const intensity = merged.intensity;
|
|
@@ -43,7 +43,7 @@ function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
|
|
|
43
43
|
const editorContext = useContext(EditorContext);
|
|
44
44
|
const positionSnap = (_a = editorContext === null || editorContext === void 0 ? void 0 : editorContext.positionSnap) !== null && _a !== void 0 ? _a : 0.5;
|
|
45
45
|
const repeatAxes = getRepeatAxesFromModelProperties(component.properties);
|
|
46
|
-
return (_jsxs(FieldGroup, { children: [_jsx(ModelPicker, { value: component.properties.filename, onChange: (filename) => onUpdate({ filename }), basePath: basePath, pickerKey: node === null || node === void 0 ? void 0 : node.id }), _jsx(BooleanField, { name: "instanced", label: "Instanced", values: component.properties, onChange: onUpdate, fallback: false }), !component.properties.instanced ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: component.properties, onChange: onUpdate, placeholder: "
|
|
46
|
+
return (_jsxs(FieldGroup, { children: [_jsx(ModelPicker, { value: component.properties.filename, onChange: (filename) => onUpdate({ filename }), basePath: basePath, pickerKey: node === null || node === void 0 ? void 0 : node.id }), _jsx(BooleanField, { name: "instanced", label: "Instanced", values: component.properties, onChange: onUpdate, fallback: false }), !component.properties.instanced ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: component.properties, onChange: onUpdate, placeholder: "node:click" })) : null] })) : null, component.properties.instanced && (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "repeat", label: "Repeat", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.repeat && (_jsx(RepeatAxisEditor, { axes: repeatAxes, onChange: (nextAxes) => onUpdate({ repeatAxes: nextAxes }), positionSnap: positionSnap }))] }))] }));
|
|
47
47
|
}
|
|
48
48
|
// View for Model component
|
|
49
49
|
function ModelComponentView({ properties, children }) {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
import { useHelper } from '@react-three/drei';
|
|
4
4
|
import { PointLightHelper } from 'three';
|
|
5
|
-
import {
|
|
5
|
+
import { useCurrentNode } from '../assetRuntime';
|
|
6
6
|
import { BooleanField, ColorField, NumberField } from './Input';
|
|
7
7
|
import { LightSection, ShadowBiasField, mergeWithDefaults } from './lightUtils';
|
|
8
8
|
const pointLightDefaults = {
|
|
@@ -23,7 +23,7 @@ function PointLightComponentEditor({ component, onUpdate }) {
|
|
|
23
23
|
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(NumberField, { name: "distance", label: "Distance", values: values, onChange: onUpdate, min: 0, step: 1, fallback: 0 }), _jsx(NumberField, { name: "decay", label: "Decay", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 2 })] }), _jsxs(LightSection, { title: "Shadow", children: [_jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: values, onChange: onUpdate, fallback: false }), values.castShadow ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "shadowAutoUpdate", label: "Auto Update", values: values, onChange: onUpdate, fallback: true }), _jsx(NumberField, { name: "shadowMapSize", label: "Map Size", values: values, onChange: onUpdate, min: 128, step: 128, fallback: 512 }), _jsx(ShadowBiasField, { name: "shadowBias", label: "Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(ShadowBiasField, { name: "shadowNormalBias", label: "Normal Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(NumberField, { name: "shadowCameraNear", label: "Near", values: values, onChange: onUpdate, min: 0.001, step: 0.1, fallback: 0.5 }), _jsx(NumberField, { name: "shadowCameraFar", label: "Far", values: values, onChange: onUpdate, min: 0.1, step: 1, fallback: 500 })] })) : null] })] }));
|
|
24
24
|
}
|
|
25
25
|
function PointLightView({ properties, children }) {
|
|
26
|
-
const { editMode, isSelected } =
|
|
26
|
+
const { editMode, isSelected } = useCurrentNode();
|
|
27
27
|
const merged = mergeWithDefaults(pointLightDefaults, properties);
|
|
28
28
|
const color = merged.color;
|
|
29
29
|
const intensity = merged.intensity;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
import { useThree } from '@react-three/fiber';
|
|
4
4
|
import { SoundPicker } from '../../assetviewer/page';
|
|
5
|
-
import { useAssetRuntime,
|
|
5
|
+
import { useAssetRuntime, useCurrentNode } from '../assetRuntime';
|
|
6
6
|
import { gameEvents } from '../GameEvents';
|
|
7
7
|
import { BooleanField, FieldGroup, FieldRenderer, ListEditor, NumberField, SelectField, StringField } from './Input';
|
|
8
8
|
import { colors, ui } from '../styles';
|
|
@@ -124,7 +124,7 @@ function SoundComponentEditor({ component, onUpdate, basePath = '' }) {
|
|
|
124
124
|
}
|
|
125
125
|
function SoundComponentView({ properties, children }) {
|
|
126
126
|
const { getSound } = useAssetRuntime();
|
|
127
|
-
const { editMode, nodeId } =
|
|
127
|
+
const { editMode, nodeId } = useCurrentNode();
|
|
128
128
|
const { camera } = useThree();
|
|
129
129
|
const { eventName, autoplay = false, positional = false, refDistance = 1, maxDistance = 24, rolloffFactor = 1, distanceModel = 'inverse' } = properties;
|
|
130
130
|
const sequenceIndexRef = useRef(0);
|
|
@@ -3,7 +3,7 @@ import { useHelper } from "@react-three/drei";
|
|
|
3
3
|
import { useRef, useEffect } from "react";
|
|
4
4
|
import { BooleanField, ColorField, Label, NumberField, Vector3Input } from "./Input";
|
|
5
5
|
import { SpotLightHelper } from "three";
|
|
6
|
-
import { useAssetRuntime,
|
|
6
|
+
import { useAssetRuntime, useCurrentNode } from "../assetRuntime";
|
|
7
7
|
import { useFrame } from "@react-three/fiber";
|
|
8
8
|
import { TexturePicker } from "../../assetviewer/page";
|
|
9
9
|
import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
|
|
@@ -31,7 +31,7 @@ function SpotLightComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
31
31
|
function SpotLightView({ properties, children }) {
|
|
32
32
|
var _a;
|
|
33
33
|
const { getTexture } = useAssetRuntime();
|
|
34
|
-
const { editMode, isSelected } =
|
|
34
|
+
const { editMode, isSelected } = useCurrentNode();
|
|
35
35
|
const merged = mergeWithDefaults(spotLightDefaults, properties);
|
|
36
36
|
const color = merged.color;
|
|
37
37
|
const intensity = merged.intensity;
|
|
@@ -4,7 +4,6 @@ import BufferGeometryComponent from './BufferGeometryComponent';
|
|
|
4
4
|
import ModelComponent from './ModelComponent';
|
|
5
5
|
import TextComponent from './TextComponent';
|
|
6
6
|
import MaterialComponent from './MaterialComponent';
|
|
7
|
-
import PhysicsComponent from './PhysicsComponent';
|
|
8
7
|
import SpotLightComponent from './SpotLightComponent';
|
|
9
8
|
import PointLightComponent from './PointLightComponent';
|
|
10
9
|
import DirectionalLightComponent from './DirectionalLightComponent';
|
|
@@ -20,7 +19,6 @@ export const builtinComponents = [
|
|
|
20
19
|
ModelComponent,
|
|
21
20
|
TextComponent,
|
|
22
21
|
MaterialComponent,
|
|
23
|
-
PhysicsComponent,
|
|
24
22
|
SpotLightComponent,
|
|
25
23
|
PointLightComponent,
|
|
26
24
|
DirectionalLightComponent,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ThreeEvent } from "@react-three/fiber";
|
|
2
|
-
export type PointerHandler<T> = (event: ThreeEvent<PointerEvent>,
|
|
2
|
+
export type PointerHandler<T> = (event: ThreeEvent<PointerEvent>, node: T) => void;
|
|
3
3
|
export interface PointerEventHandlers<T> {
|
|
4
4
|
onClick?: PointerHandler<T>;
|
|
5
5
|
onPointerDown?: PointerHandler<T>;
|
|
@@ -12,10 +12,10 @@ export interface PointerEventHandlers<T> {
|
|
|
12
12
|
}
|
|
13
13
|
export interface UsePointerEventsOptions<T> extends PointerEventHandlers<T> {
|
|
14
14
|
enabled: boolean;
|
|
15
|
-
|
|
15
|
+
node: T | null | undefined;
|
|
16
16
|
}
|
|
17
17
|
export declare function hasPointerEventHandlers<T>(handlers: PointerEventHandlers<T>): boolean;
|
|
18
|
-
export declare function usePointerEvents<T>({ enabled,
|
|
18
|
+
export declare function usePointerEvents<T>({ enabled, node, onClick, onPointerDown, onPointerUp, onPointerMove, onPointerEnter, onPointerLeave, onPointerOver, onPointerOut, }: UsePointerEventsOptions<T>): {
|
|
19
19
|
onClick: ((event: ThreeEvent<PointerEvent>) => void) | undefined;
|
|
20
20
|
onPointerDown: ((event: ThreeEvent<PointerEvent>) => void) | undefined;
|
|
21
21
|
onPointerMove: ((event: ThreeEvent<PointerEvent>) => void) | undefined;
|
|
@@ -8,7 +8,7 @@ export function hasPointerEventHandlers(handlers) {
|
|
|
8
8
|
|| handlers.onPointerOver
|
|
9
9
|
|| handlers.onPointerOut);
|
|
10
10
|
}
|
|
11
|
-
export function usePointerEvents({ enabled,
|
|
11
|
+
export function usePointerEvents({ enabled, node, onClick, onPointerDown, onPointerUp, onPointerMove, onPointerEnter, onPointerLeave, onPointerOver, onPointerOut, }) {
|
|
12
12
|
if (!enabled) {
|
|
13
13
|
return {
|
|
14
14
|
onClick: undefined,
|
|
@@ -26,17 +26,17 @@ export function usePointerEvents({ enabled, entity, onClick, onPointerDown, onPo
|
|
|
26
26
|
return undefined;
|
|
27
27
|
return (event) => {
|
|
28
28
|
event.stopPropagation();
|
|
29
|
-
if (!
|
|
29
|
+
if (!node)
|
|
30
30
|
return;
|
|
31
|
-
handler(event,
|
|
31
|
+
handler(event, node);
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
34
|
const forwardMove = onPointerMove
|
|
35
35
|
? (event) => {
|
|
36
36
|
event.stopPropagation();
|
|
37
|
-
if (!
|
|
37
|
+
if (!node)
|
|
38
38
|
return;
|
|
39
|
-
onPointerMove(event,
|
|
39
|
+
onPointerMove(event, node);
|
|
40
40
|
}
|
|
41
41
|
: undefined;
|
|
42
42
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-three-game",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.93",
|
|
4
4
|
"description": "high performance 3D game engine built in React",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"@react-three/drei": ">=10.0.0",
|
|
29
29
|
"@react-three/fiber": ">=9.0.0",
|
|
30
|
-
"@react-three/rapier": ">=2.0.0",
|
|
31
30
|
"react": ">=18.0.0",
|
|
32
31
|
"react-dom": ">=18.0.0",
|
|
33
32
|
"three": ">=0.182.0",
|
|
@@ -36,7 +35,6 @@
|
|
|
36
35
|
"devDependencies": {
|
|
37
36
|
"@react-three/drei": "^10.7.7",
|
|
38
37
|
"@react-three/fiber": "^9.5.0",
|
|
39
|
-
"@react-three/rapier": "^2.2.0",
|
|
40
38
|
"@types/react": "^19.2.9",
|
|
41
39
|
"@types/react-dom": "^19.2.3",
|
|
42
40
|
"@types/three": "^0.182.0",
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { RigidBodyOptions } from "@react-three/rapier";
|
|
2
|
-
import { Component } from "./ComponentRegistry";
|
|
3
|
-
type PhysicsColliderType = NonNullable<RigidBodyOptions['colliders']> | 'capsule';
|
|
4
|
-
type ManualColliderShape = 'cuboid' | 'ball' | 'capsule';
|
|
5
|
-
export type PhysicsProps = Omit<RigidBodyOptions, 'colliders'> & {
|
|
6
|
-
colliders?: PhysicsColliderType;
|
|
7
|
-
manualColliderShape?: ManualColliderShape;
|
|
8
|
-
activeCollisionTypes?: 'all' | undefined;
|
|
9
|
-
linearVelocity?: [number, number, number];
|
|
10
|
-
angularVelocity?: [number, number, number];
|
|
11
|
-
colliderSize?: [number, number, number];
|
|
12
|
-
colliderRadius?: number;
|
|
13
|
-
capsuleRadius?: number;
|
|
14
|
-
capsuleHalfHeight?: number;
|
|
15
|
-
emitSensorEnterEvent?: boolean;
|
|
16
|
-
sensorEnterEventName?: string;
|
|
17
|
-
emitSensorExitEvent?: boolean;
|
|
18
|
-
sensorExitEventName?: string;
|
|
19
|
-
emitCollisionEnterEvent?: boolean;
|
|
20
|
-
collisionEnterEventName?: string;
|
|
21
|
-
emitCollisionExitEvent?: boolean;
|
|
22
|
-
collisionExitEventName?: string;
|
|
23
|
-
};
|
|
24
|
-
export declare function isPhysicsProps(v: any): v is PhysicsProps;
|
|
25
|
-
declare const PhysicsComponent: Component;
|
|
26
|
-
export default PhysicsComponent;
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
12
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
-
import { BallCollider, CapsuleCollider, CuboidCollider, RigidBody, useRapier } from "@react-three/rapier";
|
|
14
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
15
|
-
import { useAssetRuntime, useEntityRuntime } from "../assetRuntime";
|
|
16
|
-
import { gameEvents, getEntityIdFromRigidBody } from "../GameEvents";
|
|
17
|
-
import { usePrefabNode, usePrefabStore } from "../prefabStore";
|
|
18
|
-
import { BooleanField, FieldGroup, NumberField, SelectField, StringField, Vector3Field } from "./Input";
|
|
19
|
-
import { findComponent, getNodeUserData } from "../types";
|
|
20
|
-
import { colors } from "../styles";
|
|
21
|
-
export function isPhysicsProps(v) {
|
|
22
|
-
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";
|
|
23
|
-
}
|
|
24
|
-
const enabledAxesFallback = [true, true, true];
|
|
25
|
-
const manualColliderShapeFallback = 'cuboid';
|
|
26
|
-
const colliderSizeFallback = [1, 1, 1];
|
|
27
|
-
const colliderRadiusFallback = 0.5;
|
|
28
|
-
const capsuleRadiusFallback = 0.35;
|
|
29
|
-
const capsuleHalfHeightFallback = 0.45;
|
|
30
|
-
const EDIT_MODE_DEBUG_REFRESH_THROTTLE_MS = 120;
|
|
31
|
-
function isManualColliderShape(value) {
|
|
32
|
-
return value === 'cuboid' || value === 'ball' || value === 'capsule';
|
|
33
|
-
}
|
|
34
|
-
function hasNodeColliderSource(node) {
|
|
35
|
-
return Boolean(findComponent(node, 'Geometry')
|
|
36
|
-
|| findComponent(node, 'BufferGeometry')
|
|
37
|
-
|| findComponent(node, 'Model'));
|
|
38
|
-
}
|
|
39
|
-
function subtreeHasColliderSource(nodeId, nodesById, childIdsById) {
|
|
40
|
-
var _a;
|
|
41
|
-
if (!nodeId)
|
|
42
|
-
return false;
|
|
43
|
-
const pending = [nodeId];
|
|
44
|
-
while (pending.length > 0) {
|
|
45
|
-
const currentId = pending.pop();
|
|
46
|
-
if (!currentId)
|
|
47
|
-
continue;
|
|
48
|
-
const currentNode = nodesById[currentId];
|
|
49
|
-
if (hasNodeColliderSource(currentNode)) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
pending.push(...((_a = childIdsById[currentId]) !== null && _a !== void 0 ? _a : []));
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
function renderManualCollider({ shape, sensor, colliderSize, colliderRadius, capsuleRadius, capsuleHalfHeight, }) {
|
|
57
|
-
if (shape === 'ball') {
|
|
58
|
-
return _jsx(BallCollider, { args: [colliderRadius], sensor: sensor });
|
|
59
|
-
}
|
|
60
|
-
if (shape === 'capsule') {
|
|
61
|
-
return _jsx(CapsuleCollider, { args: [capsuleHalfHeight, capsuleRadius], sensor: sensor });
|
|
62
|
-
}
|
|
63
|
-
return _jsx(CuboidCollider, { args: colliderSize.map(value => value / 2), sensor: sensor });
|
|
64
|
-
}
|
|
65
|
-
function LockedAxisField({ label, name, values, onChange, }) {
|
|
66
|
-
const enabledAxes = Array.isArray(values[name])
|
|
67
|
-
? values[name]
|
|
68
|
-
: enabledAxesFallback;
|
|
69
|
-
const axisLabels = ['X', 'Y', 'Z'];
|
|
70
|
-
const toggleAxisLock = (index) => {
|
|
71
|
-
const nextEnabledAxes = [...enabledAxes];
|
|
72
|
-
nextEnabledAxes[index] = !nextEnabledAxes[index];
|
|
73
|
-
onChange({ [name]: nextEnabledAxes });
|
|
74
|
-
};
|
|
75
|
-
return (_jsxs("div", { children: [_jsxs("div", { style: {
|
|
76
|
-
display: 'flex',
|
|
77
|
-
alignItems: 'center',
|
|
78
|
-
justifyContent: 'space-between',
|
|
79
|
-
marginBottom: 4,
|
|
80
|
-
}, children: [_jsx("span", { style: {
|
|
81
|
-
display: 'block',
|
|
82
|
-
fontSize: '10px',
|
|
83
|
-
color: colors.textMuted,
|
|
84
|
-
textTransform: 'uppercase',
|
|
85
|
-
letterSpacing: '0.05em',
|
|
86
|
-
fontWeight: 500,
|
|
87
|
-
}, children: label }), _jsx("span", { style: {
|
|
88
|
-
fontSize: '10px',
|
|
89
|
-
color: colors.textDim,
|
|
90
|
-
}, children: "Active means locked" })] }), _jsx("div", { style: { display: 'flex', gap: 4 }, children: axisLabels.map((axisLabel, index) => {
|
|
91
|
-
const isLocked = !enabledAxes[index];
|
|
92
|
-
return (_jsx("button", { type: "button", onClick: () => toggleAxisLock(index), style: {
|
|
93
|
-
flex: 1,
|
|
94
|
-
minHeight: 22,
|
|
95
|
-
backgroundColor: isLocked ? colors.dangerBg : colors.bgInput,
|
|
96
|
-
border: `1px solid ${isLocked ? colors.dangerBorder : colors.border}`,
|
|
97
|
-
borderRadius: 0,
|
|
98
|
-
padding: '2px 6px',
|
|
99
|
-
color: isLocked ? colors.danger : colors.textMuted,
|
|
100
|
-
fontSize: '11px',
|
|
101
|
-
fontFamily: 'monospace',
|
|
102
|
-
cursor: 'pointer',
|
|
103
|
-
}, children: axisLabel }, axisLabel));
|
|
104
|
-
}) })] }));
|
|
105
|
-
}
|
|
106
|
-
function PhysicsComponentEditor({ node, component, onUpdate }) {
|
|
107
|
-
const nodeId = node === null || node === void 0 ? void 0 : node.id;
|
|
108
|
-
const hasAutomaticColliderSource = usePrefabStore(state => subtreeHasColliderSource(nodeId, state.nodesById, state.childIdsById));
|
|
109
|
-
const manualColliderShape = isManualColliderShape(component.properties.manualColliderShape)
|
|
110
|
-
? component.properties.manualColliderShape
|
|
111
|
-
: manualColliderShapeFallback;
|
|
112
|
-
return (_jsxs(FieldGroup, { children: [_jsx(SelectField, { name: "type", label: "Type", values: component.properties, onChange: onUpdate, options: [
|
|
113
|
-
{ value: 'dynamic', label: 'Dynamic' },
|
|
114
|
-
{ value: 'fixed', label: 'Fixed' },
|
|
115
|
-
{ value: 'kinematicPosition', label: 'Kinematic Position' },
|
|
116
|
-
{ value: 'kinematicVelocity', label: 'Kinematic Velocity' },
|
|
117
|
-
] }), hasAutomaticColliderSource ? (_jsxs(_Fragment, { children: [_jsx(SelectField, { name: "colliders", label: "Collider", values: component.properties, onChange: onUpdate, options: [
|
|
118
|
-
{ value: 'hull', label: 'Hull (convex)' },
|
|
119
|
-
{ value: 'trimesh', label: 'Trimesh (exact)' },
|
|
120
|
-
{ value: 'cuboid', label: 'Cuboid (box)' },
|
|
121
|
-
{ value: 'ball', label: 'Ball (sphere)' },
|
|
122
|
-
{ value: 'capsule', label: 'Capsule' },
|
|
123
|
-
] }), component.properties.colliders === 'capsule' ? (_jsxs(_Fragment, { children: [_jsx(NumberField, { name: "capsuleRadius", label: "Capsule Radius", values: component.properties, onChange: onUpdate, fallback: capsuleRadiusFallback, min: 0.01, step: 0.01 }), _jsx(NumberField, { name: "capsuleHalfHeight", label: "Capsule Half Height", values: component.properties, onChange: onUpdate, fallback: capsuleHalfHeightFallback, min: 0.01, step: 0.01 })] })) : null] })) : (_jsxs(_Fragment, { children: [_jsx(SelectField, { name: "manualColliderShape", label: "Shape", values: Object.assign(Object.assign({}, component.properties), { manualColliderShape }), onChange: onUpdate, options: [
|
|
124
|
-
{ value: 'cuboid', label: 'Cuboid (box)' },
|
|
125
|
-
{ value: 'ball', label: 'Ball (sphere)' },
|
|
126
|
-
{ value: 'capsule', label: 'Capsule' },
|
|
127
|
-
] }), manualColliderShape === 'cuboid' ? (_jsx(Vector3Field, { name: "colliderSize", label: "Collider Size", values: component.properties, onChange: onUpdate, fallback: colliderSizeFallback })) : null, manualColliderShape === 'ball' ? (_jsx(NumberField, { name: "colliderRadius", label: "Collider Radius", values: component.properties, onChange: onUpdate, fallback: colliderRadiusFallback, min: 0.01, step: 0.01 })) : null, manualColliderShape === 'capsule' ? (_jsxs(_Fragment, { children: [_jsx(NumberField, { name: "capsuleRadius", label: "Capsule Radius", values: component.properties, onChange: onUpdate, fallback: capsuleRadiusFallback, min: 0.01, step: 0.01 }), _jsx(NumberField, { name: "capsuleHalfHeight", label: "Capsule Half Height", values: component.properties, onChange: onUpdate, fallback: capsuleHalfHeightFallback, min: 0.01, step: 0.01 })] })) : null] })), _jsx(NumberField, { name: "mass", label: "Mass", values: component.properties, onChange: onUpdate, fallback: 1, step: 0.1, min: 0 }), _jsx(NumberField, { name: "restitution", label: "Restitution (Bounciness)", values: component.properties, onChange: onUpdate, fallback: 0, min: 0, max: 1, step: 0.1 }), _jsx(NumberField, { name: "friction", label: "Friction", values: component.properties, onChange: onUpdate, fallback: 0.5, min: 0, step: 0.1 }), _jsx(NumberField, { name: "linearDamping", label: "Linear Damping", values: component.properties, onChange: onUpdate, fallback: 0, min: 0, step: 0.1 }), _jsx(NumberField, { name: "angularDamping", label: "Angular Damping", values: component.properties, onChange: onUpdate, fallback: 0, min: 0, step: 0.1 }), _jsx(NumberField, { name: "gravityScale", label: "Gravity Scale", values: component.properties, onChange: onUpdate, fallback: 1, step: 0.1 }), _jsx(Vector3Field, { name: "linearVelocity", label: "Linear Velocity", values: component.properties, onChange: onUpdate, fallback: [0, 0, 0] }), _jsx(Vector3Field, { name: "angularVelocity", label: "Angular Velocity", values: component.properties, onChange: onUpdate, fallback: [0, 0, 0] }), _jsx(LockedAxisField, { label: "Lock Movement", name: "enabledTranslations", values: component.properties, onChange: onUpdate }), _jsx(LockedAxisField, { label: "Lock Rotations", name: "enabledRotations", values: component.properties, onChange: onUpdate }), _jsx(BooleanField, { name: "sensor", label: "Sensor (Trigger Only)", values: component.properties, onChange: onUpdate, fallback: false }), _jsx(BooleanField, { name: "emitCollisionEnterEvent", label: "Emit Collision Enter", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitCollisionEnterEvent ? (_jsx(StringField, { name: "collisionEnterEventName", label: "Collision Enter Event", values: component.properties, onChange: onUpdate, placeholder: "target:hit" })) : null, _jsx(BooleanField, { name: "emitCollisionExitEvent", label: "Emit Collision Exit", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitCollisionExitEvent ? (_jsx(StringField, { name: "collisionExitEventName", label: "Collision Exit Event", values: component.properties, onChange: onUpdate, placeholder: "target:reset" })) : null, _jsx(BooleanField, { name: "emitSensorEnterEvent", label: "Emit Sensor Enter", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitSensorEnterEvent ? (_jsx(StringField, { name: "sensorEnterEventName", label: "Sensor Enter Event", values: component.properties, onChange: onUpdate, placeholder: "sensor:enter" })) : null, _jsx(BooleanField, { name: "emitSensorExitEvent", label: "Emit Sensor Exit", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitSensorExitEvent ? (_jsx(StringField, { name: "sensorExitEventName", label: "Sensor Exit Event", values: component.properties, onChange: onUpdate, placeholder: "sensor:exit" })) : null, _jsx(SelectField, { name: "activeCollisionTypes", label: "Collision Detection", values: component.properties, onChange: onUpdate, options: [
|
|
128
|
-
{ value: '', label: 'Default (Dynamic only)' },
|
|
129
|
-
{ value: 'all', label: 'All (includes kinematic & fixed)' },
|
|
130
|
-
] })] }));
|
|
131
|
-
}
|
|
132
|
-
function PhysicsComponentView({ properties, children, position, rotation, scale }) {
|
|
133
|
-
var _a, _b, _c;
|
|
134
|
-
const { registerRigidBodyRef } = useAssetRuntime();
|
|
135
|
-
const { editMode, nodeId, getObject } = useEntityRuntime();
|
|
136
|
-
const gameObject = usePrefabNode(nodeId);
|
|
137
|
-
const hasAutomaticColliderSource = usePrefabStore(state => subtreeHasColliderSource(nodeId, state.nodesById, state.childIdsById));
|
|
138
|
-
const nodeName = (_b = (_a = gameObject === null || gameObject === void 0 ? void 0 : gameObject.name) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
|
|
139
|
-
const userData = Object.assign(Object.assign({ prefabNodeId: (_c = gameObject === null || gameObject === void 0 ? void 0 : gameObject.id) !== null && _c !== void 0 ? _c : nodeId }, (nodeName ? { prefabNodeName: nodeName } : {})), getNodeUserData(gameObject));
|
|
140
|
-
const { type, colliders, sensor, manualColliderShape = manualColliderShapeFallback, activeCollisionTypes, linearVelocity = [0, 0, 0], angularVelocity = [0, 0, 0], colliderSize = colliderSizeFallback, colliderRadius = colliderRadiusFallback, capsuleRadius = capsuleRadiusFallback, capsuleHalfHeight = capsuleHalfHeightFallback, emitSensorEnterEvent = false, sensorEnterEventName, emitSensorExitEvent = false, sensorExitEventName, emitCollisionEnterEvent = false, collisionEnterEventName, emitCollisionExitEvent = false, collisionExitEventName, enabledTranslations = enabledAxesFallback, enabledRotations = enabledAxesFallback } = properties, otherProps = __rest(properties, ["type", "colliders", "sensor", "manualColliderShape", "activeCollisionTypes", "linearVelocity", "angularVelocity", "colliderSize", "colliderRadius", "capsuleRadius", "capsuleHalfHeight", "emitSensorEnterEvent", "sensorEnterEventName", "emitSensorExitEvent", "sensorExitEventName", "emitCollisionEnterEvent", "collisionEnterEventName", "emitCollisionExitEvent", "collisionExitEventName", "enabledTranslations", "enabledRotations"]);
|
|
141
|
-
const colliderType = colliders || (type === 'fixed' ? 'trimesh' : 'hull');
|
|
142
|
-
const resolvedManualColliderShape = isManualColliderShape(manualColliderShape)
|
|
143
|
-
? manualColliderShape
|
|
144
|
-
: manualColliderShapeFallback;
|
|
145
|
-
const usesAutomaticColliderSource = hasAutomaticColliderSource && colliderType !== 'capsule';
|
|
146
|
-
const manualColliderShapeToRender = hasAutomaticColliderSource
|
|
147
|
-
? 'capsule'
|
|
148
|
-
: resolvedManualColliderShape;
|
|
149
|
-
const rigidBodyRef = useRef(null);
|
|
150
|
-
const [editRefreshVersion, setEditRefreshVersion] = useState(0);
|
|
151
|
-
const lastEditRefreshAtRef = useRef(0);
|
|
152
|
-
const linearVelocityKey = linearVelocity.join(',');
|
|
153
|
-
const angularVelocityKey = angularVelocity.join(',');
|
|
154
|
-
const transformSignature = `${position === null || position === void 0 ? void 0 : position.join(',')}_${rotation === null || rotation === void 0 ? void 0 : rotation.join(',')}_${scale === null || scale === void 0 ? void 0 : scale.join(',')}`;
|
|
155
|
-
const rbKey = `${type || 'dynamic'}_${colliderType}_${resolvedManualColliderShape}_${colliderSize.join(',')}_${colliderRadius}_${capsuleRadius}_${capsuleHalfHeight}_${editMode ? editRefreshVersion : 0}`;
|
|
156
|
-
const handleRigidBodyRef = useCallback((rigidBody) => {
|
|
157
|
-
rigidBodyRef.current = rigidBody;
|
|
158
|
-
if (!nodeId)
|
|
159
|
-
return;
|
|
160
|
-
registerRigidBodyRef(nodeId, rigidBody);
|
|
161
|
-
}, [nodeId, registerRigidBodyRef]);
|
|
162
|
-
// Try to get rapier context - will be null if not inside <Physics>
|
|
163
|
-
let rapier = null;
|
|
164
|
-
try {
|
|
165
|
-
const rapierContext = useRapier();
|
|
166
|
-
rapier = rapierContext.rapier;
|
|
167
|
-
}
|
|
168
|
-
catch (e) {
|
|
169
|
-
// Not inside Physics context - that's ok, just won't have rapier features
|
|
170
|
-
}
|
|
171
|
-
// Configure active collision types for kinematic/sensor bodies
|
|
172
|
-
useEffect(() => {
|
|
173
|
-
if (activeCollisionTypes === 'all' && rigidBodyRef.current && rapier) {
|
|
174
|
-
const rb = rigidBodyRef.current;
|
|
175
|
-
// Apply to all colliders on this rigid body
|
|
176
|
-
for (let i = 0; i < rb.numColliders(); i++) {
|
|
177
|
-
const collider = rb.collider(i);
|
|
178
|
-
collider.setActiveCollisionTypes(rapier.ActiveCollisionTypes.DEFAULT |
|
|
179
|
-
rapier.ActiveCollisionTypes.KINEMATIC_FIXED |
|
|
180
|
-
rapier.ActiveCollisionTypes.KINEMATIC_KINEMATIC);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}, [activeCollisionTypes, rapier, type, colliders]);
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
if (!editMode) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
const now = Date.now();
|
|
189
|
-
const delay = Math.max(0, EDIT_MODE_DEBUG_REFRESH_THROTTLE_MS - (now - lastEditRefreshAtRef.current));
|
|
190
|
-
if (delay === 0) {
|
|
191
|
-
lastEditRefreshAtRef.current = now;
|
|
192
|
-
setEditRefreshVersion(version => version + 1);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const timeoutId = setTimeout(() => {
|
|
196
|
-
lastEditRefreshAtRef.current = Date.now();
|
|
197
|
-
setEditRefreshVersion(version => version + 1);
|
|
198
|
-
}, delay);
|
|
199
|
-
return () => clearTimeout(timeoutId);
|
|
200
|
-
}, [editMode, transformSignature]);
|
|
201
|
-
// Seed authored velocities when the body instance changes or the authored values change.
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
if (!rigidBodyRef.current)
|
|
204
|
-
return;
|
|
205
|
-
rigidBodyRef.current.setLinvel({
|
|
206
|
-
x: linearVelocity[0],
|
|
207
|
-
y: linearVelocity[1],
|
|
208
|
-
z: linearVelocity[2],
|
|
209
|
-
}, true);
|
|
210
|
-
}, [rbKey, linearVelocityKey]);
|
|
211
|
-
useEffect(() => {
|
|
212
|
-
if (!rigidBodyRef.current)
|
|
213
|
-
return;
|
|
214
|
-
rigidBodyRef.current.setAngvel({
|
|
215
|
-
x: angularVelocity[0],
|
|
216
|
-
y: angularVelocity[1],
|
|
217
|
-
z: angularVelocity[2],
|
|
218
|
-
}, true);
|
|
219
|
-
}, [rbKey, angularVelocityKey]);
|
|
220
|
-
const dispatchPhysicsEvent = useCallback((eventType, payload) => {
|
|
221
|
-
var _a, _b, _c;
|
|
222
|
-
if (!nodeId)
|
|
223
|
-
return;
|
|
224
|
-
const trimmedEventType = eventType === null || eventType === void 0 ? void 0 : eventType.trim();
|
|
225
|
-
if (!trimmedEventType)
|
|
226
|
-
return;
|
|
227
|
-
const targetEntityId = getEntityIdFromRigidBody(payload.other.rigidBody);
|
|
228
|
-
gameEvents.emit(trimmedEventType, {
|
|
229
|
-
sourceEntityId: nodeId,
|
|
230
|
-
sourceNodeId: nodeId,
|
|
231
|
-
sourceObject: getObject(),
|
|
232
|
-
sourceRigidBody: rigidBodyRef.current,
|
|
233
|
-
targetEntityId,
|
|
234
|
-
targetNodeId: targetEntityId,
|
|
235
|
-
targetObject: (_b = (_a = payload.other.rigidBodyObject) !== null && _a !== void 0 ? _a : payload.other.colliderObject) !== null && _b !== void 0 ? _b : null,
|
|
236
|
-
targetRigidBody: (_c = payload.other.rigidBody) !== null && _c !== void 0 ? _c : null,
|
|
237
|
-
rapierEvent: payload,
|
|
238
|
-
});
|
|
239
|
-
}, [getObject, nodeId]);
|
|
240
|
-
const handleIntersectionEnter = useCallback((payload) => {
|
|
241
|
-
if (!emitSensorEnterEvent)
|
|
242
|
-
return;
|
|
243
|
-
dispatchPhysicsEvent(sensorEnterEventName, payload);
|
|
244
|
-
}, [dispatchPhysicsEvent, emitSensorEnterEvent, sensorEnterEventName]);
|
|
245
|
-
const handleIntersectionExit = useCallback((payload) => {
|
|
246
|
-
if (!emitSensorExitEvent)
|
|
247
|
-
return;
|
|
248
|
-
dispatchPhysicsEvent(sensorExitEventName, payload);
|
|
249
|
-
}, [dispatchPhysicsEvent, emitSensorExitEvent, sensorExitEventName]);
|
|
250
|
-
const handleCollisionEnter = useCallback((payload) => {
|
|
251
|
-
if (!emitCollisionEnterEvent)
|
|
252
|
-
return;
|
|
253
|
-
dispatchPhysicsEvent(collisionEnterEventName, payload);
|
|
254
|
-
}, [collisionEnterEventName, dispatchPhysicsEvent, emitCollisionEnterEvent]);
|
|
255
|
-
const handleCollisionExit = useCallback((payload) => {
|
|
256
|
-
if (!emitCollisionExitEvent)
|
|
257
|
-
return;
|
|
258
|
-
dispatchPhysicsEvent(collisionExitEventName, payload);
|
|
259
|
-
}, [collisionExitEventName, dispatchPhysicsEvent, emitCollisionExitEvent]);
|
|
260
|
-
const rigidBodyProps = Object.assign({ ref: handleRigidBodyRef, type, colliders: usesAutomaticColliderSource ? colliderType : false, position,
|
|
261
|
-
rotation,
|
|
262
|
-
scale,
|
|
263
|
-
sensor,
|
|
264
|
-
enabledTranslations,
|
|
265
|
-
enabledRotations, name: nodeName, userData: Object.assign({ entityId: nodeId }, userData), onIntersectionEnter: emitSensorEnterEvent ? handleIntersectionEnter : undefined, onIntersectionExit: emitSensorExitEvent ? handleIntersectionExit : undefined, onCollisionEnter: emitCollisionEnterEvent ? handleCollisionEnter : undefined, onCollisionExit: emitCollisionExitEvent ? handleCollisionExit : undefined }, otherProps);
|
|
266
|
-
const rigidBodyContent = (_jsxs(_Fragment, { children: [!usesAutomaticColliderSource ? renderManualCollider({
|
|
267
|
-
shape: manualColliderShapeToRender,
|
|
268
|
-
sensor,
|
|
269
|
-
colliderSize,
|
|
270
|
-
colliderRadius,
|
|
271
|
-
capsuleRadius,
|
|
272
|
-
capsuleHalfHeight,
|
|
273
|
-
}) : null, children] }));
|
|
274
|
-
return (_jsx(RigidBody, Object.assign({}, rigidBodyProps, { children: rigidBodyContent }), rbKey));
|
|
275
|
-
}
|
|
276
|
-
const PhysicsComponent = {
|
|
277
|
-
name: 'Physics',
|
|
278
|
-
Editor: PhysicsComponentEditor,
|
|
279
|
-
View: PhysicsComponentView,
|
|
280
|
-
defaultProperties: {
|
|
281
|
-
type: 'dynamic',
|
|
282
|
-
colliders: 'hull',
|
|
283
|
-
manualColliderShape: manualColliderShapeFallback,
|
|
284
|
-
colliderSize: colliderSizeFallback,
|
|
285
|
-
colliderRadius: colliderRadiusFallback,
|
|
286
|
-
capsuleRadius: capsuleRadiusFallback,
|
|
287
|
-
capsuleHalfHeight: capsuleHalfHeightFallback,
|
|
288
|
-
linearVelocity: [0, 0, 0],
|
|
289
|
-
angularVelocity: [0, 0, 0],
|
|
290
|
-
enabledTranslations: [true, true, true],
|
|
291
|
-
enabledRotations: [true, true, true],
|
|
292
|
-
emitSensorEnterEvent: false,
|
|
293
|
-
sensorEnterEventName: '',
|
|
294
|
-
emitSensorExitEvent: false,
|
|
295
|
-
sensorExitEventName: '',
|
|
296
|
-
emitCollisionEnterEvent: false,
|
|
297
|
-
collisionEnterEventName: '',
|
|
298
|
-
emitCollisionExitEvent: false,
|
|
299
|
-
collisionExitEventName: '',
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
export default PhysicsComponent;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { Object3D } from "three";
|
|
2
|
-
import type { GameObject } from "./types";
|
|
3
|
-
export interface SpawnOptions {
|
|
4
|
-
name?: string;
|
|
5
|
-
parentId?: string;
|
|
6
|
-
select?: boolean;
|
|
7
|
-
}
|
|
8
|
-
export type EntityData = Omit<GameObject, "children">;
|
|
9
|
-
export type PropertyPath = string | Array<string | number>;
|
|
10
|
-
export interface EntityComponent<TProperties = Record<string, any>> {
|
|
11
|
-
readonly key: string;
|
|
12
|
-
readonly type: string;
|
|
13
|
-
get: <TValue = unknown>(path?: PropertyPath) => TValue | undefined;
|
|
14
|
-
set: (path: PropertyPath, value: unknown) => void;
|
|
15
|
-
update: (update: (properties: TProperties) => TProperties) => void;
|
|
16
|
-
}
|
|
17
|
-
export interface Entity {
|
|
18
|
-
readonly id: string;
|
|
19
|
-
readonly name: string | undefined;
|
|
20
|
-
readonly enabled: boolean;
|
|
21
|
-
readonly parent: Entity | null;
|
|
22
|
-
readonly children: Entity[];
|
|
23
|
-
readonly object: Object3D | null;
|
|
24
|
-
readonly rigidBody: any;
|
|
25
|
-
set: (data: EntityData) => void;
|
|
26
|
-
update: (update: (node: EntityData) => EntityData) => void;
|
|
27
|
-
getComponent: <TProperties = Record<string, any>>(name: string) => EntityComponent<TProperties> | null;
|
|
28
|
-
addComponent: (type: string, properties?: Record<string, any>) => EntityComponent | null;
|
|
29
|
-
removeComponent: (name: string) => void;
|
|
30
|
-
destroy: () => void;
|
|
31
|
-
}
|
|
32
|
-
export type EntityUpdate = (node: EntityData) => EntityData;
|
|
33
|
-
export type SceneUpdates = Record<string, EntityUpdate>;
|
|
34
|
-
export interface Scene {
|
|
35
|
-
readonly rootId: string;
|
|
36
|
-
find: (id: string) => Entity | null;
|
|
37
|
-
get: (id: string) => Entity;
|
|
38
|
-
create: (name: string, components?: Record<string, {
|
|
39
|
-
type: string;
|
|
40
|
-
properties?: Record<string, any>;
|
|
41
|
-
}>, options?: SpawnOptions) => Entity;
|
|
42
|
-
update: {
|
|
43
|
-
(id: string, update: EntityUpdate): void;
|
|
44
|
-
(updates: SceneUpdates): void;
|
|
45
|
-
};
|
|
46
|
-
add: (node: GameObject, options?: SpawnOptions) => Entity;
|
|
47
|
-
remove: (id: string) => void;
|
|
48
|
-
/**
|
|
49
|
-
* Coalesce many entity / component updates into a single store revision.
|
|
50
|
-
* Entity `update`/`set`, `EntityComponent` `set`/`update`, `addComponent`,
|
|
51
|
-
* and `removeComponent` calls inside the callback are buffered and flushed
|
|
52
|
-
* as one batched write. `add`, `remove`, and `destroy` (structural tree ops)
|
|
53
|
-
* still commit immediately.
|
|
54
|
-
*/
|
|
55
|
-
batch: (fn: () => void) => void;
|
|
56
|
-
}
|
|
57
|
-
interface SceneAdapter {
|
|
58
|
-
getRootId: () => string;
|
|
59
|
-
getNode: (id: string) => EntityData | null;
|
|
60
|
-
getChildIds: (id: string) => string[];
|
|
61
|
-
getParentId: (id: string) => string | null;
|
|
62
|
-
updateNode: (id: string, update: (node: EntityData) => EntityData) => void;
|
|
63
|
-
updateNodes: (updates: Record<string, (node: EntityData) => EntityData>) => void;
|
|
64
|
-
addNode: (node: GameObject, options?: SpawnOptions) => string;
|
|
65
|
-
removeNode: (id: string) => void;
|
|
66
|
-
getObject?: (id: string) => Object3D | null;
|
|
67
|
-
getRigidBody?: (id: string) => any;
|
|
68
|
-
}
|
|
69
|
-
export declare function createScene(adapter: SceneAdapter): Scene;
|
|
70
|
-
export {};
|