@needle-tools/engine 4.3.0-alpha → 4.3.0-alpha.3
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 +7 -0
- package/dist/needle-engine.bundle.js +6683 -5393
- package/dist/needle-engine.bundle.light.js +6687 -5397
- package/dist/needle-engine.bundle.light.min.js +121 -118
- package/dist/needle-engine.bundle.light.umd.cjs +128 -125
- package/dist/needle-engine.bundle.min.js +119 -116
- package/dist/needle-engine.bundle.umd.cjs +124 -121
- package/dist/needle-engine.d.ts +9 -9
- package/dist/needle-engine.light.d.ts +9 -9
- package/lib/engine/engine_context.js +1 -1
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +2 -4
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +1 -1
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_types.d.ts +162 -17
- package/lib/engine/xr/NeedleXRSession.d.ts +6 -1
- package/lib/engine/xr/NeedleXRSession.js +6 -1
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine-components/Animator.d.ts +129 -21
- package/lib/engine-components/Animator.js +115 -21
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.d.ts +161 -32
- package/lib/engine-components/AnimatorController.js +176 -29
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioListener.d.ts +16 -5
- package/lib/engine-components/AudioListener.js +16 -5
- package/lib/engine-components/AudioListener.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +120 -28
- package/lib/engine-components/AudioSource.js +121 -40
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/AvatarLoader.d.ts +61 -0
- package/lib/engine-components/AvatarLoader.js +61 -1
- package/lib/engine-components/AvatarLoader.js.map +1 -1
- package/lib/engine-components/AxesHelper.d.ts +19 -1
- package/lib/engine-components/AxesHelper.js +19 -1
- package/lib/engine-components/AxesHelper.js.map +1 -1
- package/lib/engine-components/BoxHelperComponent.d.ts +26 -0
- package/lib/engine-components/BoxHelperComponent.js +26 -0
- package/lib/engine-components/BoxHelperComponent.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +126 -37
- package/lib/engine-components/Camera.js +139 -37
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +20 -0
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +95 -21
- package/lib/engine-components/Collider.js +100 -23
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +554 -106
- package/lib/engine-components/Component.js +352 -81
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +95 -21
- package/lib/engine-components/DragControls.js +126 -32
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.d.ts +99 -16
- package/lib/engine-components/DropListener.js +119 -14
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/Light.d.ts +102 -5
- package/lib/engine-components/Light.js +102 -44
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/NeedleMenu.d.ts +28 -11
- package/lib/engine-components/NeedleMenu.js +28 -11
- package/lib/engine-components/NeedleMenu.js.map +1 -1
- package/lib/engine-components/Networking.d.ts +37 -5
- package/lib/engine-components/Networking.js +37 -5
- package/lib/engine-components/Networking.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +44 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/SpatialTrigger.d.ts +66 -1
- package/lib/engine-components/SpatialTrigger.js +74 -2
- package/lib/engine-components/SpatialTrigger.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +66 -4
- package/lib/engine-components/SpectatorCamera.js +132 -6
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SyncedTransform.d.ts +45 -6
- package/lib/engine-components/SyncedTransform.js +45 -6
- package/lib/engine-components/SyncedTransform.js.map +1 -1
- package/lib/engine-components/TransformGizmo.d.ts +49 -3
- package/lib/engine-components/TransformGizmo.js +49 -3
- package/lib/engine-components/TransformGizmo.js.map +1 -1
- package/lib/engine-components/particlesystem/ParticleSystem.js +1 -1
- package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +8 -3
- package/lib/engine-components/webxr/WebARSessionRoot.js +30 -9
- package/lib/engine-components/webxr/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/webxr/WebXR.d.ts +156 -25
- package/lib/engine-components/webxr/WebXR.js +160 -26
- package/lib/engine-components/webxr/WebXR.js.map +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.d.ts +82 -9
- package/lib/engine-components-experimental/networking/PlayerSync.js +76 -11
- package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_context.ts +1 -1
- package/src/engine/engine_mainloop_utils.ts +2 -4
- package/src/engine/engine_serialization_core.ts +1 -1
- package/src/engine/engine_types.ts +179 -18
- package/src/engine/xr/NeedleXRSession.ts +7 -1
- package/src/engine-components/Animator.ts +142 -22
- package/src/engine-components/AnimatorController.ts +184 -34
- package/src/engine-components/AudioListener.ts +16 -5
- package/src/engine-components/AudioSource.ts +127 -39
- package/src/engine-components/AvatarLoader.ts +61 -2
- package/src/engine-components/AxesHelper.ts +21 -1
- package/src/engine-components/BoxHelperComponent.ts +26 -0
- package/src/engine-components/Camera.ts +147 -41
- package/src/engine-components/CameraUtils.ts +20 -0
- package/src/engine-components/Collider.ts +102 -27
- package/src/engine-components/Component.ts +605 -129
- package/src/engine-components/DragControls.ts +134 -38
- package/src/engine-components/DropListener.ts +143 -23
- package/src/engine-components/Light.ts +105 -44
- package/src/engine-components/NeedleMenu.ts +29 -11
- package/src/engine-components/Networking.ts +37 -6
- package/src/engine-components/SceneSwitcher.ts +48 -1
- package/src/engine-components/SpatialTrigger.ts +80 -3
- package/src/engine-components/SpectatorCamera.ts +136 -18
- package/src/engine-components/SyncedTransform.ts +50 -7
- package/src/engine-components/TransformGizmo.ts +49 -4
- package/src/engine-components/particlesystem/ParticleSystem.ts +2 -2
- package/src/engine-components/webxr/WebARSessionRoot.ts +31 -8
- package/src/engine-components/webxr/WebXR.ts +173 -29
- package/src/engine-components-experimental/networking/PlayerSync.ts +85 -13
|
@@ -4,50 +4,68 @@ import { DeviceUtilities } from '../engine/engine_utils.js';
|
|
|
4
4
|
import { Behaviour } from './Component.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Provides configuration options for the built-in Needle Menu.
|
|
8
|
+
* Needle Menu uses HTML in 2D mode, and automatically switches to a 3D menu in VR/AR mode.
|
|
9
|
+
*
|
|
10
|
+
* Controls display options, button visibility, and menu positioning.
|
|
8
11
|
* From code, you can access the menu via {@link Context.menu}.
|
|
9
12
|
* @category User Interface
|
|
10
13
|
* @group Components
|
|
11
14
|
**/
|
|
12
15
|
export class NeedleMenu extends Behaviour {
|
|
13
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Determines the vertical positioning of the menu on the screen
|
|
19
|
+
*/
|
|
14
20
|
@serializable()
|
|
15
21
|
position: "top" | "bottom" = "bottom";
|
|
16
22
|
|
|
17
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Controls the visibility of the Needle logo in the menu (requires PRO license)
|
|
25
|
+
*/
|
|
18
26
|
@serializable()
|
|
19
27
|
showNeedleLogo: boolean = true;
|
|
20
28
|
|
|
21
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* When enabled, displays the menu in VR/AR mode when the user looks up
|
|
22
31
|
* @default undefined
|
|
23
|
-
|
|
32
|
+
*/
|
|
24
33
|
@serializable()
|
|
25
34
|
showSpatialMenu?: boolean;
|
|
26
35
|
|
|
27
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* When enabled, adds a fullscreen toggle button to the menu
|
|
28
38
|
* @default undefined
|
|
29
|
-
|
|
39
|
+
*/
|
|
30
40
|
@serializable()
|
|
31
41
|
createFullscreenButton?: boolean;
|
|
32
|
-
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* When enabled, adds an audio mute/unmute button to the menu
|
|
33
45
|
* @default undefined
|
|
34
|
-
|
|
46
|
+
*/
|
|
35
47
|
@serializable()
|
|
36
48
|
createMuteButton?: boolean;
|
|
37
49
|
|
|
38
50
|
/**
|
|
39
|
-
* When enabled a button to
|
|
51
|
+
* When enabled, adds a button to display a QR code for sharing the application.
|
|
52
|
+
* The QR code is only displayed on desktop devices.
|
|
40
53
|
* @default undefined
|
|
41
54
|
*/
|
|
42
55
|
@serializable()
|
|
43
56
|
createQRCodeButton?: boolean;
|
|
44
57
|
|
|
45
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Applies the configured menu options when the component is enabled
|
|
60
|
+
* @hidden
|
|
61
|
+
*/
|
|
46
62
|
onEnable() {
|
|
47
63
|
this.applyOptions();
|
|
48
64
|
}
|
|
49
65
|
|
|
50
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Applies all configured options to the active {@link Context.menu}.
|
|
68
|
+
*/
|
|
51
69
|
applyOptions() {
|
|
52
70
|
this.context.menu.setPosition(this.position);
|
|
53
71
|
this.context.menu.showNeedleLogo(this.showNeedleLogo);
|
|
@@ -7,21 +7,33 @@ import { Behaviour } from "./Component.js";
|
|
|
7
7
|
const debug = getParam("debugnet");
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Provides configuration to the built-in networking system.
|
|
11
|
+
* This component supplies websocket URLs for establishing connections.
|
|
12
|
+
* It implements the {@link INetworkingWebsocketUrlProvider} interface.
|
|
13
|
+
*
|
|
11
14
|
* @category Networking
|
|
12
15
|
* @group Components
|
|
13
16
|
*/
|
|
14
17
|
export class Networking extends Behaviour implements INetworkingWebsocketUrlProvider {
|
|
15
18
|
|
|
16
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* The websocket URL to connect to for networking functionality.
|
|
21
|
+
* Can be a complete URL or a relative path that will be resolved against the current origin.
|
|
22
|
+
*/
|
|
17
23
|
@serializable()
|
|
18
24
|
url: string | null = null;
|
|
19
25
|
|
|
20
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Name of the URL parameter that can override the websocket connection URL.
|
|
28
|
+
* When set, the URL will be overridden by the parameter value from the browser URL.
|
|
29
|
+
* For example, with `urlParameterName="ws"`, adding `?ws=ws://localhost:8080` to the browser URL will override the connection URL.
|
|
30
|
+
*/
|
|
21
31
|
@serializable()
|
|
22
32
|
urlParameterName: string | null = null;
|
|
23
33
|
|
|
24
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Alternative URL to use when running on a local network.
|
|
36
|
+
* This is particularly useful for development, when the server is running on the same machine as the client.
|
|
25
37
|
*/
|
|
26
38
|
@serializable()
|
|
27
39
|
localhost: string | null = null;
|
|
@@ -33,7 +45,13 @@ export class Networking extends Behaviour implements INetworkingWebsocketUrlProv
|
|
|
33
45
|
this.context.connection.registerProvider(this);
|
|
34
46
|
}
|
|
35
47
|
|
|
36
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Determines the websocket URL to use for networking connections.
|
|
50
|
+
* Processes the configured URL, applying localhost fallbacks when appropriate and
|
|
51
|
+
* handling URL parameter overrides if specified.
|
|
52
|
+
* @returns The formatted websocket URL string or null if no valid URL could be determined
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
37
55
|
getWebsocketUrl(): string | null {
|
|
38
56
|
|
|
39
57
|
let socketurl = this.url ? Networking.GetUrl(this.url, this.localhost) : null;
|
|
@@ -58,7 +76,13 @@ export class Networking extends Behaviour implements INetworkingWebsocketUrlProv
|
|
|
58
76
|
return "wss://" + match?.groups["url"];
|
|
59
77
|
}
|
|
60
78
|
|
|
61
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Processes a URL string applying various transformations based on network environment.
|
|
81
|
+
* Handles relative paths and localhost fallbacks for local network environments.
|
|
82
|
+
* @param url The original URL to process
|
|
83
|
+
* @param localhostFallback Alternative URL to use when on a local network
|
|
84
|
+
* @returns The processed URL string or null/undefined if input was invalid
|
|
85
|
+
*/
|
|
62
86
|
public static GetUrl(url: string | null | undefined, localhostFallback?: string | null): string | null | undefined {
|
|
63
87
|
|
|
64
88
|
let result = url;
|
|
@@ -78,6 +102,13 @@ export class Networking extends Behaviour implements INetworkingWebsocketUrlProv
|
|
|
78
102
|
return result;
|
|
79
103
|
}
|
|
80
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Determines if the current connection is on a local network.
|
|
107
|
+
* Useful for applying different networking configurations in local development environments.
|
|
108
|
+
* This is the same as calling {@link isLocalNetwork}.
|
|
109
|
+
* @param hostname Optional hostname to check instead of the current window location
|
|
110
|
+
* @returns True if the connection is on a local network, false otherwise
|
|
111
|
+
*/
|
|
81
112
|
public static IsLocalNetwork(hostname = window.location.hostname) {
|
|
82
113
|
return isLocalNetwork(hostname);
|
|
83
114
|
}
|
|
@@ -857,9 +857,18 @@ function sceneUriToName(uri: string): string {
|
|
|
857
857
|
|
|
858
858
|
|
|
859
859
|
|
|
860
|
+
/**
|
|
861
|
+
* PreLoadScheduler is responsible for managing preloading of scenes.
|
|
862
|
+
* It handles scheduling and limiting concurrent downloads of scenes based on specified parameters.
|
|
863
|
+
*/
|
|
860
864
|
class PreLoadScheduler {
|
|
865
|
+
/** Maximum number of scenes to preload ahead of the current scene */
|
|
861
866
|
maxLoadAhead: number;
|
|
867
|
+
|
|
868
|
+
/** Maximum number of scenes to preload behind the current scene */
|
|
862
869
|
maxLoadBehind: number;
|
|
870
|
+
|
|
871
|
+
/** Maximum number of scenes that can be preloaded concurrently */
|
|
863
872
|
maxConcurrent: number;
|
|
864
873
|
|
|
865
874
|
private _isRunning: boolean = false;
|
|
@@ -867,6 +876,13 @@ class PreLoadScheduler {
|
|
|
867
876
|
private _loadTasks: LoadTask[] = [];
|
|
868
877
|
private _maxConcurrentLoads: number = 1;
|
|
869
878
|
|
|
879
|
+
/**
|
|
880
|
+
* Creates a new PreLoadScheduler instance
|
|
881
|
+
* @param rooms The SceneSwitcher that this scheduler belongs to
|
|
882
|
+
* @param ahead Number of scenes to preload ahead of current scene
|
|
883
|
+
* @param behind Number of scenes to preload behind current scene
|
|
884
|
+
* @param maxConcurrent Maximum number of concurrent preloads allowed
|
|
885
|
+
*/
|
|
870
886
|
constructor(rooms: SceneSwitcher, ahead: number = 1, behind: number = 1, maxConcurrent: number = 2) {
|
|
871
887
|
this._switcher = rooms;
|
|
872
888
|
this.maxLoadAhead = ahead;
|
|
@@ -874,6 +890,10 @@ class PreLoadScheduler {
|
|
|
874
890
|
this.maxConcurrent = maxConcurrent;
|
|
875
891
|
}
|
|
876
892
|
|
|
893
|
+
/**
|
|
894
|
+
* Starts the preloading process after a specified delay
|
|
895
|
+
* @param delay Time in milliseconds to wait before starting preload
|
|
896
|
+
*/
|
|
877
897
|
begin(delay: number) {
|
|
878
898
|
if (this._isRunning) return;
|
|
879
899
|
if (debug) console.log("Preload begin", { delay })
|
|
@@ -919,14 +939,25 @@ class PreLoadScheduler {
|
|
|
919
939
|
}, 200);
|
|
920
940
|
}
|
|
921
941
|
|
|
942
|
+
/**
|
|
943
|
+
* Stops the preloading process
|
|
944
|
+
*/
|
|
922
945
|
stop() {
|
|
923
946
|
this._isRunning = false;
|
|
924
947
|
}
|
|
925
948
|
|
|
949
|
+
/**
|
|
950
|
+
* Checks if a new scene can be loaded based on current load limits
|
|
951
|
+
* @returns True if a new scene can be loaded, false otherwise
|
|
952
|
+
*/
|
|
926
953
|
canLoadNewScene(): boolean {
|
|
927
954
|
return this._loadTasks.length < this._maxConcurrentLoads;
|
|
928
955
|
}
|
|
929
956
|
|
|
957
|
+
/**
|
|
958
|
+
* Checks if all scenes in the SceneSwitcher have been loaded
|
|
959
|
+
* @returns True if all scenes are loaded, false otherwise
|
|
960
|
+
*/
|
|
930
961
|
allLoaded(): boolean {
|
|
931
962
|
if (this._switcher.scenes) {
|
|
932
963
|
for (const scene of this._switcher.scenes) {
|
|
@@ -937,12 +968,25 @@ class PreLoadScheduler {
|
|
|
937
968
|
}
|
|
938
969
|
}
|
|
939
970
|
|
|
971
|
+
/**
|
|
972
|
+
* Represents a single preloading task for a scene
|
|
973
|
+
*/
|
|
940
974
|
class LoadTask {
|
|
941
|
-
|
|
975
|
+
/** The index of the scene in the scenes array */
|
|
942
976
|
index: number;
|
|
977
|
+
|
|
978
|
+
/** The AssetReference to be loaded */
|
|
943
979
|
asset: AssetReference;
|
|
980
|
+
|
|
981
|
+
/** The collection of active load tasks this task belongs to */
|
|
944
982
|
tasks: LoadTask[];
|
|
945
983
|
|
|
984
|
+
/**
|
|
985
|
+
* Creates a new LoadTask and begins loading immediately
|
|
986
|
+
* @param index The index of the scene in the scenes array
|
|
987
|
+
* @param asset The AssetReference to preload
|
|
988
|
+
* @param tasks The collection of active load tasks
|
|
989
|
+
*/
|
|
946
990
|
constructor(index: number, asset: AssetReference, tasks: LoadTask[]) {
|
|
947
991
|
this.index = index;
|
|
948
992
|
this.asset = asset;
|
|
@@ -951,6 +995,9 @@ class LoadTask {
|
|
|
951
995
|
this.awaitLoading();
|
|
952
996
|
}
|
|
953
997
|
|
|
998
|
+
/**
|
|
999
|
+
* Asynchronously loads the asset and removes this task from the active tasks list when complete
|
|
1000
|
+
*/
|
|
954
1001
|
private async awaitLoading() {
|
|
955
1002
|
if (this.asset && !this.asset.isLoaded()) {
|
|
956
1003
|
if (debug)
|
|
@@ -8,8 +8,15 @@ import { EventList } from "./EventList.js";
|
|
|
8
8
|
|
|
9
9
|
const debug = getParam("debugspatialtrigger");
|
|
10
10
|
|
|
11
|
+
/** Layer instances used for mask comparison */
|
|
11
12
|
const layer1 = new Layers();
|
|
12
13
|
const layer2 = new Layers();
|
|
14
|
+
/**
|
|
15
|
+
* Tests if two layer masks intersect
|
|
16
|
+
* @param mask1 First layer mask
|
|
17
|
+
* @param mask2 Second layer mask
|
|
18
|
+
* @returns True if the layers intersect
|
|
19
|
+
*/
|
|
13
20
|
function testMask(mask1, mask2) {
|
|
14
21
|
layer1.mask = mask1;
|
|
15
22
|
layer2.mask = mask2;
|
|
@@ -17,25 +24,45 @@ function testMask(mask1, mask2) {
|
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
/**
|
|
27
|
+
* Component that receives and responds to spatial events, like entering or exiting a trigger zone.
|
|
28
|
+
* Used in conjunction with {@link SpatialTrigger} to create interactive spatial events.
|
|
20
29
|
* @category Interactivity
|
|
21
30
|
* @group Components
|
|
22
31
|
*/
|
|
23
32
|
export class SpatialTriggerReceiver extends Behaviour {
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Bitmask determining which triggers this receiver responds to
|
|
36
|
+
* Only triggers with matching masks will interact with this receiver
|
|
37
|
+
*/
|
|
26
38
|
@serializable()
|
|
27
39
|
triggerMask: number = 0;
|
|
40
|
+
|
|
41
|
+
/** Event invoked when this object enters a trigger zone */
|
|
28
42
|
@serializable(EventList)
|
|
29
43
|
onEnter?: EventList<any>;
|
|
44
|
+
|
|
45
|
+
/** Event invoked continuously while this object is inside a trigger zone */
|
|
30
46
|
@serializable(EventList)
|
|
31
47
|
onStay?: EventList<any>;
|
|
48
|
+
|
|
49
|
+
/** Event invoked when this object exits a trigger zone */
|
|
32
50
|
@serializable(EventList)
|
|
33
51
|
onExit?: EventList<any>;
|
|
34
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Initializes the receiver and logs debug info if enabled
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
35
57
|
start() {
|
|
36
58
|
if (debug) console.log(this.name, this.triggerMask, this);
|
|
37
59
|
}
|
|
38
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Checks for intersections with spatial triggers and fires appropriate events
|
|
63
|
+
* Handles enter, stay, and exit events for all relevant triggers
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
39
66
|
update(): void {
|
|
40
67
|
this.currentIntersected.length = 0;
|
|
41
68
|
for (const trigger of SpatialTrigger.triggers) {
|
|
@@ -59,23 +86,38 @@ export class SpatialTriggerReceiver extends Behaviour {
|
|
|
59
86
|
}
|
|
60
87
|
this.lastIntersected.length = 0;
|
|
61
88
|
this.lastIntersected.push(...this.currentIntersected);
|
|
62
|
-
|
|
63
89
|
}
|
|
64
90
|
|
|
91
|
+
/** Array of triggers currently intersecting with this receiver */
|
|
65
92
|
readonly currentIntersected: SpatialTrigger[] = [];
|
|
93
|
+
|
|
94
|
+
/** Array of triggers that intersected with this receiver in the previous frame */
|
|
66
95
|
readonly lastIntersected: SpatialTrigger[] = [];
|
|
67
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Handles trigger enter events.
|
|
99
|
+
* @param trigger The spatial trigger that was entered
|
|
100
|
+
*/
|
|
68
101
|
onEnterTrigger(trigger: SpatialTrigger): void {
|
|
69
102
|
if(debug) console.log("ENTER TRIGGER", this.name, trigger.name, this, trigger);
|
|
70
103
|
trigger.raiseOnEnterEvent(this);
|
|
71
104
|
this.onEnter?.invoke();
|
|
72
105
|
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Handles trigger exit events.
|
|
109
|
+
* @param trigger The spatial trigger that was exited
|
|
110
|
+
*/
|
|
73
111
|
onExitTrigger(trigger: SpatialTrigger): void {
|
|
74
112
|
if(debug) console.log("EXIT TRIGGER", this.name, trigger.name, );
|
|
75
113
|
trigger.raiseOnExitEvent(this);
|
|
76
114
|
this.onExit?.invoke();
|
|
77
115
|
}
|
|
78
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Handles trigger stay events.
|
|
119
|
+
* @param trigger The spatial trigger that the receiver is staying in
|
|
120
|
+
*/
|
|
79
121
|
onStayTrigger(trigger: SpatialTrigger): void {
|
|
80
122
|
trigger.raiseOnStayEvent(this);
|
|
81
123
|
this.onStay?.invoke();
|
|
@@ -83,24 +125,38 @@ export class SpatialTriggerReceiver extends Behaviour {
|
|
|
83
125
|
}
|
|
84
126
|
|
|
85
127
|
/**
|
|
86
|
-
* A trigger that
|
|
128
|
+
* A spatial trigger component that detects objects within a box-shaped area.
|
|
129
|
+
* Used to trigger events when objects enter, stay in, or exit the defined area
|
|
87
130
|
* @category Interactivity
|
|
88
131
|
* @group Components
|
|
89
132
|
*/
|
|
90
133
|
export class SpatialTrigger extends Behaviour {
|
|
91
134
|
|
|
135
|
+
/** Global registry of all active spatial triggers in the scene */
|
|
92
136
|
static triggers: SpatialTrigger[] = [];
|
|
93
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Bitmask determining which receivers this trigger affects.
|
|
140
|
+
* Only receivers with matching masks will be triggered.
|
|
141
|
+
*/
|
|
142
|
+
// currently Layers in unity but maybe this should be a string or plane number? Or should it be a bitmask to allow receivers use multiple triggers?
|
|
94
143
|
@serializable()
|
|
95
144
|
triggerMask?: number;
|
|
96
145
|
|
|
146
|
+
/** Box helper component used to visualize and calculate the trigger area */
|
|
97
147
|
private boxHelper?: BoxHelperComponent;
|
|
98
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Initializes the trigger and logs debug info if enabled
|
|
151
|
+
*/
|
|
99
152
|
start() {
|
|
100
153
|
if (debug)
|
|
101
154
|
console.log(this.name, this.triggerMask, this);
|
|
102
155
|
}
|
|
103
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Registers this trigger in the global registry and sets up debug visualization if enabled
|
|
159
|
+
*/
|
|
104
160
|
onEnable(): void {
|
|
105
161
|
SpatialTrigger.triggers.push(this);
|
|
106
162
|
if (!this.boxHelper) {
|
|
@@ -108,10 +164,19 @@ export class SpatialTrigger extends Behaviour {
|
|
|
108
164
|
this.boxHelper?.showHelper(null, debug as boolean);
|
|
109
165
|
}
|
|
110
166
|
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Removes this trigger from the global registry when disabled
|
|
170
|
+
*/
|
|
111
171
|
onDisable(): void {
|
|
112
172
|
SpatialTrigger.triggers.splice(SpatialTrigger.triggers.indexOf(this), 1);
|
|
113
173
|
}
|
|
114
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Tests if an object is inside this trigger's box
|
|
177
|
+
* @param obj The object to test against this trigger
|
|
178
|
+
* @returns True if the object is inside the trigger box
|
|
179
|
+
*/
|
|
115
180
|
test(obj: Object3D): boolean {
|
|
116
181
|
if (!this.boxHelper) return false;
|
|
117
182
|
return this.boxHelper.isInBox(obj) ?? false;
|
|
@@ -119,6 +184,10 @@ export class SpatialTrigger extends Behaviour {
|
|
|
119
184
|
|
|
120
185
|
// private args: SpatialTriggerEventArgs = new SpatialTriggerEventArgs();
|
|
121
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Raises the onEnter event on any SpatialTriggerReceiver components attached to this trigger's GameObject
|
|
189
|
+
* @param rec The receiver that entered this trigger
|
|
190
|
+
*/
|
|
122
191
|
raiseOnEnterEvent(rec: SpatialTriggerReceiver) {
|
|
123
192
|
// this.args.trigger = this;
|
|
124
193
|
// this.args.source = rec;
|
|
@@ -130,6 +199,10 @@ export class SpatialTrigger extends Behaviour {
|
|
|
130
199
|
}, false);
|
|
131
200
|
}
|
|
132
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Raises the onStay event on any SpatialTriggerReceiver components attached to this trigger's GameObject
|
|
204
|
+
* @param rec The receiver that is staying in this trigger
|
|
205
|
+
*/
|
|
133
206
|
raiseOnStayEvent(rec: SpatialTriggerReceiver) {
|
|
134
207
|
// this.args.trigger = this;
|
|
135
208
|
// this.args.source = rec;
|
|
@@ -141,6 +214,10 @@ export class SpatialTrigger extends Behaviour {
|
|
|
141
214
|
}, false);
|
|
142
215
|
}
|
|
143
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Raises the onExit event on any SpatialTriggerReceiver components attached to this trigger's GameObject
|
|
219
|
+
* @param rec The receiver that exited this trigger
|
|
220
|
+
*/
|
|
144
221
|
raiseOnExitEvent(rec: SpatialTriggerReceiver) {
|
|
145
222
|
GameObject.foreachComponent(this.gameObject, c => {
|
|
146
223
|
if (c === rec) return;
|