@needle-tools/engine 4.9.0-next.43185 → 4.9.0
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 +14 -0
- package/README.md +1 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-CZSmogSi.min.js → needle-engine.bundle-B1gr_nQ0.min.js} +119 -119
- package/dist/{needle-engine.bundle-Bs33m9iI.js → needle-engine.bundle-BikYBC35.js} +5444 -5405
- package/dist/{needle-engine.bundle-Bf4EhG38.umd.cjs → needle-engine.bundle-DrlDKOar.umd.cjs} +128 -128
- 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-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/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 +29 -3
- package/lib/engine-components/web/ScrollFollow.js +91 -20
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/package.json +2 -2
- package/src/engine-components/Component.ts +8 -5
- 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 +93 -23
|
@@ -7,14 +7,28 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
8
8
|
import { getTempVector } from "../../engine/engine_three_utils.js";
|
|
9
9
|
import { Behaviour } from "../Component.js";
|
|
10
|
+
/**
|
|
11
|
+
* The CursorFollow component makes the object follow the cursor (or touch) position on screen.
|
|
12
|
+
*/
|
|
10
13
|
export class CursorFollow extends Behaviour {
|
|
11
14
|
/**
|
|
12
15
|
* Damping for the movement, set to 0 for instant movement
|
|
13
16
|
* @default 0
|
|
14
17
|
*/
|
|
15
18
|
damping = 0;
|
|
19
|
+
/**
|
|
20
|
+
* If true, the initial distance to the camera is maintained when following the cursor.
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
keepDistance = true;
|
|
24
|
+
awake() {
|
|
25
|
+
this._distance = -1;
|
|
26
|
+
}
|
|
16
27
|
_distance = -1;
|
|
17
28
|
updateDistance() {
|
|
29
|
+
if (this.keepDistance && this._distance !== -1) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
18
32
|
this._distance = this.gameObject.worldPosition.distanceTo(this.context.mainCamera.worldPosition);
|
|
19
33
|
}
|
|
20
34
|
/** @internal */
|
|
@@ -43,4 +57,7 @@ export class CursorFollow extends Behaviour {
|
|
|
43
57
|
__decorate([
|
|
44
58
|
serializable()
|
|
45
59
|
], CursorFollow.prototype, "damping", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
serializable()
|
|
62
|
+
], CursorFollow.prototype, "keepDistance", void 0);
|
|
46
63
|
//# sourceMappingURL=CursorFollow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,SAAS;IAEvC;;;OAGG;IAEH,OAAO,GAAW,CAAC,CAAC;IAEpB;;;OAGG;IAEH,YAAY,GAAY,IAAI,CAAC;IAE7B,KAAK;QACD,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACxB,CAAC;IAEO,SAAS,GAAW,CAAC,CAAC,CAAC;IAE/B,cAAc;QACV,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC,EAAE;YAC5C,OAAO;SACV;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACrG,CAAC;IAED,gBAAgB;IAChB,MAAM;QACF,8DAA8D;QAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,yEAAyE;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACvC,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;QAE5C,iDAAiD;QACjD,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5E,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,SAAS,EAAE,CAAC;QAE7C,oDAAoD;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpF,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YAClE,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC;SACvC;aACI;YACD,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,WAAW,CAAC;SAC/C;IAEL,CAAC;CAEJ;AAjDG;IADC,YAAY,EAAE;6CACK;AAOpB;IADC,YAAY,EAAE;kDACc"}
|
|
@@ -11,9 +11,22 @@ type ScrollFollowEvent = {
|
|
|
11
11
|
preventDefault: () => void;
|
|
12
12
|
defaultPrevented: boolean;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* The ScrollFollow component allows you to link the scroll position of the page (or a specific element) to one or more target objects.
|
|
16
|
+
* This can be used to create scroll-based animations, audio playback, or other effects. For example you can link the scroll position to a timeline (PlayableDirector) to create scroll-based storytelling effects or to an Animator component to change the animation state based on scroll.
|
|
17
|
+
*
|
|
18
|
+
* @link Example at https://scrollytelling-2-z23hmxby7c6x-u30ld.needle.run/
|
|
19
|
+
*/
|
|
14
20
|
export declare class ScrollFollow extends Behaviour {
|
|
15
21
|
/**
|
|
16
22
|
* Target object(s) to follow the scroll position of the page. If null, the main camera is used.
|
|
23
|
+
*
|
|
24
|
+
* Supported target types:
|
|
25
|
+
* - PlayableDirector (timeline), the scroll position will be mapped to the timeline time
|
|
26
|
+
* - Animator, the scroll position will be set to a float parameter named "scroll"
|
|
27
|
+
* - Animation, the scroll position will be mapped to the animation time
|
|
28
|
+
* - AudioSource, the scroll position will be mapped to the audio time
|
|
29
|
+
* - Any object with a `scroll` property (number or function)
|
|
17
30
|
*/
|
|
18
31
|
target: object[] | object | null;
|
|
19
32
|
/**
|
|
@@ -21,7 +34,18 @@ export declare class ScrollFollow extends Behaviour {
|
|
|
21
34
|
* @default 0
|
|
22
35
|
*/
|
|
23
36
|
damping: number;
|
|
24
|
-
|
|
37
|
+
/**
|
|
38
|
+
* If true, the scroll value will be inverted (e.g. scrolling down will result in a value of 0)
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
invert: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* If set, the scroll position will be read from the specified element instead of the window.
|
|
44
|
+
* Use a CSS selector to specify the element, e.g. `#my-scrollable-div` or `.scroll-container`.
|
|
45
|
+
* @default null
|
|
46
|
+
*/
|
|
47
|
+
htmlSelector: string | null;
|
|
48
|
+
private mode;
|
|
25
49
|
/**
|
|
26
50
|
* Event fired when the scroll position changes
|
|
27
51
|
*/
|
|
@@ -39,7 +63,9 @@ export declare class ScrollFollow extends Behaviour {
|
|
|
39
63
|
onDisable(): void;
|
|
40
64
|
/** @internal */
|
|
41
65
|
lateUpdate(): void;
|
|
42
|
-
private
|
|
43
|
-
private
|
|
66
|
+
private _lastSelectorValue;
|
|
67
|
+
private _lastSelectorElement;
|
|
68
|
+
private updateCurrentScrollValue;
|
|
69
|
+
private static applyScroll;
|
|
44
70
|
}
|
|
45
71
|
export {};
|
|
@@ -5,16 +5,33 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { Object3D } from "three";
|
|
8
|
-
import { serializable } from "../../engine/engine_serialization.js";
|
|
9
8
|
import { Mathf } from "../../engine/engine_math.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { EventList } from "../EventList.js";
|
|
9
|
+
import { serializable } from "../../engine/engine_serialization.js";
|
|
10
|
+
import { getBoundingBox } from "../../engine/engine_three_utils.js";
|
|
13
11
|
import { Animation } from "../Animation.js";
|
|
12
|
+
import { Animator } from "../Animator.js";
|
|
14
13
|
import { AudioSource } from "../AudioSource.js";
|
|
14
|
+
import { Behaviour } from "../Component.js";
|
|
15
|
+
import { EventList } from "../EventList.js";
|
|
16
|
+
import { Light } from "../Light.js";
|
|
17
|
+
import { SplineWalker } from "../splines/SplineWalker.js";
|
|
18
|
+
import { PlayableDirector } from "../timeline/PlayableDirector.js";
|
|
19
|
+
/**
|
|
20
|
+
* The ScrollFollow component allows you to link the scroll position of the page (or a specific element) to one or more target objects.
|
|
21
|
+
* This can be used to create scroll-based animations, audio playback, or other effects. For example you can link the scroll position to a timeline (PlayableDirector) to create scroll-based storytelling effects or to an Animator component to change the animation state based on scroll.
|
|
22
|
+
*
|
|
23
|
+
* @link Example at https://scrollytelling-2-z23hmxby7c6x-u30ld.needle.run/
|
|
24
|
+
*/
|
|
15
25
|
export class ScrollFollow extends Behaviour {
|
|
16
26
|
/**
|
|
17
27
|
* Target object(s) to follow the scroll position of the page. If null, the main camera is used.
|
|
28
|
+
*
|
|
29
|
+
* Supported target types:
|
|
30
|
+
* - PlayableDirector (timeline), the scroll position will be mapped to the timeline time
|
|
31
|
+
* - Animator, the scroll position will be set to a float parameter named "scroll"
|
|
32
|
+
* - Animation, the scroll position will be mapped to the animation time
|
|
33
|
+
* - AudioSource, the scroll position will be mapped to the audio time
|
|
34
|
+
* - Any object with a `scroll` property (number or function)
|
|
18
35
|
*/
|
|
19
36
|
target = null;
|
|
20
37
|
/**
|
|
@@ -22,6 +39,17 @@ export class ScrollFollow extends Behaviour {
|
|
|
22
39
|
* @default 0
|
|
23
40
|
*/
|
|
24
41
|
damping = 0;
|
|
42
|
+
/**
|
|
43
|
+
* If true, the scroll value will be inverted (e.g. scrolling down will result in a value of 0)
|
|
44
|
+
* @default false
|
|
45
|
+
*/
|
|
46
|
+
invert = false;
|
|
47
|
+
/**
|
|
48
|
+
* If set, the scroll position will be read from the specified element instead of the window.
|
|
49
|
+
* Use a CSS selector to specify the element, e.g. `#my-scrollable-div` or `.scroll-container`.
|
|
50
|
+
* @default null
|
|
51
|
+
*/
|
|
52
|
+
htmlSelector = null;
|
|
25
53
|
mode = "window";
|
|
26
54
|
/**
|
|
27
55
|
* Event fired when the scroll position changes
|
|
@@ -38,20 +66,23 @@ export class ScrollFollow extends Behaviour {
|
|
|
38
66
|
applied_value = -1;
|
|
39
67
|
/** @internal */
|
|
40
68
|
onEnable() {
|
|
41
|
-
window.addEventListener("wheel", this.
|
|
69
|
+
window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
|
|
42
70
|
this.applied_value = -1;
|
|
43
|
-
this.updateCurrentScroll();
|
|
44
71
|
}
|
|
45
72
|
/** @internal */
|
|
46
73
|
onDisable() {
|
|
47
|
-
window.removeEventListener("wheel", this.
|
|
74
|
+
window.removeEventListener("wheel", this.updateCurrentScrollValue);
|
|
48
75
|
}
|
|
49
76
|
/** @internal */
|
|
50
77
|
lateUpdate() {
|
|
78
|
+
this.updateCurrentScrollValue();
|
|
51
79
|
// apply damping if any
|
|
52
80
|
if (this.damping > 0) {
|
|
53
81
|
this.current_value = Mathf.lerp(this.current_value, this.target_value, this.context.time.deltaTime / this.damping);
|
|
54
82
|
}
|
|
83
|
+
else {
|
|
84
|
+
this.current_value = this.target_value;
|
|
85
|
+
}
|
|
55
86
|
if (this.current_value !== this.applied_value) {
|
|
56
87
|
this.applied_value = this.current_value;
|
|
57
88
|
let defaultPrevented = false;
|
|
@@ -69,50 +100,84 @@ export class ScrollFollow extends Behaviour {
|
|
|
69
100
|
}
|
|
70
101
|
// if not prevented apply scroll
|
|
71
102
|
if (!defaultPrevented) {
|
|
103
|
+
const value = this.invert ? 1 - this.current_value : this.current_value;
|
|
72
104
|
// apply scroll to target(s)
|
|
73
105
|
if (Array.isArray(this.target)) {
|
|
74
|
-
this.target.forEach(t => t &&
|
|
106
|
+
this.target.forEach(t => t && ScrollFollow.applyScroll(t, value));
|
|
75
107
|
}
|
|
76
108
|
else if (this.target) {
|
|
77
|
-
|
|
109
|
+
ScrollFollow.applyScroll(this.target, value);
|
|
78
110
|
}
|
|
79
111
|
}
|
|
80
112
|
}
|
|
81
113
|
}
|
|
82
|
-
|
|
114
|
+
_lastSelectorValue = null;
|
|
115
|
+
_lastSelectorElement = null;
|
|
116
|
+
updateCurrentScrollValue = () => {
|
|
83
117
|
switch (this.mode) {
|
|
84
118
|
case "window":
|
|
85
|
-
|
|
119
|
+
if (this.htmlSelector?.length) {
|
|
120
|
+
if (this.htmlSelector !== this._lastSelectorValue) {
|
|
121
|
+
this._lastSelectorElement = document.querySelector(this.htmlSelector);
|
|
122
|
+
this._lastSelectorValue = this.htmlSelector;
|
|
123
|
+
}
|
|
124
|
+
if (this._lastSelectorElement) {
|
|
125
|
+
const rect = this._lastSelectorElement.getBoundingClientRect();
|
|
126
|
+
this.target_value = -rect.top / (rect.height - window.innerHeight);
|
|
127
|
+
if (isNaN(this.target_value) || !isFinite(this.target_value))
|
|
128
|
+
this.target_value = 0;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.target_value = window.scrollY / (document.body.scrollHeight - window.innerHeight);
|
|
134
|
+
}
|
|
86
135
|
if (isNaN(this.target_value) || !isFinite(this.target_value))
|
|
87
136
|
this.target_value = 0;
|
|
88
137
|
break;
|
|
89
138
|
}
|
|
90
|
-
if (this.damping <= 0) {
|
|
91
|
-
this.current_value = this.target_value;
|
|
92
|
-
}
|
|
93
139
|
};
|
|
94
|
-
applyScroll(target) {
|
|
140
|
+
static applyScroll(target, value) {
|
|
95
141
|
if (!target)
|
|
96
142
|
return;
|
|
97
143
|
if (target instanceof PlayableDirector) {
|
|
98
|
-
target.time =
|
|
144
|
+
target.time = value * target.duration;
|
|
99
145
|
if (!target.isPlaying)
|
|
100
146
|
target.evaluate();
|
|
101
147
|
}
|
|
148
|
+
else if (target instanceof Animator) {
|
|
149
|
+
target.setFloat("scroll", value);
|
|
150
|
+
}
|
|
102
151
|
else if (target instanceof Animation) {
|
|
103
|
-
target.time =
|
|
152
|
+
target.time = value * target.duration;
|
|
104
153
|
}
|
|
105
154
|
else if (target instanceof AudioSource) {
|
|
106
155
|
if (!target.duration)
|
|
107
156
|
return;
|
|
108
|
-
target.time =
|
|
157
|
+
target.time = value * target.duration;
|
|
158
|
+
}
|
|
159
|
+
else if (target instanceof SplineWalker) {
|
|
160
|
+
target.position01 = value;
|
|
161
|
+
}
|
|
162
|
+
else if (target instanceof Light) {
|
|
163
|
+
target.intensity = value;
|
|
164
|
+
}
|
|
165
|
+
else if (target instanceof Object3D) {
|
|
166
|
+
// When objects are assigned they're expected to move vertically based on scroll
|
|
167
|
+
if (target["needle:scrollbounds"] === undefined) {
|
|
168
|
+
target["needle:scrollbounds"] = getBoundingBox(target) || null;
|
|
169
|
+
}
|
|
170
|
+
const bounds = target["needle:scrollbounds"];
|
|
171
|
+
if (bounds) {
|
|
172
|
+
target.position.y = -bounds.min.y - value * (bounds.max.y - bounds.min.y);
|
|
173
|
+
}
|
|
109
174
|
}
|
|
110
175
|
else if ("scroll" in target) {
|
|
111
176
|
if (typeof target.scroll === "number") {
|
|
112
|
-
target.scroll =
|
|
177
|
+
target.scroll = value;
|
|
113
178
|
}
|
|
114
179
|
else if (typeof target.scroll === "function") {
|
|
115
|
-
target.scroll(
|
|
180
|
+
target.scroll(value);
|
|
116
181
|
}
|
|
117
182
|
}
|
|
118
183
|
}
|
|
@@ -123,6 +188,12 @@ __decorate([
|
|
|
123
188
|
__decorate([
|
|
124
189
|
serializable()
|
|
125
190
|
], ScrollFollow.prototype, "damping", void 0);
|
|
191
|
+
__decorate([
|
|
192
|
+
serializable()
|
|
193
|
+
], ScrollFollow.prototype, "invert", void 0);
|
|
194
|
+
__decorate([
|
|
195
|
+
serializable()
|
|
196
|
+
], ScrollFollow.prototype, "htmlSelector", void 0);
|
|
126
197
|
__decorate([
|
|
127
198
|
serializable()
|
|
128
199
|
], ScrollFollow.prototype, "mode", void 0);
|
|
@@ -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":";;;;;;AAAA,OAAO,EAAQ,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAcnE;;;;;GAKG;AACH,MAAM,OAAO,YAAa,SAAQ,SAAS;IAEvC;;;;;;;;;OASG;IAEH,MAAM,GAA6B,IAAI,CAAC;IAExC;;;OAGG;IAEH,OAAO,GAAW,CAAC,CAAC;IAEpB;;;OAGG;IAEH,MAAM,GAAY,KAAK,CAAC;IAExB;;;;OAIG;IAEH,YAAY,GAAkB,IAAI,CAAC;IAG3B,IAAI,GAAa,QAAQ,CAAC;IAElC;;OAEG;IAEH,OAAO,GAAiC,IAAI,SAAS,EAAqB,CAAC;IAE3E;;OAEG;IACH,IAAI,YAAY;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAEO,aAAa,GAAW,CAAC,CAAC;IAC1B,YAAY,GAAW,CAAC,CAAC;IACzB,aAAa,GAAW,CAAC,CAAC,CAAC;IAEnC,gBAAgB;IAChB,QAAQ;QACJ,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,gBAAgB;IAChB,SAAS;QACL,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACvE,CAAC;IAED,gBAAgB;IAChB,UAAU;QAEN,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAEhC,uBAAuB;QACvB,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE;YAClB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;SACtH;aACI;YACD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC;SAC1C;QAED,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,aAAa,EAAE;YAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;YAExC,IAAI,gBAAgB,GAAG,KAAK,CAAC;YAC7B,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,CAAC,EAAE;gBAChC,oBAAoB;gBACpB,MAAM,KAAK,GAAsB;oBAC7B,IAAI,EAAE,QAAQ;oBACd,KAAK,EAAE,IAAI,CAAC,aAAa;oBACzB,SAAS,EAAE,IAAI;oBACf,cAAc,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC;oBACxD,gBAAgB,EAAE,KAAK;iBAC1B,CAAC;gBACF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC3B,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;aAC7C;YAED,gCAAgC;YAChC,IAAI,CAAC,gBAAgB,EAAE;gBAEnB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;gBAExE,4BAA4B;gBAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;oBAC5B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;iBACrE;qBACI,IAAI,IAAI,CAAC,MAAM,EAAE;oBAClB,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;iBAChD;aACJ;SACJ;IACL,CAAC;IAEO,kBAAkB,GAAkB,IAAI,CAAC;IACzC,oBAAoB,GAAmB,IAAI,CAAC;IAE5C,wBAAwB,GAAG,GAAG,EAAE;QAEpC,QAAQ,IAAI,CAAC,IAAI,EAAE;YACf,KAAK,QAAQ;gBACT,IAAI,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE;oBAC3B,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,kBAAkB,EAAE;wBAC/C,IAAI,CAAC,oBAAoB,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBACtE,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC;qBAC/C;oBACD,IAAI,IAAI,CAAC,oBAAoB,EAAE;wBAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAoB,CAAC,qBAAqB,EAAE,CAAC;wBAC/D,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;wBACnE,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;4BAAE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;wBACpF,MAAM;qBACT;iBACJ;qBACI;oBACD,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;iBAC1F;gBACD,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;oBAAE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;gBACpF,MAAM;SACb;IAEL,CAAC,CAAA;IAGO,MAAM,CAAC,WAAW,CAAC,MAAc,EAAE,KAAa;QAEpD,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,MAAM,YAAY,gBAAgB,EAAE;YACpC,MAAM,CAAC,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,SAAS;gBAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;SAC5C;aACI,IAAI,MAAM,YAAY,QAAQ,EAAE;YACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;SACpC;aACI,IAAI,MAAM,YAAY,SAAS,EAAE;YAClC,MAAM,CAAC,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;SACzC;aACI,IAAI,MAAM,YAAY,WAAW,EAAE;YACpC,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,OAAO;YAC7B,MAAM,CAAC,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC;SACzC;aACI,IAAI,MAAM,YAAY,YAAY,EAAE;YACrC,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;SAC7B;aACI,IAAI,MAAM,YAAY,KAAK,EAAE;YAC9B,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC;SAC5B;aACI,IAAI,MAAM,YAAY,QAAQ,EAAE;YACjC,gFAAgF;YAChF,IAAI,MAAM,CAAC,qBAAqB,CAAC,KAAK,SAAS,EAAE;gBAC7C,MAAM,CAAC,qBAAqB,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;aAClE;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAS,CAAC;YACrD,IAAI,MAAM,EAAE;gBACR,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aAC7E;SACJ;aACI,IAAI,QAAQ,IAAI,MAAM,EAAE;YACzB,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE;gBACnC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;aACzB;iBACI,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE;gBAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;aACxB;SACJ;IACL,CAAC;CAEJ;AA9KG;IADC,YAAY,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;4CACI;AAOxC;IADC,YAAY,EAAE;6CACK;AAOpB;IADC,YAAY,EAAE;4CACS;AAQxB;IADC,YAAY,EAAE;kDACoB;AAGnC;IADC,YAAY,EAAE;0CACmB;AAMlC;IADC,YAAY,CAAC,SAAS,CAAC;6CACmD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.9.0
|
|
3
|
+
"version": "4.9.0",
|
|
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": {
|
|
@@ -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
|
+
}
|
|
@@ -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,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
|