@@ -217,7 +217,7 @@
|
|
217
217
|
// }
|
218
218
|
|
219
219
|
// check if server is running
|
220
|
-
if (server.httpServer
|
220
|
+
if (server.httpServer?.listening) {
|
221
221
|
server.restart();
|
222
222
|
}
|
223
223
|
isRunningRestart = false;
|
@@ -182,6 +182,14 @@
|
|
182
182
|
private _volume: number = 1;
|
183
183
|
|
184
184
|
@serializable()
|
185
|
+
set pitch(val: number) {
|
186
|
+
if (this.sound) this.sound.setPlaybackRate(val);
|
187
|
+
}
|
188
|
+
get pitch(): number {
|
189
|
+
return this.sound ? this.sound.getPlaybackRate() : 1;
|
190
|
+
}
|
191
|
+
|
192
|
+
@serializable()
|
185
193
|
rollOffMode: AudioRolloffMode = 0;
|
186
194
|
|
187
195
|
|
@@ -15,6 +15,7 @@
|
|
15
15
|
|
16
16
|
/** The ClearFlags enum is used to determine how the camera clears the background */
|
17
17
|
export enum ClearFlags {
|
18
|
+
None = 0,
|
18
19
|
/** Clear the background with a skybox */
|
19
20
|
Skybox = 1,
|
20
21
|
/** Clear the background with a solid color. The alpha channel of the color determines the transparency */
|
@@ -429,6 +430,9 @@
|
|
429
430
|
console.debug(msg);
|
430
431
|
}
|
431
432
|
switch (this._clearFlags) {
|
433
|
+
case ClearFlags.None:
|
434
|
+
return;
|
435
|
+
|
432
436
|
case ClearFlags.Skybox:
|
433
437
|
if (Camera.backgroundShouldBeTransparent(this.context)) {
|
434
438
|
if (!this.ARBackgroundAlpha || this.ARBackgroundAlpha < 0.001) {
|
@@ -98,18 +98,47 @@
|
|
98
98
|
/** When enabled, draws a line from the dragged object downwards to the next raycast hit. */
|
99
99
|
@serializable()
|
100
100
|
public showGizmo: boolean = false;
|
101
|
-
|
101
|
+
|
102
102
|
/** The currently dragged object (if any) */
|
103
103
|
get draggedObject() {
|
104
104
|
return this._targetObject;
|
105
105
|
}
|
106
106
|
|
107
|
+
/**
|
108
|
+
* Use to update the object that is being dragged by the DragControls
|
109
|
+
*/
|
110
|
+
setTargetObject(obj: Object3D | null) {
|
111
|
+
this._targetObject = obj;
|
112
|
+
for (const handler of this._dragHandlers.values()) {
|
113
|
+
handler.setTargetObject(obj);
|
114
|
+
}
|
115
|
+
|
116
|
+
// If the object was kinematic we want to reset it
|
117
|
+
const wasKinematicKey = "_rigidbody-was-kinematic";
|
118
|
+
if (this._rigidbody?.[wasKinematicKey] === false) {
|
119
|
+
this._rigidbody.isKinematic = false;
|
120
|
+
}
|
121
|
+
|
122
|
+
this._rigidbody = null;
|
123
|
+
// If we have a object that is being dragged we want to get the Rigidbody component
|
124
|
+
// and we set kinematic to false while it's being dragged
|
125
|
+
if (obj) {
|
126
|
+
this._rigidbody = GameObject.getComponentInChildren(obj, Rigidbody);
|
127
|
+
if (this._rigidbody?.isKinematic === false) {
|
128
|
+
this._rigidbody.isKinematic = true;
|
129
|
+
this._rigidbody[wasKinematicKey] = false;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
}
|
134
|
+
private _rigidbody: Rigidbody | null = null;
|
135
|
+
|
107
136
|
// future:
|
108
137
|
// constraints?
|
109
138
|
|
110
139
|
|
111
140
|
/** The object to be dragged – we pass this to handlers when they are created */
|
112
|
-
private _targetObject:
|
141
|
+
private _targetObject: Object3D | null = null;
|
113
142
|
private _dragHelper: LegacyDragVisualsHelper | null = null;
|
114
143
|
private static lastHovered: Object3D;
|
115
144
|
private _draggingRigidbodies: Rigidbody[] = [];
|
@@ -121,13 +150,6 @@
|
|
121
150
|
private _isDragging: boolean = false;
|
122
151
|
private _didDrag: boolean = false;
|
123
152
|
|
124
|
-
setTargetObject(obj: Object3D | null) {
|
125
|
-
this._targetObject = obj as GameObject;
|
126
|
-
for (const handler of this._dragHandlers.values()) {
|
127
|
-
handler.setTargetObject(obj);
|
128
|
-
}
|
129
|
-
}
|
130
|
-
|
131
153
|
/** @internal */
|
132
154
|
awake() {
|
133
155
|
// initialize all data that may be cloned incorrectly otherwise
|
@@ -202,10 +224,13 @@
|
|
202
224
|
this._totalMovement.set(0, 0, 0);
|
203
225
|
this._potentialDragStartEvt = args;
|
204
226
|
}
|
227
|
+
if (!this._targetObject) {
|
228
|
+
this.setTargetObject(this.gameObject);
|
229
|
+
}
|
205
230
|
|
206
231
|
DragControls._active += 1;
|
207
232
|
|
208
|
-
const newDragHandler = new DragPointerHandler(this, this._targetObject
|
233
|
+
const newDragHandler = new DragPointerHandler(this, this._targetObject!);
|
209
234
|
this._dragHandlers.set(args.event.space, newDragHandler);
|
210
235
|
|
211
236
|
newDragHandler.onDragStart(args);
|
@@ -214,9 +239,8 @@
|
|
214
239
|
const iterator = this._dragHandlers.values();
|
215
240
|
const a = iterator.next().value;
|
216
241
|
const b = iterator.next().value;
|
217
|
-
const mtHandler = new MultiTouchDragHandler(this, this._targetObject
|
242
|
+
const mtHandler = new MultiTouchDragHandler(this, this._targetObject!, a, b);
|
218
243
|
this._dragHandlers.set(this.gameObject, mtHandler);
|
219
|
-
|
220
244
|
mtHandler.onDragStart(args);
|
221
245
|
}
|
222
246
|
|
@@ -231,9 +255,7 @@
|
|
231
255
|
|
232
256
|
/** @internal */
|
233
257
|
onPointerUp(args: PointerEventData) {
|
234
|
-
|
235
258
|
if (debug) Gizmos.DrawLabel(args.point ?? this.gameObject.worldPosition, "POINTERUP:" + args.pointerId + ", " + args.button, .03, 3);
|
236
|
-
|
237
259
|
if (!this.allowEdit(this.gameObject)) return;
|
238
260
|
if (args.button !== 0) return;
|
239
261
|
this._potentialDragStartEvt = null;
|
@@ -250,6 +272,8 @@
|
|
250
272
|
if (DragControls._active > 0)
|
251
273
|
DragControls._active -= 1;
|
252
274
|
|
275
|
+
this.setTargetObject(null);
|
276
|
+
|
253
277
|
if (handler.onDragEnd) handler.onDragEnd(args);
|
254
278
|
this._dragHandlers.delete(args.event.space);
|
255
279
|
|
@@ -388,7 +412,7 @@
|
|
388
412
|
|
389
413
|
private context: Context;
|
390
414
|
private settings: DragControls;
|
391
|
-
private gameObject:
|
415
|
+
private gameObject: Object3D;
|
392
416
|
private _handlerAAttachmentPoint: Vector3 = new Vector3();
|
393
417
|
private _handlerBAttachmentPoint: Vector3 = new Vector3();
|
394
418
|
|
@@ -397,7 +421,7 @@
|
|
397
421
|
private _deviceMode!: XRTargetRayMode | "transient-pointer";
|
398
422
|
private _followObjectStartWorldQuaternion: Quaternion = new Quaternion();
|
399
423
|
|
400
|
-
constructor(dragControls: DragControls, gameObject:
|
424
|
+
constructor(dragControls: DragControls, gameObject: Object3D, pointerA: DragPointerHandler, pointerB: DragPointerHandler) {
|
401
425
|
this.context = dragControls.context;
|
402
426
|
this.settings = dragControls;
|
403
427
|
this.gameObject = gameObject;
|
@@ -633,7 +657,7 @@
|
|
633
657
|
get hitPointInLocalSpace(): Vector3 { return this._hitPointInLocalSpace; }
|
634
658
|
|
635
659
|
private context: Context;
|
636
|
-
private gameObject:
|
660
|
+
private gameObject: Object3D | null;
|
637
661
|
private settings: DragControls;
|
638
662
|
private _lastRig: IGameObject | undefined = undefined;
|
639
663
|
|
@@ -667,10 +691,10 @@
|
|
667
691
|
|
668
692
|
/** Allows overriding which object is dragged while a drag is already ongoing. Used for example by Duplicatable */
|
669
693
|
setTargetObject(obj: Object3D | null) {
|
670
|
-
this.gameObject = obj
|
694
|
+
this.gameObject = obj;
|
671
695
|
}
|
672
696
|
|
673
|
-
constructor(dragControls: DragControls, gameObject:
|
697
|
+
constructor(dragControls: DragControls, gameObject: Object3D) {
|
674
698
|
this.settings = dragControls;
|
675
699
|
this.context = dragControls.context;
|
676
700
|
this.gameObject = gameObject;
|
@@ -682,6 +706,10 @@
|
|
682
706
|
console.warn("Error: space follow object doesn't have parent but recenter() is called. This is likely a bug");
|
683
707
|
return;
|
684
708
|
}
|
709
|
+
if (!this.gameObject) {
|
710
|
+
console.warn("Error: space follow object doesn't have a gameObject");
|
711
|
+
return;
|
712
|
+
}
|
685
713
|
|
686
714
|
const p = this._followObject.parent as GameObject;
|
687
715
|
|
@@ -721,6 +749,10 @@
|
|
721
749
|
}
|
722
750
|
|
723
751
|
onDragStart(args: PointerEventData) {
|
752
|
+
if (!this.gameObject) {
|
753
|
+
console.warn("Error: space follow object doesn't have a gameObject");
|
754
|
+
return;
|
755
|
+
}
|
724
756
|
|
725
757
|
args.event.space.add(this._followObject);
|
726
758
|
|
@@ -1037,7 +1069,8 @@
|
|
1037
1069
|
}
|
1038
1070
|
}
|
1039
1071
|
else if (didHaveSurfaceHitPointLastFrame) {
|
1040
|
-
|
1072
|
+
if (this.gameObject)
|
1073
|
+
this.setPlaneViewAligned(this.gameObject.worldPosition, false)
|
1041
1074
|
}
|
1042
1075
|
}
|
1043
1076
|
|
@@ -148,7 +148,7 @@
|
|
148
148
|
* @returns The created object
|
149
149
|
*/
|
150
150
|
static createOccluder(type: PrimitiveTypeNames): Mesh {
|
151
|
-
const occluderMaterial = new
|
151
|
+
const occluderMaterial = new MeshBasicMaterial({ colorWrite: false, depthWrite: true, side: DoubleSide });
|
152
152
|
return this.createPrimitive(type, { material: occluderMaterial });
|
153
153
|
}
|
154
154
|
|
@@ -6,10 +6,18 @@
|
|
6
6
|
|
7
7
|
class MathHelper {
|
8
8
|
|
9
|
-
random(
|
10
|
-
|
11
|
-
|
9
|
+
random<T>(arr: Array<T>): T | null;
|
10
|
+
random(min?: number, max?: number): number;
|
11
|
+
random<T>(arrayOrMin?: number | Array<T>, max?: number): number | T | null {
|
12
|
+
if (Array.isArray(arrayOrMin)) {
|
13
|
+
if(arrayOrMin.length <= 0) return null;
|
14
|
+
return arrayOrMin[Math.floor(Math.random() * arrayOrMin.length)];
|
12
15
|
}
|
16
|
+
else {
|
17
|
+
if (arrayOrMin !== undefined && max !== undefined) {
|
18
|
+
return Math.random() * (max - arrayOrMin) + arrayOrMin;
|
19
|
+
}
|
20
|
+
}
|
13
21
|
return Math.random();
|
14
22
|
}
|
15
23
|
|
@@ -200,7 +200,7 @@
|
|
200
200
|
}
|
201
201
|
|
202
202
|
}, err => {
|
203
|
-
console.error("
|
203
|
+
console.error("Loading asset at \"" + path + "\" failed\n", err);
|
204
204
|
resolve(undefined);
|
205
205
|
});
|
206
206
|
}
|
@@ -262,7 +262,7 @@
|
|
262
262
|
}, evt => {
|
263
263
|
prog?.call(loader, evt);
|
264
264
|
}, err => {
|
265
|
-
console.error("
|
265
|
+
console.error("Loading asset at \"" + url + "\" failed\n", err);
|
266
266
|
resolve(undefined);
|
267
267
|
});
|
268
268
|
}
|
@@ -73,7 +73,7 @@
|
|
73
73
|
|
74
74
|
/** Gets a temporary vector. If a vector is passed in it will be copied to the temporary vector
|
75
75
|
* Temporary vectors are cached and reused internally. Don't store them!
|
76
|
-
* @param
|
76
|
+
* @param vec3 the vector to copy or the x value
|
77
77
|
* @param y the y value
|
78
78
|
* @param z the z value
|
79
79
|
* @returns a temporary vector
|
@@ -87,15 +87,24 @@
|
|
87
87
|
* const vec5 = getTempVector();
|
88
88
|
* ```
|
89
89
|
*/
|
90
|
-
export function getTempVector(
|
90
|
+
export function getTempVector(): Vector3;
|
91
|
+
export function getTempVector(vec3: Vector3): Vector3;
|
92
|
+
export function getTempVector(vec3: [number, number, number]): Vector3;
|
93
|
+
export function getTempVector(dom: DOMPointReadOnly): Vector3;
|
94
|
+
export function getTempVector(x: number): Vector3;
|
95
|
+
export function getTempVector(x: number, y: number, z: number): Vector3;
|
96
|
+
export function getTempVector(vecOrX?: Vector3 | [number, number, number] | DOMPointReadOnly | number, y?: number, z?: number): Vector3 {
|
91
97
|
const vec = _tempVecs.get();
|
92
98
|
vec.set(0, 0, 0); // initialize with default values
|
93
99
|
if (vecOrX instanceof Vector3) vec.copy(vecOrX);
|
100
|
+
else if (Array.isArray(vecOrX)) vec.set(vecOrX[0], vecOrX[1], vecOrX[2]);
|
94
101
|
else if (vecOrX instanceof DOMPointReadOnly) vec.set(vecOrX.x, vecOrX.y, vecOrX.z);
|
95
102
|
else {
|
96
|
-
if (typeof vecOrX === "number")
|
97
|
-
|
98
|
-
|
103
|
+
if (typeof vecOrX === "number") {
|
104
|
+
vec.x = vecOrX;
|
105
|
+
vec.y = y !== undefined ? y : vec.x;
|
106
|
+
vec.z = z !== undefined ? z : vec.x;
|
107
|
+
}
|
99
108
|
}
|
100
109
|
return vec;
|
101
110
|
}
|
@@ -523,7 +532,7 @@
|
|
523
532
|
if (obj["needle:rendercustomshadow"] === true) {
|
524
533
|
return true;
|
525
534
|
}
|
526
|
-
else if(obj["needle:rendercustomshadow"] == undefined) {
|
535
|
+
else if (obj["needle:rendercustomshadow"] == undefined) {
|
527
536
|
return true;
|
528
537
|
}
|
529
538
|
}
|
@@ -141,6 +141,10 @@
|
|
141
141
|
width /= zoomLevel;
|
142
142
|
height /= zoomLevel;
|
143
143
|
|
144
|
+
// save XR state and reset it for screenshot
|
145
|
+
const previousXRState = context.renderer.xr.enabled;
|
146
|
+
context.renderer.xr.enabled = false;
|
147
|
+
|
144
148
|
// reset style during screenshot
|
145
149
|
context.renderer.domElement.style.width = width + "px";
|
146
150
|
context.renderer.domElement.style.height = height + "px";
|
@@ -247,6 +251,7 @@
|
|
247
251
|
camera.aspect = previousAspect;
|
248
252
|
camera.updateProjectionMatrix();
|
249
253
|
}
|
254
|
+
context.renderer.xr.enabled = previousXRState;
|
250
255
|
}
|
251
256
|
|
252
257
|
return null;
|
@@ -311,6 +311,7 @@
|
|
311
311
|
this._activePointerEvents = [];
|
312
312
|
this.context.input.addEventListener("pointerdown", this._onPointerDown, { queue: InputEventQueue.Early });
|
313
313
|
this.context.input.addEventListener("pointerup", this._onPointerUp, { queue: InputEventQueue.Early });
|
314
|
+
this.context.input.addEventListener("pointerup", this._onPointerUpLate, { queue: InputEventQueue.Late });
|
314
315
|
}
|
315
316
|
|
316
317
|
/** @internal */
|
@@ -327,6 +328,7 @@
|
|
327
328
|
this._activePointerEvents.length = 0;
|
328
329
|
this.context.input.removeEventListener("pointerdown", this._onPointerDown);
|
329
330
|
this.context.input.removeEventListener("pointerup", this._onPointerUp);
|
331
|
+
this.context.input.removeEventListener("pointerup", this._onPointerUpLate);
|
330
332
|
}
|
331
333
|
|
332
334
|
private _activePointerEvents!: NEPointerEvent[];
|
@@ -373,6 +375,12 @@
|
|
373
375
|
}
|
374
376
|
};
|
375
377
|
|
378
|
+
private _onPointerUpLate = (evt: NEPointerEvent) => {
|
379
|
+
if(this.doubleClickToFocus && evt.isDoubleClick && !evt.used){
|
380
|
+
this.setTargetFromRaycast();
|
381
|
+
}
|
382
|
+
};
|
383
|
+
|
376
384
|
private onControlsChangeStarted = () => {
|
377
385
|
if (this._syncedTransform) {
|
378
386
|
this._syncedTransform.requestOwnership();
|
@@ -447,8 +455,7 @@
|
|
447
455
|
}
|
448
456
|
}
|
449
457
|
|
450
|
-
|
451
|
-
focusAtPointer ||= (this.doubleClickToFocus && this.context.input.getPointerDoubleClicked(0) && this.context.time.time - this._enableTime > .3);
|
458
|
+
const focusAtPointer = (this.middleClickToFocus && this.context.input.getPointerClicked(1));
|
452
459
|
if (focusAtPointer) {
|
453
460
|
this.setTargetFromRaycast();
|
454
461
|
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { BufferAttribute, BufferGeometry, Color, DoubleSide, Material, Mesh, MeshBasicMaterial, NearestFilter, SRGBColorSpace, Texture } from "three";
|
2
2
|
|
3
|
-
import { Context } from "../engine/engine_context.js";
|
4
3
|
import { serializable, serializeable } from "../engine/engine_serialization_decorator.js";
|
5
4
|
import { getParam } from "../engine/engine_utils.js";
|
6
5
|
import { NEEDLE_progressive } from "../engine/extensions/NEEDLE_progressive.js";
|
@@ -75,6 +74,16 @@
|
|
75
74
|
*/
|
76
75
|
export class Sprite {
|
77
76
|
|
77
|
+
constructor(texture?: Texture) {
|
78
|
+
if (texture) {
|
79
|
+
this.texture = texture;
|
80
|
+
this.triangles = [0, 1, 2, 0, 2, 3];
|
81
|
+
this.uv = [{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 1 }, { x: 0, y: 1 }];
|
82
|
+
this.vertices = [{ x: -.5, y: -.5 }, { x: .5, y: -.5 }, { x: .5, y: .5 }, { x: -.5, y: .5 }];
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
|
78
87
|
@serializable()
|
79
88
|
guid?: string;
|
80
89
|
@serializable(Texture)
|
@@ -140,9 +149,49 @@
|
|
140
149
|
|
141
150
|
export class SpriteData {
|
142
151
|
|
152
|
+
static create() {
|
153
|
+
const i = new SpriteData();
|
154
|
+
i.spriteSheet = new SpriteSheet();
|
155
|
+
return i;
|
156
|
+
}
|
157
|
+
|
158
|
+
// we don't assign anything here because it's used by the serialization system.
|
159
|
+
// there's currently a limitation in the serializer when e.g. spriteSheet is already assigned it will not be overriden by the serializer
|
160
|
+
// hence the spriteSheet field is undefined by default
|
161
|
+
constructor() { }
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Set the sprite to be rendered in the currently assigned sprite sheet at the currently active index {@link index}
|
165
|
+
*/
|
166
|
+
set sprite(sprite: Sprite | undefined) {
|
167
|
+
if (!sprite) {
|
168
|
+
return;
|
169
|
+
}
|
170
|
+
if (!this.spriteSheet) {
|
171
|
+
this.spriteSheet = new SpriteSheet();
|
172
|
+
this.spriteSheet.sprites = [sprite];
|
173
|
+
this.index = 0;
|
174
|
+
}
|
175
|
+
else {
|
176
|
+
if (this.index === null || this.index === undefined) this.index = 0;
|
177
|
+
this.spriteSheet.sprites[this.index] = sprite;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
/** The currently active sprite */
|
181
|
+
get sprite(): Sprite | undefined {
|
182
|
+
if (!this.spriteSheet) return undefined;
|
183
|
+
return this.spriteSheet.sprites[this.index];
|
184
|
+
}
|
185
|
+
|
186
|
+
/**
|
187
|
+
* The spritesheet holds all sprites that can be rendered by the sprite renderer
|
188
|
+
*/
|
143
189
|
@serializable(SpriteSheet)
|
144
190
|
spriteSheet?: SpriteSheet;
|
145
191
|
|
192
|
+
/**
|
193
|
+
* The index of the sprite to be rendered in the currently assigned sprite sheet
|
194
|
+
*/
|
146
195
|
@serializable()
|
147
196
|
index: number = 0;
|
148
197
|
|
@@ -178,7 +227,7 @@
|
|
178
227
|
}
|
179
228
|
|
180
229
|
/**
|
181
|
-
* The sprite renderer renders a sprite on a GameObject using an assigned spritesheet ({@link SpriteData})
|
230
|
+
* The sprite renderer renders a sprite on a GameObject using an assigned spritesheet ({@link SpriteData}).
|
182
231
|
*/
|
183
232
|
export class SpriteRenderer extends Behaviour {
|
184
233
|
|
@@ -211,20 +260,67 @@
|
|
211
260
|
@serializable()
|
212
261
|
toneMapped: boolean = true;
|
213
262
|
|
263
|
+
/**
|
264
|
+
* Assign a new texture to the currently active sprite
|
265
|
+
*/
|
266
|
+
set texture(value: Texture | undefined) {
|
267
|
+
if (!this._spriteSheet) return;
|
268
|
+
const currentSprite = this._spriteSheet.spriteSheet?.sprites[this.spriteIndex];
|
269
|
+
if (!currentSprite) return;
|
270
|
+
currentSprite.texture = value;
|
271
|
+
this.updateSprite();
|
272
|
+
}
|
273
|
+
|
274
|
+
/**
|
275
|
+
* Add a new sprite to the currently assigned sprite sheet. The sprite will be added to the end of the sprite sheet.
|
276
|
+
* Note that the sprite will not be rendered by default - set the `spriteIndex` to the index of the sprite to be rendered.
|
277
|
+
* @param sprite The sprite to be added
|
278
|
+
* @returns The index of the sprite in the sprite sheet
|
279
|
+
* @example
|
280
|
+
* ```typescript
|
281
|
+
* const spriteRenderer = gameObject.addComponent(SpriteRenderer);
|
282
|
+
* const index = spriteRenderer.addSprite(mySprite);
|
283
|
+
* if(index >= 0)
|
284
|
+
* spriteRenderer.spriteIndex = index;
|
285
|
+
* ```
|
286
|
+
*/
|
287
|
+
addSprite(sprite: Sprite, setActive: boolean = false): number {
|
288
|
+
if (!this._spriteSheet) {
|
289
|
+
this._spriteSheet = SpriteData.create();
|
290
|
+
}
|
291
|
+
if (!this._spriteSheet.spriteSheet) return -1;
|
292
|
+
this._spriteSheet.spriteSheet?.sprites.push(sprite);
|
293
|
+
const index = this._spriteSheet.spriteSheet?.sprites.length - 1;
|
294
|
+
if (setActive) {
|
295
|
+
this.spriteIndex = index;
|
296
|
+
}
|
297
|
+
return index;
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
* Get the currently active sprite
|
302
|
+
*/
|
214
303
|
@serializable(SpriteData)
|
215
304
|
get sprite(): SpriteData | undefined {
|
216
305
|
return this._spriteSheet;
|
217
306
|
}
|
218
307
|
/**
|
219
|
-
* Set
|
308
|
+
* Set the sprite to be rendered in the currently assigned sprite sheet at the currently active index {@link spriteIndex}
|
220
309
|
*/
|
221
|
-
set sprite(value: SpriteData | undefined | number) {
|
310
|
+
set sprite(value: Sprite | SpriteData | undefined | number) {
|
222
311
|
if (value === this._spriteSheet) return;
|
223
312
|
if (typeof value === "number") {
|
224
313
|
const index = Math.floor(value);
|
225
314
|
this.spriteIndex = index;
|
226
315
|
return;
|
227
316
|
}
|
317
|
+
else if (value instanceof Sprite) {
|
318
|
+
if (!this._spriteSheet) {
|
319
|
+
this._spriteSheet = SpriteData.create();
|
320
|
+
}
|
321
|
+
this._spriteSheet.sprite = value;
|
322
|
+
this.updateSprite();
|
323
|
+
}
|
228
324
|
else {
|
229
325
|
this._spriteSheet = value;
|
230
326
|
this.updateSprite();
|
@@ -236,6 +332,7 @@
|
|
236
332
|
*/
|
237
333
|
set spriteIndex(value: number) {
|
238
334
|
if (!this._spriteSheet) return;
|
335
|
+
if (value === this.spriteIndex) return;
|
239
336
|
this._spriteSheet.index = value;
|
240
337
|
this.updateSprite();
|
241
338
|
}
|
@@ -255,6 +352,10 @@
|
|
255
352
|
/** @internal */
|
256
353
|
awake(): void {
|
257
354
|
this._currentSprite = undefined;
|
355
|
+
if (!this._spriteSheet) {
|
356
|
+
this._spriteSheet = new SpriteData();
|
357
|
+
this._spriteSheet.spriteSheet = new SpriteSheet();
|
358
|
+
}
|
258
359
|
if (debug) {
|
259
360
|
console.log("Awake", this.name, this, this.sprite);
|
260
361
|
}
|
@@ -270,19 +371,24 @@
|
|
270
371
|
|
271
372
|
/**
|
272
373
|
* Update the sprite. Modified properties will be applied to the sprite mesh. This method is called automatically when the sprite is changed.
|
374
|
+
* @param force If true, the sprite will be forced to update.
|
375
|
+
* @returns True if the sprite was updated successfully
|
273
376
|
*/
|
274
|
-
updateSprite(force: boolean = false) {
|
275
|
-
if (!this.__didAwake && !force) return;
|
276
|
-
|
277
|
-
|
377
|
+
updateSprite(force: boolean = false): boolean {
|
378
|
+
if (!this.__didAwake && !force) return false;
|
379
|
+
const data = this._spriteSheet;
|
380
|
+
if (!data?.spriteSheet?.sprites) {
|
381
|
+
console.warn("SpriteRenderer has no data or spritesheet assigned...");
|
382
|
+
return false;
|
383
|
+
}
|
384
|
+
const sprite = data.spriteSheet.sprites[this.spriteIndex];
|
278
385
|
if (!sprite) {
|
279
386
|
if (debug)
|
280
|
-
console.warn("Sprite not found", this.spriteIndex,
|
281
|
-
return;
|
387
|
+
console.warn("Sprite not found", this.spriteIndex, data.spriteSheet.sprites);
|
388
|
+
return false;
|
282
389
|
}
|
283
390
|
if (!this._currentSprite) {
|
284
391
|
const mat = new MeshBasicMaterial({ color: 0xffffff, side: DoubleSide });
|
285
|
-
if (!mat) return;
|
286
392
|
if (showWireframe)
|
287
393
|
mat.wireframe = true;
|
288
394
|
if (this.color) {
|
@@ -330,6 +436,7 @@
|
|
330
436
|
this.sharedMaterial.transparent = this.transparent;
|
331
437
|
}
|
332
438
|
this._currentSprite.castShadow = this.castShadows;
|
333
|
-
|
439
|
+
data?.update(this.sharedMaterial);
|
440
|
+
return true;
|
334
441
|
}
|
335
442
|
}
|