@needle-tools/engine 4.9.0-next.ce04b9f → 4.9.1
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/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-DHAUN6T_.umd.cjs → needle-engine.bundle-BuTUhZAc.umd.cjs} +133 -133
- package/dist/{needle-engine.bundle-a5_4RZjH.min.js → needle-engine.bundle-DoywABnJ.min.js} +135 -135
- package/dist/{needle-engine.bundle-qHhlH-u4.js → needle-engine.bundle-O7rlGMn7.js} +6332 -6224
- package/dist/needle-engine.js +2 -2
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_gameobject.d.ts +7 -7
- package/lib/engine/engine_gameobject.js +88 -27
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.js +23 -6
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +2 -2
- package/lib/engine/engine_serialization_core.js +7 -7
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_serialization_decorator.js +2 -1
- package/lib/engine/engine_serialization_decorator.js.map +1 -1
- package/lib/engine-components/Component.d.ts +8 -5
- package/lib/engine-components/Component.js +8 -5
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +7 -6
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/physics/Attractor.d.ts +12 -0
- package/lib/engine-components/physics/Attractor.js +14 -2
- package/lib/engine-components/physics/Attractor.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.d.ts +1 -0
- package/lib/engine-components/web/Clickthrough.js +4 -2
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +9 -0
- package/lib/engine-components/web/CursorFollow.js +17 -0
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +66 -4
- package/lib/engine-components/web/ScrollFollow.js +155 -18
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/package.json +3 -3
- package/plugins/vite/build.js +3 -0
- package/src/engine/engine_gameobject.ts +105 -38
- package/src/engine/engine_networking_instantiate.ts +21 -6
- package/src/engine/engine_serialization_core.ts +9 -9
- package/src/engine/engine_serialization_decorator.ts +2 -1
- package/src/engine-components/Component.ts +8 -5
- package/src/engine-components/Renderer.ts +12 -10
- package/src/engine-components/physics/Attractor.ts +14 -4
- package/src/engine-components/web/Clickthrough.ts +6 -2
- package/src/engine-components/web/CursorFollow.ts +17 -2
- package/src/engine-components/web/ScrollFollow.ts +174 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/ScrollFollow.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ScrollFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/ScrollFollow.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.1",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
|
|
5
5
|
"main": "dist/needle-engine.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
],
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@dimforge/rapier3d-compat": "^0.19.0",
|
|
96
|
-
"@needle-tools/gltf-progressive": "3.3.
|
|
96
|
+
"@needle-tools/gltf-progressive": "3.3.4",
|
|
97
97
|
"@needle-tools/three-animation-pointer": "1.0.2",
|
|
98
98
|
"@webxr-input-profiles/motion-controllers": "^1.0.0",
|
|
99
99
|
"flatbuffers": "2.0.4",
|
|
@@ -168,4 +168,4 @@
|
|
|
168
168
|
"module": "lib/needle-engine.js",
|
|
169
169
|
"typings": "lib/needle-engine.d.ts",
|
|
170
170
|
"types": "lib/needle-engine.d.ts"
|
|
171
|
-
}
|
|
171
|
+
}
|
package/plugins/vite/build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bone, Object3D, Quaternion, SkinnedMesh, Vector3 } from "three";
|
|
1
|
+
import { Bone, Euler, Object3D, Quaternion, SkinnedMesh, Vector3 } from "three";
|
|
2
2
|
|
|
3
3
|
import { $shadowDomOwner } from "../engine-components/ui/Symbols.js";
|
|
4
4
|
import { type AssetReference } from "./engine_addressables.js";
|
|
@@ -11,7 +11,7 @@ import { processNewScripts } from "./engine_mainloop_utils.js";
|
|
|
11
11
|
import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
|
|
12
12
|
import { assign, ISerializable } from "./engine_serialization_core.js";
|
|
13
13
|
import { Context, registerComponent } from "./engine_setup.js";
|
|
14
|
-
import { logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils.js";
|
|
14
|
+
import { getTempQuaternion, logHierarchy, setWorldPosition, setWorldQuaternion } from "./engine_three_utils.js";
|
|
15
15
|
import { type Constructor, type GuidsMap, type IComponent as Component, type IComponent, IEventList, type IGameObject as GameObject, type UIDProvider } from "./engine_types.js";
|
|
16
16
|
import { deepClone, getParam, tryFindObject } from "./engine_utils.js";
|
|
17
17
|
import { apply } from "./js-extensions/index.js";
|
|
@@ -24,12 +24,12 @@ export type IInstantiateOptions = {
|
|
|
24
24
|
//** parent guid or object */
|
|
25
25
|
parent?: string | Object3D;
|
|
26
26
|
/** position in local space. Set `keepWorldPosition` to true if this is world space */
|
|
27
|
-
position?: Vector3;
|
|
27
|
+
position?: Vector3 | [number, number, number];
|
|
28
28
|
/** for duplicatable parenting */
|
|
29
29
|
keepWorldPosition?: boolean;
|
|
30
30
|
/** rotation in local space. Set `keepWorldPosition` to true if this is world space */
|
|
31
|
-
rotation?: Quaternion;
|
|
32
|
-
scale?: Vector3;
|
|
31
|
+
rotation?: Quaternion | Euler | [number, number, number];
|
|
32
|
+
scale?: Vector3 | [number, number, number];
|
|
33
33
|
/** if the instantiated object should be visible */
|
|
34
34
|
visible?: boolean;
|
|
35
35
|
context?: Context;
|
|
@@ -46,9 +46,9 @@ export class InstantiateOptions implements IInstantiateOptions {
|
|
|
46
46
|
idProvider?: UIDProvider | undefined;
|
|
47
47
|
parent?: string | undefined | Object3D;
|
|
48
48
|
keepWorldPosition?: boolean
|
|
49
|
-
position?: Vector3 | undefined;
|
|
50
|
-
rotation?: Quaternion | undefined;
|
|
51
|
-
scale?: Vector3 | undefined;
|
|
49
|
+
position?: Vector3 | [number, number, number] | undefined;
|
|
50
|
+
rotation?: Quaternion | Euler | [number, number, number] | undefined;
|
|
51
|
+
scale?: Vector3 | [number, number, number] | undefined;
|
|
52
52
|
visible?: boolean | undefined;
|
|
53
53
|
context?: Context | undefined;
|
|
54
54
|
components?: boolean | undefined;
|
|
@@ -58,9 +58,9 @@ export class InstantiateOptions implements IInstantiateOptions {
|
|
|
58
58
|
clone.idProvider = this.idProvider;
|
|
59
59
|
clone.parent = this.parent;
|
|
60
60
|
clone.keepWorldPosition = this.keepWorldPosition;
|
|
61
|
-
clone.position = this.position?.clone();
|
|
62
|
-
clone.rotation = this.rotation?.clone();
|
|
63
|
-
clone.scale = this.scale?.clone();
|
|
61
|
+
clone.position = Array.isArray(this.position) ? [...this.position] : this.position?.clone();
|
|
62
|
+
clone.rotation = Array.isArray(this.rotation) ? [...this.rotation] : this.rotation?.clone();
|
|
63
|
+
clone.scale = Array.isArray(this.scale) ? [...this.scale] : this.scale?.clone();
|
|
64
64
|
clone.visible = this.visible;
|
|
65
65
|
clone.context = this.context;
|
|
66
66
|
clone.components = this.components;
|
|
@@ -72,9 +72,9 @@ export class InstantiateOptions implements IInstantiateOptions {
|
|
|
72
72
|
this.idProvider = other.idProvider;
|
|
73
73
|
this.parent = other.parent;
|
|
74
74
|
this.keepWorldPosition = other.keepWorldPosition;
|
|
75
|
-
this.position = other.position?.clone();
|
|
76
|
-
this.rotation = other.rotation?.clone();
|
|
77
|
-
this.scale = other.scale?.clone();
|
|
75
|
+
this.position = Array.isArray(other.position) ? [...other.position] : other.position?.clone();
|
|
76
|
+
this.rotation = Array.isArray(other.rotation) ? [...other.rotation] : other.rotation?.clone();
|
|
77
|
+
this.scale = Array.isArray(other.scale) ? [...other.scale] : other.scale?.clone();
|
|
78
78
|
this.visible = other.visible;
|
|
79
79
|
this.context = other.context;
|
|
80
80
|
this.components = other.components;
|
|
@@ -287,6 +287,8 @@ declare type ObjectCloneReference = {
|
|
|
287
287
|
|
|
288
288
|
|
|
289
289
|
declare type InstantiateReferenceMap = Record<string, ObjectCloneReference>;
|
|
290
|
+
declare type NewObjectReferenceMap = Record<string, { target: object, key: string }>;
|
|
291
|
+
|
|
290
292
|
/**
|
|
291
293
|
* Provides access to the instantiated object and its clone
|
|
292
294
|
*/
|
|
@@ -325,13 +327,13 @@ export function instantiate(instance: AssetReference | GameObject | Object3D, op
|
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
const components: Array<Component> = [];
|
|
328
|
-
const
|
|
330
|
+
const referencemap: InstantiateReferenceMap = {}; // used to resolve references on components to components on other gameobjects to their new counterpart
|
|
329
331
|
const skinnedMeshes: InstantiateReferenceMap = {}; // used to resolve skinned mesh bones
|
|
330
|
-
const clone = internalInstantiate(context, instance, options, components,
|
|
332
|
+
const clone = internalInstantiate(context, instance, options, components, referencemap, skinnedMeshes);
|
|
331
333
|
|
|
332
334
|
if (clone) {
|
|
333
|
-
resolveReferences(
|
|
334
|
-
resolveAndBindSkinnedMeshBones(skinnedMeshes,
|
|
335
|
+
resolveReferences(clone, referencemap);
|
|
336
|
+
resolveAndBindSkinnedMeshBones(skinnedMeshes, referencemap);
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
if (debug) {
|
|
@@ -426,19 +428,45 @@ function internalInstantiate(
|
|
|
426
428
|
parent.add(clone);
|
|
427
429
|
}
|
|
428
430
|
|
|
429
|
-
//
|
|
431
|
+
// POSITION
|
|
430
432
|
if (opts?.position) {
|
|
431
|
-
|
|
433
|
+
if (Array.isArray(opts.position)) {
|
|
434
|
+
const vec = new Vector3();
|
|
435
|
+
vec.fromArray(opts.position);
|
|
436
|
+
clone.worldPosition = vec;
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
clone.worldPosition = opts.position;
|
|
440
|
+
}
|
|
432
441
|
}
|
|
433
442
|
else clone.position.copy(instance.position);
|
|
443
|
+
|
|
444
|
+
// ROTATION
|
|
434
445
|
if (opts?.rotation) {
|
|
435
|
-
|
|
446
|
+
if (opts.rotation instanceof Quaternion)
|
|
447
|
+
clone.worldQuaternion = opts.rotation;
|
|
448
|
+
else if (opts.rotation instanceof Euler)
|
|
449
|
+
clone.worldQuaternion = getTempQuaternion().setFromEuler(opts.rotation);
|
|
450
|
+
else if (Array.isArray(opts.rotation)) {
|
|
451
|
+
const euler = new Euler();
|
|
452
|
+
euler.fromArray(opts.rotation);
|
|
453
|
+
clone.worldQuaternion = getTempQuaternion().setFromEuler(euler);
|
|
454
|
+
}
|
|
436
455
|
}
|
|
437
456
|
else clone.quaternion.copy(instance.quaternion);
|
|
457
|
+
|
|
458
|
+
// SCALE
|
|
438
459
|
if (opts?.scale) {
|
|
439
|
-
clone.scale.copy(opts.scale);
|
|
440
460
|
// TODO MAJOR: replace with worldscale
|
|
441
461
|
// clone.worldScale = opts.scale;
|
|
462
|
+
if (Array.isArray(opts.scale)) {
|
|
463
|
+
const vec = new Vector3();
|
|
464
|
+
vec.fromArray(opts.scale);
|
|
465
|
+
opts.scale = vec;
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
clone.scale.copy(opts.scale);
|
|
469
|
+
}
|
|
442
470
|
}
|
|
443
471
|
else clone.scale.copy(instance.scale);
|
|
444
472
|
|
|
@@ -470,17 +498,7 @@ function internalInstantiate(
|
|
|
470
498
|
for (let i = 0; i < components.length; i++) {
|
|
471
499
|
const comp = components[i];
|
|
472
500
|
const copy = new comp.constructor();
|
|
473
|
-
|
|
474
|
-
// onAssign: (source, key, value) => {
|
|
475
|
-
// if (typeof value === "object") {
|
|
476
|
-
// const serializable = source as ISerializable;
|
|
477
|
-
// if (serializable?.$serializedTypes?.[key]) {
|
|
478
|
-
// console.debug("TODO CLONE", key, value);
|
|
479
|
-
// }
|
|
480
|
-
// }
|
|
481
|
-
// return value;
|
|
482
|
-
// }
|
|
483
|
-
});
|
|
501
|
+
onAssignComponent(comp, copy, objectsMap);
|
|
484
502
|
// make sure the original guid stays intact
|
|
485
503
|
if (comp[editorGuidKeyName] !== undefined)
|
|
486
504
|
copy[editorGuidKeyName] = comp[editorGuidKeyName];
|
|
@@ -501,7 +519,6 @@ function internalInstantiate(
|
|
|
501
519
|
opts.parent = undefined;
|
|
502
520
|
opts.visible = undefined;
|
|
503
521
|
}
|
|
504
|
-
|
|
505
522
|
for (const ch in instance.children) {
|
|
506
523
|
const child = instance.children[ch];
|
|
507
524
|
const newChild = internalInstantiate(context, child as GameObject, opts, componentsList, objectsMap, skinnedMeshesMap);
|
|
@@ -510,11 +527,59 @@ function internalInstantiate(
|
|
|
510
527
|
clone.add(newChild);
|
|
511
528
|
}
|
|
512
529
|
}
|
|
513
|
-
|
|
514
530
|
return clone;
|
|
531
|
+
}
|
|
532
|
+
|
|
515
533
|
|
|
534
|
+
function onAssignComponent(source: any, target: any, _newObjectsMap: InstantiateReferenceMap) {
|
|
535
|
+
assign(target, source, undefined, {
|
|
536
|
+
// onAssigned: (target, key, _oldValue, value) => {
|
|
537
|
+
// if (value !== null && typeof value === "object") {
|
|
538
|
+
// const serializable = target as ISerializable;
|
|
539
|
+
// if (serializable?.$serializedTypes?.[key]) {
|
|
540
|
+
// if (!(value instanceof Object3D)) {
|
|
541
|
+
// // let clone = null;
|
|
542
|
+
// // if ("clone" in value) {
|
|
543
|
+
// // if (canClone(value)) clone = (value as any).clone();
|
|
544
|
+
// // }
|
|
545
|
+
// // else {
|
|
546
|
+
// // clone = Object.assign(Object.create(Object.getPrototypeOf(value)), value);
|
|
547
|
+
// // }
|
|
548
|
+
// // if (clone) {
|
|
549
|
+
// // console.debug(key, { target, value, clone })
|
|
550
|
+
// // target[key] = clone;
|
|
551
|
+
// // findNestedReferences(clone, objectsMap);
|
|
552
|
+
// // }
|
|
553
|
+
// // else console.debug("Could not clone value for key", key, value);
|
|
554
|
+
// }
|
|
555
|
+
// else {
|
|
556
|
+
// console.log("ASSIGNED", value)
|
|
557
|
+
// }
|
|
558
|
+
|
|
559
|
+
// recursiveAssign(target, target[key], newObjectsMap);
|
|
560
|
+
// }
|
|
561
|
+
|
|
562
|
+
// }
|
|
563
|
+
// }
|
|
564
|
+
});
|
|
516
565
|
}
|
|
517
566
|
|
|
567
|
+
// function findNestedReferences(object: object, map: InstantiateReferenceMap) {
|
|
568
|
+
// const keys = Object.keys(object);
|
|
569
|
+
// for (const key of keys) {
|
|
570
|
+
// const val = (object as any)[key];
|
|
571
|
+
// if (val instanceof Object3D) {
|
|
572
|
+
// if ("guid" in val && val.guid) {
|
|
573
|
+
// console.log("FOUND ", val.guid, val)
|
|
574
|
+
// map[val.guid] = { original: val, clone: null };
|
|
575
|
+
// }
|
|
576
|
+
// }
|
|
577
|
+
// else if (typeof val === "object" && val !== null) {
|
|
578
|
+
// findNestedReferences(val, map);
|
|
579
|
+
// }
|
|
580
|
+
// }
|
|
581
|
+
// }
|
|
582
|
+
|
|
518
583
|
function resolveAndBindSkinnedMeshBones(
|
|
519
584
|
skinnedMeshes: { [key: string]: ObjectCloneReference },
|
|
520
585
|
newObjectsMap: { [key: string]: ObjectCloneReference }
|
|
@@ -599,13 +664,13 @@ function resolveAndBindSkinnedMeshBones(
|
|
|
599
664
|
|
|
600
665
|
// }
|
|
601
666
|
|
|
602
|
-
function resolveReferences(newObjectsMap: InstantiateReferenceMap) {
|
|
667
|
+
function resolveReferences(_newInstance: Object3D, newObjectsMap: InstantiateReferenceMap) {
|
|
603
668
|
// for every object that is newly created we want to update references to their newly created counterparts
|
|
604
669
|
// e.g. a collider instance referencing a rigidbody instance should be updated so that
|
|
605
670
|
// the cloned collider does not reference the cloned rigidbody (instead of the original rigidbody)
|
|
606
671
|
for (const key in newObjectsMap) {
|
|
607
672
|
const val = newObjectsMap[key];
|
|
608
|
-
const clone = val.clone as Object3D;
|
|
673
|
+
const clone = val.clone as Object3D | null;
|
|
609
674
|
// resolve references
|
|
610
675
|
if (clone?.isObject3D && clone?.userData?.components) {
|
|
611
676
|
for (let i = 0; i < clone.userData.components.length; i++) {
|
|
@@ -706,4 +771,6 @@ function postProcessNewInstance(copy: Object3D, key: string, value: IComponent |
|
|
|
706
771
|
return copy;
|
|
707
772
|
}
|
|
708
773
|
}
|
|
709
|
-
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// const canClone = (value: any) => value.isVector4 || value.isVector3 || value.isVector2 || value.isQuaternion || value.isEuler || value.isColor === true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Object3D, Quaternion, Vector3 } from "three";
|
|
1
|
+
import { Euler, Object3D, Quaternion, Vector3 } from "three";
|
|
2
2
|
// https://github.com/uuidjs/uuid
|
|
3
3
|
// v5 takes string and namespace
|
|
4
4
|
import { v5 } from 'uuid';
|
|
@@ -254,12 +254,27 @@ export function syncInstantiate(object: GameObject | Object3D, opts: SyncInstant
|
|
|
254
254
|
if (opts.deleteOnDisconnect === true)
|
|
255
255
|
model.deleteStateOnDisconnect = true;
|
|
256
256
|
if (originalOpts) {
|
|
257
|
-
if (originalOpts.position)
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
if (originalOpts.position) {
|
|
258
|
+
if (Array.isArray(originalOpts.position)) {
|
|
259
|
+
model.position = { x: originalOpts.position[0], y: originalOpts.position[1], z: originalOpts.position[2] };
|
|
260
|
+
}
|
|
261
|
+
else model.position = { x: originalOpts.position.x, y: originalOpts.position.y, z: originalOpts.position.z };
|
|
262
|
+
}
|
|
263
|
+
if (originalOpts.rotation) {
|
|
264
|
+
if (originalOpts.rotation instanceof Euler) {
|
|
265
|
+
originalOpts.rotation = new Quaternion().setFromEuler(originalOpts.rotation);
|
|
266
|
+
}
|
|
267
|
+
else if (originalOpts.rotation instanceof Array) {
|
|
268
|
+
originalOpts.rotation = new Quaternion().fromArray(originalOpts.rotation);
|
|
269
|
+
}
|
|
260
270
|
model.rotation = { x: originalOpts.rotation.x, y: originalOpts.rotation.y, z: originalOpts.rotation.z, w: originalOpts.rotation.w };
|
|
261
|
-
|
|
262
|
-
|
|
271
|
+
}
|
|
272
|
+
if (originalOpts.scale) {
|
|
273
|
+
if (Array.isArray(originalOpts.scale)) {
|
|
274
|
+
model.scale = { x: originalOpts.scale[0], y: originalOpts.scale[1], z: originalOpts.scale[2] };
|
|
275
|
+
}
|
|
276
|
+
else model.scale = { x: originalOpts.scale.x, y: originalOpts.scale.y, z: originalOpts.scale.z };
|
|
277
|
+
}
|
|
263
278
|
}
|
|
264
279
|
if (!model.position)
|
|
265
280
|
model.position = { x: go.position.x, y: go.position.y, z: go.position.z };
|
|
@@ -658,10 +658,10 @@ export const $isAssigningProperties = Symbol("assigned component properties");
|
|
|
658
658
|
* @param key the key that is being assigned
|
|
659
659
|
* @param value the value that is being assigned
|
|
660
660
|
*/
|
|
661
|
-
type
|
|
661
|
+
type AssignedCallback = (source: object, key: string, oldValue: any, newValue: any) => any;
|
|
662
662
|
|
|
663
663
|
/** Object.assign behaviour but check if property is writeable (e.g. getter only properties are skipped) */
|
|
664
|
-
export function assign(target: any, source: any, info?: ImplementationInformation, opts?: {
|
|
664
|
+
export function assign(target: any, source: any, info?: ImplementationInformation, opts?: { onAssigned?: AssignedCallback }) {
|
|
665
665
|
if (source === undefined || source === null) return;
|
|
666
666
|
if (target === undefined || target === null) return;
|
|
667
667
|
|
|
@@ -699,13 +699,13 @@ export function assign(target: any, source: any, info?: ImplementationInformatio
|
|
|
699
699
|
// arrow functions are defined as properties on the object
|
|
700
700
|
continue;
|
|
701
701
|
}
|
|
702
|
-
if (!desc || desc.writable === true) {
|
|
703
|
-
const
|
|
704
|
-
target[key]
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
702
|
+
if (!desc || desc.writable === true || desc.set !== undefined) {
|
|
703
|
+
const newValue = source[key];
|
|
704
|
+
const oldValue = target[key];
|
|
705
|
+
target[key] = newValue;
|
|
706
|
+
if (opts?.onAssigned) {
|
|
707
|
+
opts.onAssigned(target, key, oldValue, newValue);
|
|
708
|
+
}
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
delete target[$isAssigningProperties];
|
|
@@ -27,7 +27,8 @@ export const serializable = function <T>(type?: Constructor<T> | null | Array<Co
|
|
|
27
27
|
|
|
28
28
|
return function (_target: any, _propertyKey: string | { name: string }) {
|
|
29
29
|
if (!_target) {
|
|
30
|
-
|
|
30
|
+
const propertyName = typeof _propertyKey === 'string' ? _propertyKey : _propertyKey.name;
|
|
31
|
+
console.warn(`@serializable without a target at '${propertyName}'.`);
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
// The _propertyKey parameter is a string in TS4 with experimentalDecorators
|
|
@@ -543,22 +543,25 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
|
|
|
543
543
|
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
|
-
* Needle Engine component
|
|
546
|
+
* Needle Engine component's are the main building blocks of the Needle Engine.
|
|
547
547
|
* Derive from {@link Behaviour} to implement your own using the provided lifecycle methods.
|
|
548
548
|
* Components can be added to any {@link Object3D} using {@link addComponent} or {@link GameObject.addComponent}.
|
|
549
549
|
*
|
|
550
|
-
*
|
|
550
|
+
* **Component lifecycle event methods:**
|
|
551
|
+
* {@link awake}, {@link start}, {@link onEnable}, {@link onDisable}, {@link onDestroy}, {@link earlyUpdate}, {@link update}, {@link lateUpdate}, {@link onBeforeRender}, {@link onAfterRender}.
|
|
551
552
|
*
|
|
552
|
-
* XR
|
|
553
|
+
* **XR event methods:**
|
|
554
|
+
* {@link onEnterXR}, {@link onLeaveXR}, {@link onUpdateXR}, {@link onXRControllerAdded} and {@link onXRControllerRemoved}.
|
|
553
555
|
*
|
|
554
|
-
*
|
|
556
|
+
* **Input event methods:**
|
|
557
|
+
* {@link onPointerDown}, {@link onPointerUp}, {@link onPointerEnter}, {@link onPointerExit} and {@link onPointerMove}.
|
|
555
558
|
*
|
|
556
559
|
* @example
|
|
557
560
|
* ```typescript
|
|
558
561
|
* import { Behaviour } from "@needle-tools/engine";
|
|
559
562
|
* export class MyComponent extends Behaviour {
|
|
560
563
|
* start() {
|
|
561
|
-
* console.log("Hello World");
|
|
564
|
+
* console.log("Hello World", this.gameObject.name);
|
|
562
565
|
* }
|
|
563
566
|
* update() {
|
|
564
567
|
* console.log("Frame", this.context.time.frame);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getRaycastMesh } from "@needle-tools/gltf-progressive";
|
|
2
|
-
import { AxesHelper, Material, Mesh, Object3D, SkinnedMesh, Texture, Vector4 } from "three";
|
|
2
|
+
import { AxesHelper, Material, Mesh, MeshBasicMaterial, MeshPhysicalMaterial, MeshStandardMaterial, Object3D, RawShaderMaterial, ShaderMaterial, SkinnedMesh, Texture, Vector4 } from "three";
|
|
3
3
|
|
|
4
4
|
import { showBalloonWarning } from "../engine/debug/index.js";
|
|
5
5
|
import { getComponent, getOrAddComponent } from "../engine/engine_components.js";
|
|
@@ -48,6 +48,8 @@ export enum RenderState {
|
|
|
48
48
|
Front = 2,
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
type SharedMaterial = (Material & Partial<MeshStandardMaterial> & Partial<MeshPhysicalMaterial> & Partial<ShaderMaterial> & Partial<RawShaderMaterial>);
|
|
52
|
+
|
|
51
53
|
|
|
52
54
|
// support sharedMaterials[index] assigning materials directly to the objects
|
|
53
55
|
class SharedMaterialArray implements ISharedMaterials {
|
|
@@ -185,7 +187,7 @@ class SharedMaterialArray implements ISharedMaterials {
|
|
|
185
187
|
this.changed = true;
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
private getMaterial(index: number):
|
|
190
|
+
private getMaterial(index: number): SharedMaterial | null {
|
|
189
191
|
index = this.resolveIndex(index);
|
|
190
192
|
if (index < 0) return null;
|
|
191
193
|
const obj = this._targets;
|
|
@@ -302,11 +304,11 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
302
304
|
return this._sharedMeshes;
|
|
303
305
|
}
|
|
304
306
|
|
|
305
|
-
get sharedMaterial():
|
|
306
|
-
return this.sharedMaterials[0];
|
|
307
|
+
get sharedMaterial(): SharedMaterial {
|
|
308
|
+
return this.sharedMaterials[0] as SharedMaterial;
|
|
307
309
|
}
|
|
308
310
|
|
|
309
|
-
set sharedMaterial(mat:
|
|
311
|
+
set sharedMaterial(mat: SharedMaterial) {
|
|
310
312
|
const cur = this.sharedMaterials[0];
|
|
311
313
|
if (cur === mat) return;
|
|
312
314
|
this.sharedMaterials[0] = mat;
|
|
@@ -314,12 +316,12 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
314
316
|
}
|
|
315
317
|
|
|
316
318
|
/**@deprecated please use sharedMaterial */
|
|
317
|
-
get material():
|
|
318
|
-
return this.sharedMaterials[0];
|
|
319
|
+
get material(): SharedMaterial {
|
|
320
|
+
return this.sharedMaterials[0] as SharedMaterial;
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
/**@deprecated please use sharedMaterial */
|
|
322
|
-
set material(mat:
|
|
324
|
+
set material(mat: SharedMaterial) {
|
|
323
325
|
this.sharedMaterial = mat;
|
|
324
326
|
}
|
|
325
327
|
|
|
@@ -329,10 +331,10 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
329
331
|
private _probeAnchorLastFrame?: Object3D;
|
|
330
332
|
|
|
331
333
|
// this is just available during deserialization
|
|
332
|
-
private set sharedMaterials(_val: Array<
|
|
334
|
+
private set sharedMaterials(_val: Array<SharedMaterial | null>) {
|
|
333
335
|
// TODO: elements in the array might be missing at the moment which leads to problems if an index is serialized
|
|
334
336
|
if (!this._originalMaterials) {
|
|
335
|
-
this._originalMaterials = _val as
|
|
337
|
+
this._originalMaterials = _val as SharedMaterial[];
|
|
336
338
|
}
|
|
337
339
|
else if (_val) {
|
|
338
340
|
let didWarn = false;
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
1
2
|
import { Behaviour } from "../Component.js";
|
|
2
3
|
import { Rigidbody } from "../RigidBody.js";
|
|
3
|
-
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
4
|
-
|
|
5
4
|
|
|
6
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Used to attract Rigidbodies towards the position of this component.
|
|
8
|
+
* Add Rigidbodies to the `targets` array to have them be attracted.
|
|
9
|
+
* You can use negative strength values to create a repulsion effect.
|
|
10
|
+
*
|
|
11
|
+
* @example Attractor component attracting a Rigidbody
|
|
12
|
+
* ```ts
|
|
13
|
+
* const attractor = object.addComponent(Attractor);
|
|
14
|
+
* attractor.strength = 5; // positive value to attract
|
|
15
|
+
* attractor.radius = 10; // only attract within 10 units
|
|
16
|
+
* attractor.targets.push(rigidbody); // add the Rigidbody to be attracted
|
|
17
|
+
*/
|
|
7
18
|
export class Attractor extends Behaviour {
|
|
8
19
|
|
|
9
20
|
@serializable()
|
|
@@ -15,11 +26,10 @@ export class Attractor extends Behaviour {
|
|
|
15
26
|
@serializable(Rigidbody)
|
|
16
27
|
targets: Rigidbody[] = [];
|
|
17
28
|
|
|
18
|
-
|
|
19
29
|
update() {
|
|
20
30
|
const wp = this.gameObject.worldPosition;
|
|
21
31
|
const factor = -this.strength * this.context.time.deltaTime;
|
|
22
|
-
this.targets
|
|
32
|
+
this.targets?.forEach(t => {
|
|
23
33
|
if(!t) return;
|
|
24
34
|
const dir = t.gameObject.worldPosition.sub(wp);
|
|
25
35
|
const length = dir.length();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
|
-
import { Behaviour } from "../Component.js";
|
|
3
2
|
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
3
|
+
import { Behaviour } from "../Component.js";
|
|
4
4
|
|
|
5
5
|
// Automatically add ClickThrough component if "clickthrough" attribute is present on the needle-engine element
|
|
6
6
|
onStart(ctx => {
|
|
@@ -23,6 +23,9 @@ onStart(ctx => {
|
|
|
23
23
|
* @link Example https://stackblitz.com/~/github.com/needle-engine/sample-3d-over-html
|
|
24
24
|
*/
|
|
25
25
|
export class ClickThrough extends Behaviour {
|
|
26
|
+
|
|
27
|
+
private _previousPointerEvents: string = 'all';
|
|
28
|
+
|
|
26
29
|
onEnable() {
|
|
27
30
|
// Register for pointer down and pointer move event
|
|
28
31
|
this.context.input.addEventListener('pointerdown', this.onPointerEvent);
|
|
@@ -30,12 +33,13 @@ export class ClickThrough extends Behaviour {
|
|
|
30
33
|
queue: 100,
|
|
31
34
|
});
|
|
32
35
|
window.addEventListener("touchend", this.onTouchEnd, { passive: true });
|
|
36
|
+
this._previousPointerEvents = this.context.domElement.style.pointerEvents;
|
|
33
37
|
}
|
|
34
38
|
onDisable() {
|
|
35
39
|
this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
|
|
36
40
|
this.context.input.removeEventListener('pointermove', this.onPointerEvent);
|
|
37
41
|
window.removeEventListener("touchend", this.onTouchEnd);
|
|
38
|
-
this.context.domElement.style.pointerEvents =
|
|
42
|
+
this.context.domElement.style.pointerEvents = this._previousPointerEvents;
|
|
39
43
|
}
|
|
40
44
|
onPointerEnter() {
|
|
41
45
|
/** do nothing, necessary to raycast children */
|
|
@@ -2,7 +2,9 @@ import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
|
2
2
|
import { getTempVector } from "../../engine/engine_three_utils.js";
|
|
3
3
|
import { Behaviour } from "../Component.js";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The CursorFollow component makes the object follow the cursor (or touch) position on screen.
|
|
7
|
+
*/
|
|
6
8
|
export class CursorFollow extends Behaviour {
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -12,13 +14,26 @@ export class CursorFollow extends Behaviour {
|
|
|
12
14
|
@serializable()
|
|
13
15
|
damping: number = 0;
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* If true, the initial distance to the camera is maintained when following the cursor.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
@serializable()
|
|
22
|
+
keepDistance: boolean = true;
|
|
23
|
+
|
|
24
|
+
awake() {
|
|
25
|
+
this._distance = -1;
|
|
26
|
+
}
|
|
15
27
|
|
|
16
28
|
private _distance: number = -1;
|
|
29
|
+
|
|
17
30
|
updateDistance() {
|
|
31
|
+
if (this.keepDistance && this._distance !== -1) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
18
34
|
this._distance = this.gameObject.worldPosition.distanceTo(this.context.mainCamera.worldPosition);
|
|
19
35
|
}
|
|
20
36
|
|
|
21
|
-
|
|
22
37
|
/** @internal */
|
|
23
38
|
update() {
|
|
24
39
|
// continuously update distance in case camera or object moves
|