react-three-game 0.0.84 → 0.0.86
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 +110 -36
- package/dist/index.d.ts +3 -7
- package/dist/index.js +1 -4
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +0 -4
- package/dist/tools/prefabeditor/InstanceProvider.js +13 -44
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +7 -2
- package/dist/tools/prefabeditor/PrefabEditor.js +13 -24
- package/dist/tools/prefabeditor/PrefabRoot.js +99 -48
- package/dist/tools/prefabeditor/{runtime.d.ts → assetRuntime.d.ts} +0 -25
- package/dist/tools/prefabeditor/assetRuntime.js +37 -0
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +98 -0
- package/dist/tools/prefabeditor/components/CameraComponent.js +1 -1
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +0 -3
- package/dist/tools/prefabeditor/components/DataComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/DataComponent.js +87 -0
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/EnvironmentComponent.js +1 -1
- package/dist/tools/prefabeditor/components/GeometryComponent.js +4 -2
- package/dist/tools/prefabeditor/components/Input.d.ts +2 -13
- package/dist/tools/prefabeditor/components/Input.js +0 -55
- package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +3 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.js +49 -18
- package/dist/tools/prefabeditor/components/ModelComponent.js +3 -3
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +4 -0
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +69 -132
- package/dist/tools/prefabeditor/components/PointLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/SoundComponent.js +17 -17
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/index.js +10 -8
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/types.js +18 -0
- package/dist/tools/prefabeditor/usePointerEvents.d.ts +27 -0
- package/dist/tools/prefabeditor/usePointerEvents.js +52 -0
- package/package.json +1 -1
- package/dist/tools/prefabeditor/GameEvents.d.ts +0 -128
- package/dist/tools/prefabeditor/GameEvents.js +0 -118
- package/dist/tools/prefabeditor/components/ClickComponent.d.ts +0 -3
- package/dist/tools/prefabeditor/components/ClickComponent.js +0 -52
- package/dist/tools/prefabeditor/runtime.js +0 -184
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export type FieldType = 'vector3' | 'number' | 'string' | 'color' | 'boolean' | 'select' | 'node'
|
|
2
|
+
export type FieldType = 'vector3' | 'number' | 'string' | 'color' | 'boolean' | 'select' | 'node';
|
|
3
3
|
interface BaseFieldDefinition {
|
|
4
4
|
name: string;
|
|
5
5
|
label: string;
|
|
@@ -36,10 +36,6 @@ interface NodeFieldDefinition extends BaseFieldDefinition {
|
|
|
36
36
|
placeholder?: string;
|
|
37
37
|
includeRoot?: boolean;
|
|
38
38
|
}
|
|
39
|
-
interface EventFieldDefinition extends BaseFieldDefinition {
|
|
40
|
-
type: 'event';
|
|
41
|
-
placeholder?: string;
|
|
42
|
-
}
|
|
43
39
|
interface CustomFieldDefinition extends BaseFieldDefinition {
|
|
44
40
|
type: 'custom';
|
|
45
41
|
render: (props: {
|
|
@@ -49,7 +45,7 @@ interface CustomFieldDefinition extends BaseFieldDefinition {
|
|
|
49
45
|
onChangeMultiple: (values: Record<string, any>) => void;
|
|
50
46
|
}) => React.ReactNode;
|
|
51
47
|
}
|
|
52
|
-
export type FieldDefinition = Vector3FieldDefinition | NumberFieldDefinition | StringFieldDefinition | ColorFieldDefinition | BooleanFieldDefinition | SelectFieldDefinition | NodeFieldDefinition |
|
|
48
|
+
export type FieldDefinition = Vector3FieldDefinition | NumberFieldDefinition | StringFieldDefinition | ColorFieldDefinition | BooleanFieldDefinition | SelectFieldDefinition | NodeFieldDefinition | CustomFieldDefinition;
|
|
53
49
|
declare const styles: {
|
|
54
50
|
input: React.CSSProperties;
|
|
55
51
|
label: React.CSSProperties;
|
|
@@ -95,12 +91,6 @@ export declare function NodeInput({ label, value, onChange, placeholder, include
|
|
|
95
91
|
placeholder?: string;
|
|
96
92
|
includeRoot?: boolean;
|
|
97
93
|
}): import("react/jsx-runtime").JSX.Element;
|
|
98
|
-
export declare function EventInput({ label, value, onChange, placeholder, }: {
|
|
99
|
-
label: string;
|
|
100
|
-
value: string;
|
|
101
|
-
onChange: (value: string) => void;
|
|
102
|
-
placeholder?: string;
|
|
103
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
104
94
|
export declare function BooleanInput({ label, value, onChange }: {
|
|
105
95
|
label?: string;
|
|
106
96
|
value: boolean;
|
|
@@ -182,7 +172,6 @@ export declare function SelectField({ name, label, values, onChange, fallback, o
|
|
|
182
172
|
export declare function NodeField({ name, label, values, onChange, fallback, }: BoundStringFieldProps & {
|
|
183
173
|
fallback?: string;
|
|
184
174
|
}): import("react/jsx-runtime").JSX.Element;
|
|
185
|
-
export declare function EventField({ name, label, values, onChange, fallback, placeholder, }: BoundStringFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
186
175
|
export declare function Vector3Field({ name, label, values, onChange, fallback, snap, labelExtra, }: BoundVector3FieldProps): import("react/jsx-runtime").JSX.Element;
|
|
187
176
|
interface FieldRendererProps {
|
|
188
177
|
fields: FieldDefinition[];
|
|
@@ -347,55 +347,6 @@ export function NodeInput({ label, value, onChange, placeholder, includeRoot = t
|
|
|
347
347
|
setQuery('');
|
|
348
348
|
}, emptyMessage: "No matching nodes." })] })) : null] }));
|
|
349
349
|
}
|
|
350
|
-
const BUILT_IN_EVENT_OPTIONS = [
|
|
351
|
-
'sensor:enter',
|
|
352
|
-
'sensor:exit',
|
|
353
|
-
'collision:enter',
|
|
354
|
-
'collision:exit',
|
|
355
|
-
'click',
|
|
356
|
-
].map(eventName => ({
|
|
357
|
-
value: eventName,
|
|
358
|
-
label: eventName,
|
|
359
|
-
searchText: eventName.toLowerCase(),
|
|
360
|
-
}));
|
|
361
|
-
export function EventInput({ label, value, onChange, placeholder, }) {
|
|
362
|
-
const prefabState = useOptionalPrefabSnapshot();
|
|
363
|
-
const [query, setQuery] = useState('');
|
|
364
|
-
const options = useMemo(() => {
|
|
365
|
-
var _a;
|
|
366
|
-
const authoredEvents = new Map();
|
|
367
|
-
Object.values((_a = prefabState === null || prefabState === void 0 ? void 0 : prefabState.nodesById) !== null && _a !== void 0 ? _a : {}).forEach(node => {
|
|
368
|
-
var _a;
|
|
369
|
-
Object.values((_a = node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
|
|
370
|
-
var _a;
|
|
371
|
-
Object.entries((_a = component === null || component === void 0 ? void 0 : component.properties) !== null && _a !== void 0 ? _a : {}).forEach(([key, entry]) => {
|
|
372
|
-
var _a, _b;
|
|
373
|
-
if (typeof entry !== 'string')
|
|
374
|
-
return;
|
|
375
|
-
if (!(key === 'eventName' || key.endsWith('EventName')))
|
|
376
|
-
return;
|
|
377
|
-
const eventName = entry.trim();
|
|
378
|
-
if (!eventName)
|
|
379
|
-
return;
|
|
380
|
-
authoredEvents.set(eventName, {
|
|
381
|
-
value: eventName,
|
|
382
|
-
label: eventName,
|
|
383
|
-
description: `${(_a = component === null || component === void 0 ? void 0 : component.type) !== null && _a !== void 0 ? _a : 'Component'} -> ${key}`,
|
|
384
|
-
searchText: `${eventName} ${(_b = component === null || component === void 0 ? void 0 : component.type) !== null && _b !== void 0 ? _b : ''} ${key}`.toLowerCase(),
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
const merged = new Map();
|
|
390
|
-
BUILT_IN_EVENT_OPTIONS.forEach(option => merged.set(option.value, option));
|
|
391
|
-
authoredEvents.forEach((option, key) => merged.set(key, option));
|
|
392
|
-
return [...merged.values()].sort((left, right) => left.value.localeCompare(right.value));
|
|
393
|
-
}, [prefabState === null || prefabState === void 0 ? void 0 : prefabState.nodesById]);
|
|
394
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx(StringInput, { label: label, value: value, onChange: onChange, placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : 'Event name' }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [_jsx("input", { type: "text", style: Object.assign(Object.assign({}, styles.input), { width: '100%', textAlign: 'left' }), value: query, onChange: e => setQuery(e.target.value), placeholder: "Search built-in and authored events" }), _jsx(SearchSuggestionList, { query: query, options: options, onSelect: (nextValue) => {
|
|
395
|
-
onChange(nextValue);
|
|
396
|
-
setQuery('');
|
|
397
|
-
}, emptyMessage: "No matching events." })] })] }));
|
|
398
|
-
}
|
|
399
350
|
export function BooleanInput({ label, value, onChange }) {
|
|
400
351
|
return (_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between' }, children: [label && _jsx(Label, { children: label }), _jsx("input", { type: "checkbox", style: {
|
|
401
352
|
height: 16,
|
|
@@ -470,10 +421,6 @@ export function NodeField({ name, label, values, onChange, fallback = '', }) {
|
|
|
470
421
|
var _a;
|
|
471
422
|
return (_jsx(NodeInput, { label: label, value: (_a = values[name]) !== null && _a !== void 0 ? _a : fallback, onChange: bindFieldChange(name, onChange) }));
|
|
472
423
|
}
|
|
473
|
-
export function EventField({ name, label, values, onChange, fallback = '', placeholder, }) {
|
|
474
|
-
var _a;
|
|
475
|
-
return (_jsx(EventInput, { label: label, value: (_a = values[name]) !== null && _a !== void 0 ? _a : fallback, onChange: bindFieldChange(name, onChange), placeholder: placeholder }));
|
|
476
|
-
}
|
|
477
424
|
export function Vector3Field({ name, label, values, onChange, fallback = [0, 0, 0], snap, labelExtra, }) {
|
|
478
425
|
var _a;
|
|
479
426
|
return (_jsx(Vector3Input, { label: label, value: (_a = values[name]) !== null && _a !== void 0 ? _a : fallback, onChange: bindFieldChange(name, onChange), snap: snap, labelExtra: labelExtra }));
|
|
@@ -500,8 +447,6 @@ export function FieldRenderer({ fields, values, onChange }) {
|
|
|
500
447
|
return (_jsx(SelectInput, { label: field.label, value: (_b = value !== null && value !== void 0 ? value : (_a = field.options[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '', onChange: v => updateField(field.name, v), options: field.options }, field.name));
|
|
501
448
|
case 'node':
|
|
502
449
|
return (_jsx(NodeInput, { label: field.label, value: value !== null && value !== void 0 ? value : '', onChange: v => updateField(field.name, v), placeholder: field.placeholder, includeRoot: field.includeRoot }, field.name));
|
|
503
|
-
case 'event':
|
|
504
|
-
return (_jsx(EventInput, { label: field.label, value: value !== null && value !== void 0 ? value : '', onChange: v => updateField(field.name, v), placeholder: field.placeholder }, field.name));
|
|
505
450
|
case 'custom':
|
|
506
451
|
return (_jsxs("div", { children: [field.label && _jsx(Label, { children: field.label }), field.render({
|
|
507
452
|
value,
|
|
@@ -15,8 +15,11 @@ export interface MaterialProps extends Omit<MeshStandardMaterialProperties & Mes
|
|
|
15
15
|
thickness?: number;
|
|
16
16
|
ior?: number;
|
|
17
17
|
texture?: string;
|
|
18
|
+
offset?: [number, number];
|
|
18
19
|
repeat?: boolean;
|
|
19
20
|
repeatCount?: [number, number];
|
|
21
|
+
animateOffset?: boolean;
|
|
22
|
+
offsetSpeed?: [number, number];
|
|
20
23
|
generateMipmaps?: boolean;
|
|
21
24
|
minFilter?: string;
|
|
22
25
|
magFilter?: string;
|
|
@@ -9,14 +9,19 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import {
|
|
13
|
-
import { createContext, useContext, useMemo } from 'react';
|
|
12
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { createContext, useContext, useMemo, useRef } from 'react';
|
|
14
14
|
import { extend } from '@react-three/fiber';
|
|
15
|
+
import { useFrame } from '@react-three/fiber';
|
|
15
16
|
import { FieldRenderer, Label, NumberInput } from './Input';
|
|
16
|
-
import { useAssetRuntime } from '../
|
|
17
|
+
import { useAssetRuntime } from '../assetRuntime';
|
|
17
18
|
import { MeshBasicNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
|
|
18
19
|
import { TexturePicker } from '../../assetviewer/page';
|
|
19
20
|
import { RepeatWrapping, ClampToEdgeWrapping, SRGBColorSpace, LinearSRGBColorSpace, NearestFilter, LinearFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter, FrontSide, BackSide, DoubleSide, } from 'three';
|
|
21
|
+
function Vector2Editor({ label, value, onChange, min, max, step, }) {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
return (_jsxs("div", { style: { display: 'flex', gap: 2 }, children: [_jsxs("div", { style: { flex: 1 }, children: [_jsxs(Label, { children: [label, " X"] }), _jsx(NumberInput, { value: (_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, onChange: x => { var _a; return onChange([x, (_a = value === null || value === void 0 ? void 0 : value[1]) !== null && _a !== void 0 ? _a : 0]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { style: { flex: 1 }, children: [_jsxs(Label, { children: [label, " Y"] }), _jsx(NumberInput, { value: (_b = value === null || value === void 0 ? void 0 : value[1]) !== null && _b !== void 0 ? _b : 0, onChange: y => { var _a; return onChange([(_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, y]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] }));
|
|
24
|
+
}
|
|
20
25
|
const EMPTY_MATERIAL_OVERRIDES = Object.freeze({});
|
|
21
26
|
const MaterialOverridesContext = createContext(EMPTY_MATERIAL_OVERRIDES);
|
|
22
27
|
export function useMaterialOverrides() {
|
|
@@ -36,6 +41,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
36
41
|
const materialType = (_a = component.properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
|
|
37
42
|
const hasTexture = !!component.properties.texture;
|
|
38
43
|
const hasRepeat = component.properties.repeat;
|
|
44
|
+
const animateOffset = component.properties.animateOffset;
|
|
39
45
|
const isStandardMaterial = materialType === 'standard';
|
|
40
46
|
const fields = [
|
|
41
47
|
{
|
|
@@ -82,10 +88,20 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
82
88
|
name: 'repeatCount',
|
|
83
89
|
type: 'custom',
|
|
84
90
|
label: 'Repeat (X, Y)',
|
|
85
|
-
render: ({ value, onChange }) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Repeat", value: value, onChange: onChange, min: 0.01, max: 100, step: 0.1 })),
|
|
92
|
+
}] : []),
|
|
93
|
+
{
|
|
94
|
+
name: 'offset',
|
|
95
|
+
type: 'custom',
|
|
96
|
+
label: 'Offset (X, Y)',
|
|
97
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Offset", value: value, onChange: onChange, step: 0.01 })),
|
|
98
|
+
},
|
|
99
|
+
{ name: 'animateOffset', type: 'boolean', label: 'Animate Offset' },
|
|
100
|
+
...(animateOffset ? [{
|
|
101
|
+
name: 'offsetSpeed',
|
|
102
|
+
type: 'custom',
|
|
103
|
+
label: 'Speed (X, Y)',
|
|
104
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Speed", value: value, onChange: onChange, step: 0.01 })),
|
|
89
105
|
}] : []),
|
|
90
106
|
{
|
|
91
107
|
name: 'normalMapTexture',
|
|
@@ -97,10 +113,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
97
113
|
name: 'normalScale',
|
|
98
114
|
type: 'custom',
|
|
99
115
|
label: 'Normal Scale (X, Y)',
|
|
100
|
-
render: ({ value, onChange }) => {
|
|
101
|
-
var _a, _b;
|
|
102
|
-
return (_jsxs("div", { style: { display: 'flex', gap: 2 }, children: [_jsxs("div", { style: { flex: 1 }, children: [_jsx(Label, { children: "X" }), _jsx(NumberInput, { value: (_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 1, onChange: v => { var _a; return onChange([v, (_a = value === null || value === void 0 ? void 0 : value[1]) !== null && _a !== void 0 ? _a : 1]); }, min: 0, max: 5, step: 0.01, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { style: { flex: 1 }, children: [_jsx(Label, { children: "Y" }), _jsx(NumberInput, { value: (_b = value === null || value === void 0 ? void 0 : value[1]) !== null && _b !== void 0 ? _b : 1, onChange: v => { var _a; return onChange([(_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 1, v]); }, min: 0, max: 5, step: 0.01, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] }));
|
|
103
|
-
},
|
|
116
|
+
render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Normal", value: value, onChange: onChange, min: 0, max: 5, step: 0.01 })),
|
|
104
117
|
}] : []),
|
|
105
118
|
{ name: 'generateMipmaps', type: 'boolean', label: 'Generate Mipmaps' },
|
|
106
119
|
{
|
|
@@ -131,13 +144,16 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
|
|
|
131
144
|
}
|
|
132
145
|
// View for Material component
|
|
133
146
|
function MaterialComponentView({ properties: rawProps }) {
|
|
134
|
-
var _a, _b, _c, _d, _e, _f;
|
|
147
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
135
148
|
const { getTexture } = useAssetRuntime();
|
|
136
149
|
const properties = rawProps;
|
|
137
150
|
const materialType = (_a = properties === null || properties === void 0 ? void 0 : properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
|
|
138
151
|
const textureName = properties === null || properties === void 0 ? void 0 : properties.texture;
|
|
152
|
+
const offset = properties === null || properties === void 0 ? void 0 : properties.offset;
|
|
139
153
|
const repeat = properties === null || properties === void 0 ? void 0 : properties.repeat;
|
|
140
154
|
const repeatCount = properties === null || properties === void 0 ? void 0 : properties.repeatCount;
|
|
155
|
+
const animateOffset = properties === null || properties === void 0 ? void 0 : properties.animateOffset;
|
|
156
|
+
const offsetSpeed = properties === null || properties === void 0 ? void 0 : properties.offsetSpeed;
|
|
141
157
|
const generateMipmaps = (properties === null || properties === void 0 ? void 0 : properties.generateMipmaps) !== false;
|
|
142
158
|
const minFilter = (properties === null || properties === void 0 ? void 0 : properties.minFilter) || 'LinearMipmapLinearFilter';
|
|
143
159
|
const magFilter = (properties === null || properties === void 0 ? void 0 : properties.magFilter) || 'LinearFilter';
|
|
@@ -147,7 +163,7 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
147
163
|
const normalMapTexture = normalMapTextureName ? (_c = getTexture(normalMapTextureName)) !== null && _c !== void 0 ? _c : undefined : undefined;
|
|
148
164
|
const materialSource = properties !== null && properties !== void 0 ? properties : {};
|
|
149
165
|
// Destructure all material props and separate custom texture handling props
|
|
150
|
-
const { texture: _texture, repeat: _repeat, repeatCount: _repeatCount, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "repeat", "repeatCount", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
|
|
166
|
+
const { texture: _texture, offset: _offset, repeat: _repeat, repeatCount: _repeatCount, animateOffset: _animateOffset, offsetSpeed: _offsetSpeed, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "offset", "repeat", "repeatCount", "animateOffset", "offsetSpeed", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
|
|
151
167
|
const sideMap = { FrontSide, BackSide, DoubleSide };
|
|
152
168
|
const resolvedSide = sideProp ? ((_d = sideMap[sideProp]) !== null && _d !== void 0 ? _d : FrontSide) : FrontSide;
|
|
153
169
|
const minFilterMap = {
|
|
@@ -162,8 +178,9 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
162
178
|
NearestFilter,
|
|
163
179
|
LinearFilter
|
|
164
180
|
};
|
|
181
|
+
const animatedOffsetRef = useRef([(_e = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _e !== void 0 ? _e : 0, (_f = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _f !== void 0 ? _f : 0]);
|
|
165
182
|
const finalTexture = useMemo(() => {
|
|
166
|
-
var _a, _b;
|
|
183
|
+
var _a, _b, _c, _d;
|
|
167
184
|
if (!texture)
|
|
168
185
|
return undefined;
|
|
169
186
|
const t = texture.clone();
|
|
@@ -176,13 +193,24 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
176
193
|
t.wrapS = t.wrapT = ClampToEdgeWrapping;
|
|
177
194
|
t.repeat.set(1, 1);
|
|
178
195
|
}
|
|
196
|
+
t.offset.set((_a = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _a !== void 0 ? _a : 0, (_b = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _b !== void 0 ? _b : 0);
|
|
179
197
|
t.colorSpace = SRGBColorSpace;
|
|
180
198
|
t.generateMipmaps = generateMipmaps;
|
|
181
|
-
t.minFilter = (
|
|
182
|
-
t.magFilter = (
|
|
199
|
+
t.minFilter = (_c = minFilterMap[minFilter]) !== null && _c !== void 0 ? _c : LinearMipmapLinearFilter;
|
|
200
|
+
t.magFilter = (_d = magFilterMap[magFilter]) !== null && _d !== void 0 ? _d : LinearFilter;
|
|
183
201
|
t.needsUpdate = true;
|
|
184
202
|
return t;
|
|
185
|
-
}, [texture, repeat, repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0], repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1], generateMipmaps, minFilter, magFilter]);
|
|
203
|
+
}, [texture, repeat, repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0], repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1], offset === null || offset === void 0 ? void 0 : offset[0], offset === null || offset === void 0 ? void 0 : offset[1], generateMipmaps, minFilter, magFilter]);
|
|
204
|
+
animatedOffsetRef.current = [(_g = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _g !== void 0 ? _g : 0, (_h = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _h !== void 0 ? _h : 0];
|
|
205
|
+
useFrame((_, delta) => {
|
|
206
|
+
var _a, _b;
|
|
207
|
+
if (!finalTexture || !animateOffset)
|
|
208
|
+
return;
|
|
209
|
+
const nextX = animatedOffsetRef.current[0] + ((_a = offsetSpeed === null || offsetSpeed === void 0 ? void 0 : offsetSpeed[0]) !== null && _a !== void 0 ? _a : 0) * delta;
|
|
210
|
+
const nextY = animatedOffsetRef.current[1] + ((_b = offsetSpeed === null || offsetSpeed === void 0 ? void 0 : offsetSpeed[1]) !== null && _b !== void 0 ? _b : 0) * delta;
|
|
211
|
+
animatedOffsetRef.current = [nextX, nextY];
|
|
212
|
+
finalTexture.offset.set(nextX, nextY);
|
|
213
|
+
});
|
|
186
214
|
const finalNormalMap = useMemo(() => {
|
|
187
215
|
if (!normalMapTexture)
|
|
188
216
|
return undefined;
|
|
@@ -199,7 +227,7 @@ function MaterialComponentView({ properties: rawProps }) {
|
|
|
199
227
|
if (materialType === 'basic') {
|
|
200
228
|
return _jsx("meshBasicNodeMaterial", Object.assign({}, sharedProps));
|
|
201
229
|
}
|
|
202
|
-
return (_jsx("meshStandardNodeMaterial", Object.assign({}, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(
|
|
230
|
+
return (_jsx("meshStandardNodeMaterial", Object.assign({}, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(_j = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _j !== void 0 ? _j : 1, (_k = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _k !== void 0 ? _k : 1] : undefined })));
|
|
203
231
|
}
|
|
204
232
|
const MaterialComponent = {
|
|
205
233
|
name: 'Material',
|
|
@@ -212,6 +240,9 @@ const MaterialComponent = {
|
|
|
212
240
|
wireframe: false,
|
|
213
241
|
transparent: false,
|
|
214
242
|
opacity: 1,
|
|
243
|
+
offset: [0, 0],
|
|
244
|
+
animateOffset: false,
|
|
245
|
+
offsetSpeed: [0, 0],
|
|
215
246
|
metalness: 0,
|
|
216
247
|
roughness: 1
|
|
217
248
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ModelPicker } from '../../assetviewer/page';
|
|
3
3
|
import { useContext, useMemo } from 'react';
|
|
4
|
-
import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput } from './Input';
|
|
5
|
-
import { useAssetRuntime } from '../
|
|
4
|
+
import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput, StringField } from './Input';
|
|
5
|
+
import { useAssetRuntime } from '../assetRuntime';
|
|
6
6
|
import { EditorContext } from '../PrefabEditor';
|
|
7
7
|
import { getRepeatAxesFromModelProperties, normalizeRepeatAxes } from '../InstanceProvider';
|
|
8
8
|
import { colors } from '../styles';
|
|
@@ -61,7 +61,7 @@ function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
|
|
|
61
61
|
const editorContext = useContext(EditorContext);
|
|
62
62
|
const positionSnap = (_a = editorContext === null || editorContext === void 0 ? void 0 : editorContext.positionSnap) !== null && _a !== void 0 ? _a : 0.5;
|
|
63
63
|
const repeatAxes = getRepeatAxesFromModelProperties(component.properties);
|
|
64
|
-
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: "repeat", label: "Repeat", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.repeat && (_jsx(RepeatAxisEditor, { axes: repeatAxes, onChange: (nextAxes) => onUpdate({ repeatAxes: nextAxes }), positionSnap: positionSnap }))] }))] }));
|
|
64
|
+
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: "entity: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 }))] }))] }));
|
|
65
65
|
}
|
|
66
66
|
// View for Model component
|
|
67
67
|
function ModelComponentView({ properties, children }) {
|
|
@@ -8,9 +8,13 @@ export type PhysicsProps = Omit<RigidBodyOptions, 'colliders'> & {
|
|
|
8
8
|
angularVelocity?: [number, number, number];
|
|
9
9
|
capsuleRadius?: number;
|
|
10
10
|
capsuleHalfHeight?: number;
|
|
11
|
+
emitSensorEnterEvent?: boolean;
|
|
11
12
|
sensorEnterEventName?: string;
|
|
13
|
+
emitSensorExitEvent?: boolean;
|
|
12
14
|
sensorExitEventName?: string;
|
|
15
|
+
emitCollisionEnterEvent?: boolean;
|
|
13
16
|
collisionEnterEventName?: string;
|
|
17
|
+
emitCollisionExitEvent?: boolean;
|
|
14
18
|
collisionExitEventName?: string;
|
|
15
19
|
};
|
|
16
20
|
export declare function isPhysicsProps(v: any): v is PhysicsProps;
|
|
@@ -11,10 +11,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
13
|
import { CapsuleCollider, RigidBody, useRapier } from "@react-three/rapier";
|
|
14
|
-
import {
|
|
15
|
-
import { useAssetRuntime, useEntityRuntime } from "../
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
14
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
15
|
+
import { useAssetRuntime, useEntityRuntime } from "../assetRuntime";
|
|
16
|
+
import { usePrefabNode } from "../prefabStore";
|
|
17
|
+
import { BooleanField, FieldGroup, NumberField, SelectField, StringField, Vector3Field } from "./Input";
|
|
18
|
+
import { getNodeUserData } from "../types";
|
|
18
19
|
import { colors } from "../styles";
|
|
19
20
|
export function isPhysicsProps(v) {
|
|
20
21
|
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";
|
|
@@ -22,90 +23,6 @@ export function isPhysicsProps(v) {
|
|
|
22
23
|
const enabledAxesFallback = [true, true, true];
|
|
23
24
|
const capsuleRadiusFallback = 0.35;
|
|
24
25
|
const capsuleHalfHeightFallback = 0.45;
|
|
25
|
-
const PHYSICS_EVENT_OPTIONS = [
|
|
26
|
-
{
|
|
27
|
-
key: 'sensorEnterEventName',
|
|
28
|
-
label: 'Sensor Enter',
|
|
29
|
-
defaultName: 'sensor:enter',
|
|
30
|
-
requiresSensor: true,
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
key: 'sensorExitEventName',
|
|
34
|
-
label: 'Sensor Exit',
|
|
35
|
-
defaultName: 'sensor:exit',
|
|
36
|
-
requiresSensor: true,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
key: 'collisionEnterEventName',
|
|
40
|
-
label: 'Collision Enter',
|
|
41
|
-
defaultName: 'collision:enter',
|
|
42
|
-
requiresSensor: false,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
key: 'collisionExitEventName',
|
|
46
|
-
label: 'Collision Exit',
|
|
47
|
-
defaultName: 'collision:exit',
|
|
48
|
-
requiresSensor: false,
|
|
49
|
-
},
|
|
50
|
-
];
|
|
51
|
-
function getPhysicsEventOption(key) {
|
|
52
|
-
return PHYSICS_EVENT_OPTIONS.find(option => option.key === key);
|
|
53
|
-
}
|
|
54
|
-
function getConfiguredPhysicsEvents(values) {
|
|
55
|
-
return PHYSICS_EVENT_OPTIONS.filter(option => typeof values[option.key] === 'string' && values[option.key].trim().length > 0);
|
|
56
|
-
}
|
|
57
|
-
function getAvailablePhysicsEvents(values, currentKey) {
|
|
58
|
-
const configuredKeys = new Set(getConfiguredPhysicsEvents(values).map(option => option.key));
|
|
59
|
-
return PHYSICS_EVENT_OPTIONS
|
|
60
|
-
.filter(option => option.key === currentKey || !configuredKeys.has(option.key))
|
|
61
|
-
.map(option => ({ value: option.key, label: option.label }));
|
|
62
|
-
}
|
|
63
|
-
function PhysicsEventBindingsEditor({ values, onChange, }) {
|
|
64
|
-
const configuredEvents = getConfiguredPhysicsEvents(values);
|
|
65
|
-
const nextEventOptions = getAvailablePhysicsEvents(values);
|
|
66
|
-
const addEvent = (eventKey) => {
|
|
67
|
-
if (!eventKey)
|
|
68
|
-
return;
|
|
69
|
-
const option = getPhysicsEventOption(eventKey);
|
|
70
|
-
if (!option)
|
|
71
|
-
return;
|
|
72
|
-
onChange(Object.assign({ [option.key]: option.defaultName }, (option.requiresSensor ? { sensor: true } : null)));
|
|
73
|
-
};
|
|
74
|
-
const updateEventKey = (currentKey, nextKey) => {
|
|
75
|
-
const nextOption = getPhysicsEventOption(nextKey);
|
|
76
|
-
if (!nextOption)
|
|
77
|
-
return;
|
|
78
|
-
onChange(Object.assign({ [currentKey]: undefined, [nextOption.key]: values[currentKey] || nextOption.defaultName }, (nextOption.requiresSensor ? { sensor: true } : null)));
|
|
79
|
-
};
|
|
80
|
-
const updateEventName = (key, eventName) => {
|
|
81
|
-
onChange({ [key]: eventName });
|
|
82
|
-
};
|
|
83
|
-
const removeEvent = (key) => {
|
|
84
|
-
onChange({ [key]: undefined });
|
|
85
|
-
};
|
|
86
|
-
return (_jsx(ListEditor, { label: "Events", items: configuredEvents, onAdd: addEvent, addOptions: nextEventOptions, canAdd: nextEventOptions.length > 0, emptyMessage: "No physics events configured.", addButtonTitle: "Add physics event", addDisabledTitle: "All physics events already added", renderItem: (option) => {
|
|
87
|
-
var _a;
|
|
88
|
-
return (_jsxs("div", { style: {
|
|
89
|
-
display: 'flex',
|
|
90
|
-
flexDirection: 'column',
|
|
91
|
-
gap: 6,
|
|
92
|
-
padding: 8,
|
|
93
|
-
border: `1px solid ${colors.border}`,
|
|
94
|
-
borderRadius: 4,
|
|
95
|
-
background: colors.bgSurface,
|
|
96
|
-
}, children: [_jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'end' }, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsx(SelectInput, { label: "Type", value: option.key, onChange: (nextKey) => updateEventKey(option.key, nextKey), options: getAvailablePhysicsEvents(values, option.key) }) }), _jsx("button", { type: "button", onClick: () => removeEvent(option.key), style: {
|
|
97
|
-
height: 24,
|
|
98
|
-
width: 28,
|
|
99
|
-
borderRadius: 3,
|
|
100
|
-
border: `1px solid ${colors.border}`,
|
|
101
|
-
background: colors.bgInput,
|
|
102
|
-
color: colors.text,
|
|
103
|
-
cursor: 'pointer',
|
|
104
|
-
padding: 0,
|
|
105
|
-
flexShrink: 0,
|
|
106
|
-
}, title: "Remove physics event", children: "\u00D7" })] }), _jsx(EventInput, { label: "Event Name", value: (_a = values[option.key]) !== null && _a !== void 0 ? _a : option.defaultName, onChange: (eventName) => updateEventName(option.key, eventName), placeholder: option.defaultName })] }, option.key));
|
|
107
|
-
} }));
|
|
108
|
-
}
|
|
109
26
|
function LockedAxisField({ label, name, values, onChange, }) {
|
|
110
27
|
const enabledAxes = Array.isArray(values[name])
|
|
111
28
|
? values[name]
|
|
@@ -158,15 +75,29 @@ function PhysicsComponentEditor({ component, onUpdate }) {
|
|
|
158
75
|
{ value: 'cuboid', label: 'Cuboid (box)' },
|
|
159
76
|
{ value: 'ball', label: 'Ball (sphere)' },
|
|
160
77
|
{ value: 'capsule', label: 'Capsule' },
|
|
161
|
-
] }), 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, _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(
|
|
78
|
+
] }), 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, _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: [
|
|
162
79
|
{ value: '', label: 'Default (Dynamic only)' },
|
|
163
80
|
{ value: 'all', label: 'All (includes kinematic & fixed)' },
|
|
164
81
|
] })] }));
|
|
165
82
|
}
|
|
83
|
+
function emitNativeEvent(type, detail) {
|
|
84
|
+
const trimmedType = type === null || type === void 0 ? void 0 : type.trim();
|
|
85
|
+
if (!trimmedType || typeof window === 'undefined')
|
|
86
|
+
return;
|
|
87
|
+
window.dispatchEvent(new CustomEvent(trimmedType, { detail }));
|
|
88
|
+
}
|
|
89
|
+
function getEntityIdFromRigidBody(rigidBody) {
|
|
90
|
+
const userData = rigidBody === null || rigidBody === void 0 ? void 0 : rigidBody.userData;
|
|
91
|
+
return typeof (userData === null || userData === void 0 ? void 0 : userData.entityId) === 'string' ? userData.entityId : null;
|
|
92
|
+
}
|
|
166
93
|
function PhysicsComponentView({ properties, children, position, rotation, scale }) {
|
|
94
|
+
var _a, _b, _c;
|
|
167
95
|
const { registerRigidBodyRef } = useAssetRuntime();
|
|
168
|
-
const { editMode, nodeId } = useEntityRuntime();
|
|
169
|
-
const
|
|
96
|
+
const { editMode, nodeId, getObject } = useEntityRuntime();
|
|
97
|
+
const gameObject = usePrefabNode(nodeId);
|
|
98
|
+
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 : '';
|
|
99
|
+
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));
|
|
100
|
+
const { type, colliders, sensor, activeCollisionTypes, linearVelocity = [0, 0, 0], angularVelocity = [0, 0, 0], 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", "activeCollisionTypes", "linearVelocity", "angularVelocity", "capsuleRadius", "capsuleHalfHeight", "emitSensorEnterEvent", "sensorEnterEventName", "emitSensorExitEvent", "sensorExitEventName", "emitCollisionEnterEvent", "collisionEnterEventName", "emitCollisionExitEvent", "collisionExitEventName", "enabledTranslations", "enabledRotations"]);
|
|
170
101
|
const colliderType = colliders || (type === 'fixed' ? 'trimesh' : 'hull');
|
|
171
102
|
const usesManualCapsuleCollider = colliderType === 'capsule';
|
|
172
103
|
const rigidBodyRef = useRef(null);
|
|
@@ -175,6 +106,12 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
175
106
|
const rbKey = editMode
|
|
176
107
|
? `${type || 'dynamic'}_${colliderType}_${capsuleRadius}_${capsuleHalfHeight}_${position === null || position === void 0 ? void 0 : position.join(',')}_${rotation === null || rotation === void 0 ? void 0 : rotation.join(',')}`
|
|
177
108
|
: `${type || 'dynamic'}_${colliderType}_${capsuleRadius}_${capsuleHalfHeight}`;
|
|
109
|
+
const handleRigidBodyRef = useCallback((rigidBody) => {
|
|
110
|
+
rigidBodyRef.current = rigidBody;
|
|
111
|
+
if (!nodeId)
|
|
112
|
+
return;
|
|
113
|
+
registerRigidBodyRef(nodeId, rigidBody);
|
|
114
|
+
}, [nodeId, registerRigidBodyRef]);
|
|
178
115
|
// Try to get rapier context - will be null if not inside <Physics>
|
|
179
116
|
let rapier = null;
|
|
180
117
|
try {
|
|
@@ -184,17 +121,6 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
184
121
|
catch (e) {
|
|
185
122
|
// Not inside Physics context - that's ok, just won't have rapier features
|
|
186
123
|
}
|
|
187
|
-
// Register RigidBody ref when it's available
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
if (nodeId && rigidBodyRef.current) {
|
|
190
|
-
registerRigidBodyRef(nodeId, rigidBodyRef.current);
|
|
191
|
-
}
|
|
192
|
-
return () => {
|
|
193
|
-
if (nodeId) {
|
|
194
|
-
registerRigidBodyRef(nodeId, null);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
}, [nodeId, registerRigidBodyRef]);
|
|
198
124
|
// Configure active collision types for kinematic/sensor bodies
|
|
199
125
|
useEffect(() => {
|
|
200
126
|
if (activeCollisionTypes === 'all' && rigidBodyRef.current && rapier) {
|
|
@@ -227,44 +153,47 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
227
153
|
z: angularVelocity[2],
|
|
228
154
|
}, true);
|
|
229
155
|
}, [rbKey, angularVelocityKey]);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (!nodeId
|
|
156
|
+
const dispatchPhysicsEvent = useCallback((eventType, payload) => {
|
|
157
|
+
var _a, _b, _c;
|
|
158
|
+
if (!nodeId)
|
|
233
159
|
return;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
160
|
+
emitNativeEvent(eventType, {
|
|
161
|
+
sourceNodeId: nodeId,
|
|
162
|
+
sourceObject: getObject(),
|
|
163
|
+
sourceRigidBody: rigidBodyRef.current,
|
|
164
|
+
targetNodeId: getEntityIdFromRigidBody(payload.other.rigidBody),
|
|
165
|
+
targetObject: (_b = (_a = payload.other.rigidBodyObject) !== null && _a !== void 0 ? _a : payload.other.colliderObject) !== null && _b !== void 0 ? _b : null,
|
|
166
|
+
targetRigidBody: (_c = payload.other.rigidBody) !== null && _c !== void 0 ? _c : null,
|
|
167
|
+
rapierEvent: payload,
|
|
238
168
|
});
|
|
239
|
-
}, [
|
|
169
|
+
}, [getObject, nodeId]);
|
|
170
|
+
const handleIntersectionEnter = useCallback((payload) => {
|
|
171
|
+
if (!emitSensorEnterEvent)
|
|
172
|
+
return;
|
|
173
|
+
dispatchPhysicsEvent(sensorEnterEventName, payload);
|
|
174
|
+
}, [dispatchPhysicsEvent, emitSensorEnterEvent, sensorEnterEventName]);
|
|
240
175
|
const handleIntersectionExit = useCallback((payload) => {
|
|
241
|
-
if (!
|
|
176
|
+
if (!emitSensorExitEvent)
|
|
242
177
|
return;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
targetEntityId: getEntityIdFromRigidBody(payload.other.rigidBody),
|
|
246
|
-
targetRigidBody: payload.other.rigidBody,
|
|
247
|
-
});
|
|
248
|
-
}, [nodeId, sensorExitEventName]);
|
|
178
|
+
dispatchPhysicsEvent(sensorExitEventName, payload);
|
|
179
|
+
}, [dispatchPhysicsEvent, emitSensorExitEvent, sensorExitEventName]);
|
|
249
180
|
const handleCollisionEnter = useCallback((payload) => {
|
|
250
|
-
if (!
|
|
181
|
+
if (!emitCollisionEnterEvent)
|
|
251
182
|
return;
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
targetEntityId: getEntityIdFromRigidBody(payload.other.rigidBody),
|
|
255
|
-
targetRigidBody: payload.other.rigidBody,
|
|
256
|
-
});
|
|
257
|
-
}, [collisionEnterEventName, nodeId]);
|
|
183
|
+
dispatchPhysicsEvent(collisionEnterEventName, payload);
|
|
184
|
+
}, [collisionEnterEventName, dispatchPhysicsEvent, emitCollisionEnterEvent]);
|
|
258
185
|
const handleCollisionExit = useCallback((payload) => {
|
|
259
|
-
if (!
|
|
186
|
+
if (!emitCollisionExitEvent)
|
|
260
187
|
return;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
188
|
+
dispatchPhysicsEvent(collisionExitEventName, payload);
|
|
189
|
+
}, [collisionExitEventName, dispatchPhysicsEvent, emitCollisionExitEvent]);
|
|
190
|
+
const rigidBodyProps = Object.assign({ ref: handleRigidBodyRef, type, colliders: usesManualCapsuleCollider ? false : colliderType, position,
|
|
191
|
+
rotation,
|
|
192
|
+
scale,
|
|
193
|
+
sensor,
|
|
194
|
+
enabledTranslations,
|
|
195
|
+
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);
|
|
196
|
+
return (_jsxs(RigidBody, Object.assign({}, rigidBodyProps, { children: [usesManualCapsuleCollider ? _jsx(CapsuleCollider, { args: [capsuleHalfHeight, capsuleRadius], sensor: sensor }) : null, children] }), rbKey));
|
|
268
197
|
}
|
|
269
198
|
const PhysicsComponent = {
|
|
270
199
|
name: 'Physics',
|
|
@@ -279,6 +208,14 @@ const PhysicsComponent = {
|
|
|
279
208
|
angularVelocity: [0, 0, 0],
|
|
280
209
|
enabledTranslations: [true, true, true],
|
|
281
210
|
enabledRotations: [true, true, true],
|
|
211
|
+
emitSensorEnterEvent: false,
|
|
212
|
+
sensorEnterEventName: '',
|
|
213
|
+
emitSensorExitEvent: false,
|
|
214
|
+
sensorExitEventName: '',
|
|
215
|
+
emitCollisionEnterEvent: false,
|
|
216
|
+
collisionEnterEventName: '',
|
|
217
|
+
emitCollisionExitEvent: false,
|
|
218
|
+
collisionExitEventName: '',
|
|
282
219
|
}
|
|
283
220
|
};
|
|
284
221
|
export default PhysicsComponent;
|
|
@@ -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 { useEntityRuntime } from '../
|
|
5
|
+
import { useEntityRuntime } from '../assetRuntime';
|
|
6
6
|
import { BooleanField, ColorField, NumberField } from './Input';
|
|
7
7
|
import { LightSection, ShadowBiasField, mergeWithDefaults } from './lightUtils';
|
|
8
8
|
const pointLightDefaults = {
|