@needle-tools/engine 3.32.6-alpha → 3.32.7-alpha
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 +6 -0
- package/dist/needle-engine.js +1797 -1712
- package/dist/needle-engine.light.js +1765 -1680
- package/dist/needle-engine.light.min.js +122 -122
- package/dist/needle-engine.light.umd.cjs +104 -104
- package/dist/needle-engine.min.js +122 -122
- package/dist/needle-engine.umd.cjs +104 -104
- package/lib/engine/engine_gameobject.js +0 -1
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gizmos.js +1 -1
- package/lib/engine/engine_gizmos.js.map +1 -1
- package/lib/engine/xr/NeedleXRController.js +1 -0
- package/lib/engine/xr/NeedleXRController.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +1 -5
- package/lib/engine/xr/NeedleXRSession.js +9 -53
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/SceneTransition.d.ts +18 -0
- package/lib/engine/xr/SceneTransition.js +68 -0
- package/lib/engine/xr/SceneTransition.js.map +1 -0
- package/lib/engine-components/ui/EventSystem.d.ts +12 -1
- package/lib/engine-components/ui/EventSystem.js +88 -24
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/PointerEvents.d.ts +27 -3
- package/lib/engine-components/ui/PointerEvents.js +36 -2
- package/lib/engine-components/ui/PointerEvents.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_gameobject.ts +0 -1
- package/src/engine/engine_gizmos.ts +1 -1
- package/src/engine/xr/NeedleXRController.ts +1 -0
- package/src/engine/xr/NeedleXRSession.ts +9 -54
- package/src/engine/xr/SceneTransition.ts +76 -0
- package/src/engine-components/ui/EventSystem.ts +104 -33
- package/src/engine-components/ui/PointerEvents.ts +40 -5
|
@@ -14,6 +14,7 @@ import { registerFrameEventCallback, unregisterFrameEventCallback } from "../eng
|
|
|
14
14
|
import { isDestroyed } from "../engine_gameobject.js";
|
|
15
15
|
import { TemporaryXRContext } from "./TempXRContext.js";
|
|
16
16
|
import { Mathf } from "../engine_math.js";
|
|
17
|
+
import { SceneTransition } from "./SceneTransition.js";
|
|
17
18
|
|
|
18
19
|
export type NeedleXREventArgs = { xr: NeedleXRSession }
|
|
19
20
|
export type SessionChangedEvt = (args: NeedleXREventArgs) => void;
|
|
@@ -1019,7 +1020,7 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1019
1020
|
|
|
1020
1021
|
private onAfterRender = () => {
|
|
1021
1022
|
this.onUpdateFade_PostRender();
|
|
1022
|
-
|
|
1023
|
+
|
|
1023
1024
|
// render spectator view if we're in VR using Link
|
|
1024
1025
|
if (isDesktop()) {
|
|
1025
1026
|
const renderer = this.context.renderer;
|
|
@@ -1200,71 +1201,25 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
1200
1201
|
}
|
|
1201
1202
|
|
|
1202
1203
|
// TODO: for scene transitions (e.g. SceneSwitcher) where creating the scene might take a few moments we might want more control over when/how this fading occurs and how long the scene stays black
|
|
1203
|
-
|
|
1204
|
+
private transition?: SceneTransition;
|
|
1205
|
+
|
|
1204
1206
|
/** Call to fade rendering to black for a short moment (the returned promise will be resolved when fully black)
|
|
1205
1207
|
* This can be used to mask scene transitions or teleportation
|
|
1206
1208
|
* @returns a promise that is resolved when the screen is fully black
|
|
1207
1209
|
* @example `fadeTransition().then(() => { <fully_black> })`
|
|
1208
1210
|
*/
|
|
1209
1211
|
fadeTransition() {
|
|
1210
|
-
if (this.
|
|
1211
|
-
this.
|
|
1212
|
-
const promise = new Promise<void>(resolve => {
|
|
1213
|
-
this._transitionResolve = resolve;
|
|
1214
|
-
});
|
|
1215
|
-
this._transitionPromise = promise;
|
|
1216
|
-
return promise;
|
|
1212
|
+
if (!this.transition) this.transition = new SceneTransition();
|
|
1213
|
+
return this.transition.fadeTransition();
|
|
1217
1214
|
}
|
|
1218
1215
|
|
|
1219
|
-
private _requestedFadeValue: number = 0;
|
|
1220
|
-
private _transitionPromise: Promise<void> | null = null;
|
|
1221
|
-
private _transitionResolve: (() => void) | null = null;
|
|
1222
|
-
private _fadeToColorQuad: Mesh | null = null;
|
|
1223
|
-
private _fadeToColorMaterial!: MeshBasicMaterial;
|
|
1224
|
-
|
|
1225
1216
|
/** e.g. FadeToBlack */
|
|
1226
1217
|
private updateFade(camera: Camera) {
|
|
1227
|
-
if (
|
|
1228
|
-
|
|
1229
|
-
this._fadeToColorMaterial = new MeshBasicMaterial({
|
|
1230
|
-
color: 0x000000,
|
|
1231
|
-
transparent: true,
|
|
1232
|
-
depthTest: false,
|
|
1233
|
-
fog: false,
|
|
1234
|
-
side: DoubleSide,
|
|
1235
|
-
});
|
|
1236
|
-
this._fadeToColorQuad = new Mesh(new PlaneGeometry(10, 10), this._fadeToColorMaterial);
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
// ensure that the quad is setup with the right properties
|
|
1240
|
-
const quad = this._fadeToColorQuad;
|
|
1241
|
-
const mat = this._fadeToColorMaterial;
|
|
1242
|
-
|
|
1243
|
-
// make sure the quad is in the scene
|
|
1244
|
-
if (quad.parent !== camera && mat.opacity > 0) {
|
|
1245
|
-
camera!.add(quad);
|
|
1246
|
-
}
|
|
1247
|
-
else if (mat.opacity === 0) {
|
|
1248
|
-
quad.removeFromParent();
|
|
1249
|
-
}
|
|
1250
|
-
quad.layers.set(2);
|
|
1251
|
-
quad.material = this._fadeToColorMaterial!;
|
|
1252
|
-
quad.position.z = -1;
|
|
1253
|
-
// perform the fade
|
|
1254
|
-
const fadeValue = this._requestedFadeValue;
|
|
1255
|
-
mat.opacity = Mathf.lerp(mat.opacity, fadeValue, this.context.time.deltaTime / .03);
|
|
1256
|
-
// check if we're close enough to the desired value:
|
|
1257
|
-
if (Math.abs(mat.opacity - fadeValue) <= .01) {
|
|
1258
|
-
if (this._transitionResolve) {
|
|
1259
|
-
this._transitionResolve();
|
|
1260
|
-
this._transitionResolve = null;
|
|
1261
|
-
this._transitionPromise = null;
|
|
1262
|
-
this._requestedFadeValue = 0;
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1218
|
+
if (this.transition && camera instanceof PerspectiveCamera)
|
|
1219
|
+
this.transition.update(camera, this.context.time.deltaTime);
|
|
1265
1220
|
}
|
|
1266
1221
|
|
|
1267
1222
|
private onUpdateFade_PostRender() {
|
|
1268
|
-
this.
|
|
1223
|
+
this.transition?.remove();
|
|
1269
1224
|
}
|
|
1270
1225
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Camera, DoubleSide, Mesh, MeshBasicMaterial, PlaneGeometry } from "three";
|
|
2
|
+
import { Mathf } from "../engine_math.js";
|
|
3
|
+
|
|
4
|
+
export class SceneTransition {
|
|
5
|
+
|
|
6
|
+
private readonly _fadeToColorQuad: Mesh;
|
|
7
|
+
private readonly _fadeToColorMaterial: MeshBasicMaterial;
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
this._fadeToColorMaterial = new MeshBasicMaterial({
|
|
11
|
+
color: 0x000000,
|
|
12
|
+
transparent: true,
|
|
13
|
+
depthTest: false,
|
|
14
|
+
fog: false,
|
|
15
|
+
side: DoubleSide,
|
|
16
|
+
});
|
|
17
|
+
this._fadeToColorQuad = new Mesh(new PlaneGeometry(10, 10), this._fadeToColorMaterial);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
dispose() {
|
|
21
|
+
this._fadeToColorQuad.geometry.dispose();
|
|
22
|
+
this._fadeToColorMaterial.dispose();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
update(camera: Camera, dt: number) {
|
|
26
|
+
const quad = this._fadeToColorQuad;
|
|
27
|
+
const mat = this._fadeToColorMaterial;
|
|
28
|
+
|
|
29
|
+
// make sure the quad is in the scene
|
|
30
|
+
if (quad.parent !== camera && mat.opacity > 0) {
|
|
31
|
+
camera.add(quad);
|
|
32
|
+
}
|
|
33
|
+
else if (mat.opacity === 0) {
|
|
34
|
+
quad.removeFromParent();
|
|
35
|
+
}
|
|
36
|
+
quad.layers.set(2);
|
|
37
|
+
quad.material = this._fadeToColorMaterial!;
|
|
38
|
+
quad.position.z = -1;
|
|
39
|
+
// perform the fade
|
|
40
|
+
const fadeValue = this._requestedFadeValue;
|
|
41
|
+
mat.opacity = Mathf.lerp(mat.opacity, fadeValue, dt / .03);
|
|
42
|
+
|
|
43
|
+
// check if we're close enough to the desired value:
|
|
44
|
+
if (Math.abs(mat.opacity - fadeValue) <= .01) {
|
|
45
|
+
if (this._transitionResolve) {
|
|
46
|
+
this._transitionResolve();
|
|
47
|
+
this._transitionResolve = null;
|
|
48
|
+
this._transitionPromise = null;
|
|
49
|
+
this._requestedFadeValue = 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
remove() {
|
|
54
|
+
this._fadeToColorQuad.removeFromParent();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Call to fade rendering to black for a short moment (the returned promise will be resolved when fully black)
|
|
58
|
+
* This can be used to mask scene transitions or teleportation
|
|
59
|
+
* @returns a promise that is resolved when the screen is fully black
|
|
60
|
+
* @example `fadeTransition().then(() => { <fully_black> })`
|
|
61
|
+
*/
|
|
62
|
+
fadeTransition() {
|
|
63
|
+
if (this._transitionPromise) return this._transitionPromise;
|
|
64
|
+
this._requestedFadeValue = 1;
|
|
65
|
+
const promise = new Promise<void>(resolve => {
|
|
66
|
+
this._transitionResolve = resolve;
|
|
67
|
+
});
|
|
68
|
+
this._transitionPromise = promise;
|
|
69
|
+
return promise;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
private _requestedFadeValue: number = 0;
|
|
74
|
+
private _transitionPromise: Promise<void> | null = null;
|
|
75
|
+
private _transitionResolve: (() => void) | null = null;
|
|
76
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { RaycastOptions, RaycastTestObjectReturnType } from "../../engine/engine_physics.js";
|
|
2
2
|
import { Behaviour, GameObject } from "../Component.js";
|
|
3
|
-
import * as ThreeMeshUI from 'three-mesh-ui'
|
|
4
3
|
import { Context } from "../../engine/engine_setup.js";
|
|
5
|
-
import { type IPointerEventHandler, PointerEventData, hasPointerEventComponent } from "./PointerEvents.js";
|
|
4
|
+
import { type IPointerEventHandler, PointerEventData, hasPointerEventComponent, IPointerUpHandler } from "./PointerEvents.js";
|
|
6
5
|
import { ObjectRaycaster, Raycaster } from "./Raycaster.js";
|
|
7
6
|
import { InputEvents, NEPointerEvent, PointerType } from "../../engine/engine_input.js";
|
|
8
|
-
import { Object3D } from "three";
|
|
7
|
+
import { Intersection, Object3D } from "three";
|
|
9
8
|
import type { ICanvasGroup } from "./Interfaces.js";
|
|
10
9
|
import { getParam } from "../../engine/engine_utils.js";
|
|
11
10
|
import { UIRaycastUtils } from "./RaycastUtils.js";
|
|
@@ -13,7 +12,7 @@ import { $shadowDomOwner } from "./BaseUIComponent.js";
|
|
|
13
12
|
import { isDevEnvironment, showBalloonMessage } from "../../engine/debug/index.js";
|
|
14
13
|
import { Mathf } from "../../engine/engine_math.js";
|
|
15
14
|
import { isUIObject } from "./Utils.js";
|
|
16
|
-
import {
|
|
15
|
+
import { IComponent } from "../../engine/engine_types.js";
|
|
17
16
|
|
|
18
17
|
const debug = getParam("debugeventsystem");
|
|
19
18
|
|
|
@@ -187,12 +186,12 @@ export class EventSystem extends Behaviour {
|
|
|
187
186
|
hasActiveUI: this.currentActiveMeshUIComponents.length > 0,
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
this.dispatchEvent(new CustomEvent(EventSystemEvents.BeforeHandleInput, { detail: evt }))
|
|
189
|
+
this.dispatchEvent(new CustomEvent(EventSystemEvents.BeforeHandleInput, { detail: evt }));
|
|
191
190
|
|
|
192
|
-
// handle
|
|
193
|
-
this.handleIntersections(id, hits, data)
|
|
191
|
+
// then handle the intersections and call the callbacks on the regular objects
|
|
192
|
+
this.handleIntersections(id, hits, data);
|
|
194
193
|
|
|
195
|
-
this.dispatchEvent(new CustomEvent<AfterHandleInputEvent>(EventSystemEvents.AfterHandleInput, { detail: evt }))
|
|
194
|
+
this.dispatchEvent(new CustomEvent<AfterHandleInputEvent>(EventSystemEvents.AfterHandleInput, { detail: evt }));
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
private readonly _sortedHits: THREE.Intersection[] = [];
|
|
@@ -294,20 +293,38 @@ export class EventSystem extends Behaviour {
|
|
|
294
293
|
return this._sortedHits;
|
|
295
294
|
}
|
|
296
295
|
|
|
297
|
-
private
|
|
296
|
+
private assignHitInformation(args: PointerEventData, hit?: Intersection) {
|
|
297
|
+
if (!hit) {
|
|
298
|
+
args.point = undefined;
|
|
299
|
+
args.normal = undefined;
|
|
300
|
+
args.face = undefined;
|
|
301
|
+
args.distance = undefined;
|
|
302
|
+
args.instanceId = undefined;
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
args.point = hit.point;
|
|
306
|
+
args.normal = hit.normal;
|
|
307
|
+
args.face = hit.face;
|
|
308
|
+
args.distance = hit.distance;
|
|
309
|
+
args.instanceId = hit.instanceId;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private handleIntersections(id: number, hits: Intersection[] | null | undefined, args: PointerEventData): boolean {
|
|
314
|
+
|
|
315
|
+
// first invoke captured pointers
|
|
316
|
+
this.assignHitInformation(args, hits?.[0]);
|
|
317
|
+
this.invokePointerCapture(args);
|
|
318
|
+
|
|
319
|
+
|
|
298
320
|
if (hits?.length) {
|
|
299
321
|
hits = this.sortCandidates(hits);
|
|
300
322
|
for (const hit of hits) {
|
|
301
323
|
if (args.event.immediatePropagationStopped) {
|
|
302
324
|
return false;
|
|
303
325
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
args.normal = hit.normal;
|
|
307
|
-
args.face = hit.face;
|
|
308
|
-
args.distance = hit.distance;
|
|
309
|
-
args.instanceId = hit.instanceId;
|
|
310
|
-
if (this.handleEventOnObject(object, args)) {
|
|
326
|
+
this.assignHitInformation(args, hit);
|
|
327
|
+
if (this.handleEventOnObject(hit.object, args)) {
|
|
311
328
|
return true;
|
|
312
329
|
}
|
|
313
330
|
}
|
|
@@ -325,7 +342,7 @@ export class EventSystem extends Behaviour {
|
|
|
325
342
|
// if it was up, it means it doesn't should notify things that it down on before
|
|
326
343
|
if (args.isUp) {
|
|
327
344
|
const pressedData = this.pressedByID.get(id);
|
|
328
|
-
pressedData?.handlers.forEach(h =>
|
|
345
|
+
pressedData?.handlers.forEach(h => this.invokeOnPointerUp(args, h));
|
|
329
346
|
this.pressedByID.delete(id);
|
|
330
347
|
}
|
|
331
348
|
|
|
@@ -374,16 +391,11 @@ export class EventSystem extends Behaviour {
|
|
|
374
391
|
|
|
375
392
|
// Event without pointer can't be handled
|
|
376
393
|
if (args.pointerId === undefined) {
|
|
377
|
-
if (debug) console.
|
|
394
|
+
if (debug) console.error("Event without pointer can't be handled", args);
|
|
378
395
|
return false;
|
|
379
396
|
}
|
|
380
397
|
|
|
381
|
-
// We want to call all event methods even if the event was used
|
|
382
|
-
// Used event can't be handled
|
|
383
|
-
// if (args.used) return false;
|
|
384
|
-
|
|
385
398
|
// Correct the handled object to match the relevant object in shadow dom (?)
|
|
386
|
-
const originalObject = object;
|
|
387
399
|
args.object = object;
|
|
388
400
|
|
|
389
401
|
const parent = object.parent as any;
|
|
@@ -460,13 +472,10 @@ export class EventSystem extends Behaviour {
|
|
|
460
472
|
/**
|
|
461
473
|
* Propagate up in hiearchy and call the callback for each component that is possibly a handler
|
|
462
474
|
*/
|
|
463
|
-
private propagate(object: Object3D | null,
|
|
475
|
+
private propagate(object: Object3D | null, onComponent: (behaviour: Behaviour) => void) {
|
|
464
476
|
|
|
465
477
|
while (true) {
|
|
466
478
|
|
|
467
|
-
// Propagate up the hierarchy
|
|
468
|
-
if (args.used) break;
|
|
469
|
-
|
|
470
479
|
if (!object) break;
|
|
471
480
|
|
|
472
481
|
GameObject.foreachComponent(object, comp => {
|
|
@@ -505,7 +514,7 @@ export class EventSystem extends Behaviour {
|
|
|
505
514
|
break;
|
|
506
515
|
}
|
|
507
516
|
|
|
508
|
-
this.propagate(object,
|
|
517
|
+
this.propagate(object, (behaviour) => {
|
|
509
518
|
const comp = behaviour as any;
|
|
510
519
|
|
|
511
520
|
if (comp.interactable === false) return;
|
|
@@ -528,17 +537,20 @@ export class EventSystem extends Behaviour {
|
|
|
528
537
|
// So we can call the up event on the same handler
|
|
529
538
|
// In a scenario where we Down on one object and Up on another
|
|
530
539
|
pressedEvent?.handlers.add(comp);
|
|
540
|
+
|
|
541
|
+
this.handlePointerCapture(args, comp);
|
|
531
542
|
}
|
|
532
543
|
}
|
|
533
544
|
|
|
534
545
|
if (comp.onPointerMove) {
|
|
535
546
|
if (isMoving)
|
|
536
547
|
comp.onPointerMove(args);
|
|
548
|
+
this.handlePointerCapture(args, comp);
|
|
537
549
|
}
|
|
538
550
|
|
|
539
551
|
if (args.isUp) {
|
|
540
552
|
if (comp.onPointerUp) {
|
|
541
|
-
|
|
553
|
+
this.invokeOnPointerUp(args, comp);
|
|
542
554
|
|
|
543
555
|
// We don't want to call Up twice if we Down and Up on the same object
|
|
544
556
|
// But if we Down on one and Up on another we want to call Up on the first one as well
|
|
@@ -566,9 +578,7 @@ export class EventSystem extends Behaviour {
|
|
|
566
578
|
// If user drags away from the object, then it doesn't get the UP event
|
|
567
579
|
if (args.isUp) {
|
|
568
580
|
pressedEvent?.handlers.forEach((handler) => {
|
|
569
|
-
|
|
570
|
-
handler.onPointerUp(args);
|
|
571
|
-
}
|
|
581
|
+
this.invokeOnPointerUp(args, handler);
|
|
572
582
|
});
|
|
573
583
|
|
|
574
584
|
this.pressedByID.delete(args.pointerId);
|
|
@@ -580,7 +590,7 @@ export class EventSystem extends Behaviour {
|
|
|
580
590
|
*/
|
|
581
591
|
private triggerOnExit(object: Object3D, args: PointerEventData, newObject: Object3D | null) {
|
|
582
592
|
|
|
583
|
-
this.propagate(object,
|
|
593
|
+
this.propagate(object, (behaviour) => {
|
|
584
594
|
if (!behaviour.gameObject || behaviour.destroyed) return;
|
|
585
595
|
|
|
586
596
|
const inst: any = behaviour;
|
|
@@ -597,6 +607,67 @@ export class EventSystem extends Behaviour {
|
|
|
597
607
|
});
|
|
598
608
|
}
|
|
599
609
|
|
|
610
|
+
/** handles onPointerUp - this will also release the pointerCapture */
|
|
611
|
+
private invokeOnPointerUp(evt: PointerEventData, handler: IPointerUpHandler) {
|
|
612
|
+
handler.onPointerUp?.call(handler, evt);
|
|
613
|
+
this.releasePointerCapture(evt.pointerId, handler);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/** the list of component handlers that requested pointerCapture for a specific pointerId */
|
|
617
|
+
private readonly _capturedPointer: { [pointerId: number]: IPointerEventHandler[] } = {};
|
|
618
|
+
|
|
619
|
+
/** check if the event was marked to be captured: if yes add the current component to the captured list */
|
|
620
|
+
private handlePointerCapture(evt: PointerEventData, comp: IPointerEventHandler) {
|
|
621
|
+
if (evt.z__pointer_ctured) {
|
|
622
|
+
evt.z__pointer_ctured = false;
|
|
623
|
+
// only the onPointerMove event is called with captured pointers so we don't need to add it to our list if it doesnt implement onPointerMove
|
|
624
|
+
if (comp.onPointerMove) {
|
|
625
|
+
const list = this._capturedPointer[evt.pointerId] || [];
|
|
626
|
+
list.push(comp);
|
|
627
|
+
this._capturedPointer[evt.pointerId] = list;
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
if (isDevEnvironment())
|
|
631
|
+
console.warn("PointerCapture was requested but the component doesn't implement onPointerMove. It will not receive any pointer events");
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
else if (evt.z__pointer_cture_rleased) {
|
|
635
|
+
evt.z__pointer_cture_rleased = false;
|
|
636
|
+
this.releasePointerCapture(evt.pointerId, comp);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/** removes the component from the pointer capture list */
|
|
641
|
+
releasePointerCapture(pointerId: number, component: IPointerEventHandler) {
|
|
642
|
+
if (this._capturedPointer[pointerId]) {
|
|
643
|
+
const i = this._capturedPointer[pointerId].indexOf(component);
|
|
644
|
+
if (i !== -1) {
|
|
645
|
+
this._capturedPointer[pointerId].splice(i, 1);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/** invoke the pointerMove event on all captured handlers */
|
|
650
|
+
private invokePointerCapture(evt: PointerEventData) {
|
|
651
|
+
if (evt.event.type === InputEvents.PointerMove) {
|
|
652
|
+
const pointerId = evt.pointerId;
|
|
653
|
+
const captured = this._capturedPointer[pointerId];
|
|
654
|
+
if (captured) {
|
|
655
|
+
for (let i = 0; i < captured.length; i++) {
|
|
656
|
+
const handler = captured[i];
|
|
657
|
+
// check if it was destroyed
|
|
658
|
+
const comp = handler as IComponent;
|
|
659
|
+
if (comp.destroyed) {
|
|
660
|
+
captured.splice(i, 1);
|
|
661
|
+
i--;
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
// invoke pointer move
|
|
665
|
+
handler.onPointerMove?.call(handler, evt);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
600
671
|
private readonly pointerEnterSymbol = Symbol("pointerEnter");
|
|
601
672
|
private readonly pointerExitSymbol = Symbol("pointerExit");
|
|
602
673
|
|
|
@@ -5,13 +5,20 @@ import { GamepadButtonName, MouseButtonName } from "../../engine/engine_types.js
|
|
|
5
5
|
|
|
6
6
|
export interface IInputEventArgs {
|
|
7
7
|
get used(): boolean;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
use(): void;
|
|
9
|
+
stopImmediatePropagation?(): void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/** This pointer event data object is passed to all event receivers that are currently active
|
|
13
|
+
* It contains hit information if an object was hovered or clicked
|
|
14
|
+
* If the event is received in onPointerDown or onPointerMove, you can call `setPointerCapture` to receive onPointerMove events even when the pointer has left the object until you call `releasePointerCapture` or when the pointerUp event happens
|
|
15
|
+
* You can get additional information about the event or event source via the `event` property (of type `NEPointerEvent`)
|
|
16
|
+
*/
|
|
12
17
|
export class PointerEventData implements IInputEventArgs {
|
|
13
18
|
|
|
19
|
+
/** the original event */
|
|
14
20
|
readonly event: NEPointerEvent;
|
|
21
|
+
/** the pointer identifier for this event */
|
|
15
22
|
readonly pointerId: number;
|
|
16
23
|
/**
|
|
17
24
|
* mouse button 0 === LEFT, 1 === MIDDLE, 2 === RIGHT
|
|
@@ -20,25 +27,53 @@ export class PointerEventData implements IInputEventArgs {
|
|
|
20
27
|
readonly buttonName: MouseButtonName | GamepadButtonName | undefined;
|
|
21
28
|
|
|
22
29
|
private _used: boolean = false;
|
|
30
|
+
/** true when `use()` has been called */
|
|
23
31
|
get used(): boolean {
|
|
24
32
|
return this._used;
|
|
25
33
|
}
|
|
26
34
|
|
|
35
|
+
/** mark this event to be used */
|
|
27
36
|
use() {
|
|
37
|
+
if (this._used) return;
|
|
28
38
|
this._used = true;
|
|
29
39
|
if (this.pointerId !== undefined)
|
|
30
40
|
this.input.setPointerUsed(this.pointerId);
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
private _propagationStopped: boolean = false;
|
|
44
|
+
get propagationStopped() {
|
|
45
|
+
return this._propagationStopped;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Call this method to stop immediate propagation on the `event` object.
|
|
49
|
+
* WARNING: this is currently equivalent to stopImmediatePropagation
|
|
50
|
+
*/
|
|
34
51
|
stopPropagation() {
|
|
35
|
-
// we currently don't have a distinction between stopPropagation and stopImmediatePropagation
|
|
52
|
+
// we currently don't have a distinction between stopPropagation and stopImmediatePropagation
|
|
53
|
+
this._propagationStopped = true;
|
|
36
54
|
this.event.stopImmediatePropagation();
|
|
37
55
|
}
|
|
56
|
+
/** Call this method to stop immediate propagation on the `event` object.
|
|
57
|
+
*/
|
|
38
58
|
stopImmediatePropagation() {
|
|
59
|
+
this._propagationStopped = true;
|
|
39
60
|
this.event.stopImmediatePropagation();
|
|
40
61
|
}
|
|
41
62
|
|
|
63
|
+
/**@ignore internal flag, pointer captured (we dont want to see it in intellisense) */
|
|
64
|
+
z__pointer_ctured: boolean = false;
|
|
65
|
+
/** Call this method in `onPointerDown` or `onPointerMove` to receive onPointerMove events for this pointerId even when the pointer has left the object until you call `releasePointerCapture` or when the pointerUp event happens
|
|
66
|
+
*/
|
|
67
|
+
setPointerCapture() {
|
|
68
|
+
this.z__pointer_ctured = true;
|
|
69
|
+
}
|
|
70
|
+
/**@ignore internal flag, pointer capture released */
|
|
71
|
+
z__pointer_cture_rleased: boolean = false;
|
|
72
|
+
/** call this method in `onPointerDown` or `onPointerMove` to stop receiving onPointerMove events */
|
|
73
|
+
releasePointerCapture() {
|
|
74
|
+
this.z__pointer_cture_rleased = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
42
77
|
|
|
43
78
|
/** Who initiated this event */
|
|
44
79
|
inputSource: Input | any;
|
|
@@ -67,7 +102,7 @@ export class PointerEventData implements IInputEventArgs {
|
|
|
67
102
|
|
|
68
103
|
private input: Input;
|
|
69
104
|
|
|
70
|
-
constructor(pointerId: number, input: Input, event: NEPointerEvent) {
|
|
105
|
+
constructor(pointerId: number, input: Input, event: NEPointerEvent) {
|
|
71
106
|
this.pointerId = pointerId;
|
|
72
107
|
this.event = event;
|
|
73
108
|
this.input = input;
|