@playcanvas/web-components 0.3.0 → 0.6.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/LICENSE +21 -21
- package/README.md +84 -84
- package/dist/components/gsplat-component.d.ts +79 -0
- package/dist/components/light-component.d.ts +48 -0
- package/dist/index.d.ts +2 -2
- package/dist/pwc.cjs +324 -203
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +324 -203
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.mjs +325 -204
- package/dist/pwc.mjs.map +1 -1
- package/package.json +76 -66
- package/src/app.ts +612 -606
- package/src/asset.ts +159 -159
- package/src/async-element.ts +46 -46
- package/src/colors.ts +150 -150
- package/src/components/camera-component.ts +557 -557
- package/src/components/collision-component.ts +183 -183
- package/src/components/component.ts +97 -97
- package/src/components/element-component.ts +367 -367
- package/src/components/gsplat-component.ts +161 -0
- package/src/components/light-component.ts +570 -466
- package/src/components/listener-component.ts +30 -30
- package/src/components/particlesystem-component.ts +155 -155
- package/src/components/render-component.ts +147 -147
- package/src/components/rigidbody-component.ts +227 -227
- package/src/components/screen-component.ts +157 -157
- package/src/components/script-component.ts +270 -270
- package/src/components/script.ts +90 -90
- package/src/components/sound-component.ts +230 -230
- package/src/components/sound-slot.ts +288 -288
- package/src/entity.ts +360 -360
- package/src/index.ts +63 -63
- package/src/material.ts +141 -141
- package/src/model.ts +111 -111
- package/src/module.ts +43 -43
- package/src/scene.ts +217 -217
- package/src/sky.ts +293 -293
- package/src/utils.ts +71 -71
- package/dist/components/splat-component.d.ts +0 -61
- package/src/components/splat-component.ts +0 -133
package/src/entity.ts
CHANGED
|
@@ -1,360 +1,360 @@
|
|
|
1
|
-
import { AppBase, Entity, Vec3 } from 'playcanvas';
|
|
2
|
-
|
|
3
|
-
import { AsyncElement } from './async-element';
|
|
4
|
-
import { parseVec3 } from './utils';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The EntityElement interface provides properties and methods for manipulating
|
|
8
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
9
|
-
* The EntityElement interface also inherits the properties and methods of the
|
|
10
|
-
* {@link HTMLElement} interface.
|
|
11
|
-
*/
|
|
12
|
-
class EntityElement extends AsyncElement {
|
|
13
|
-
/**
|
|
14
|
-
* Whether the entity is enabled.
|
|
15
|
-
*/
|
|
16
|
-
private _enabled = true;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* The name of the entity.
|
|
20
|
-
*/
|
|
21
|
-
private _name = 'Untitled';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* The position of the entity.
|
|
25
|
-
*/
|
|
26
|
-
private _position = new Vec3();
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The rotation of the entity.
|
|
30
|
-
*/
|
|
31
|
-
private _rotation = new Vec3();
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* The scale of the entity.
|
|
35
|
-
*/
|
|
36
|
-
private _scale = new Vec3(1, 1, 1);
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* The tags of the entity.
|
|
40
|
-
*/
|
|
41
|
-
private _tags: string[] = [];
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The pointer event listeners for the entity.
|
|
45
|
-
*/
|
|
46
|
-
private _listeners: { [key: string]: EventListener[] } = {};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The PlayCanvas entity instance.
|
|
50
|
-
*/
|
|
51
|
-
entity: Entity | null = null;
|
|
52
|
-
|
|
53
|
-
createEntity(app: AppBase) {
|
|
54
|
-
// Create a new entity
|
|
55
|
-
this.entity = new Entity(this.getAttribute('name') || this._name, app);
|
|
56
|
-
|
|
57
|
-
const enabled = this.getAttribute('enabled');
|
|
58
|
-
if (enabled) {
|
|
59
|
-
this.entity.enabled = enabled !== 'false';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const position = this.getAttribute('position');
|
|
63
|
-
if (position) {
|
|
64
|
-
this.entity.setLocalPosition(parseVec3(position));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const rotation = this.getAttribute('rotation');
|
|
68
|
-
if (rotation) {
|
|
69
|
-
this.entity.setLocalEulerAngles(parseVec3(rotation));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const scale = this.getAttribute('scale');
|
|
73
|
-
if (scale) {
|
|
74
|
-
this.entity.setLocalScale(parseVec3(scale));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const tags = this.getAttribute('tags');
|
|
78
|
-
if (tags) {
|
|
79
|
-
this.entity.tags.add(tags.split(',').map(tag => tag.trim()));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Handle pointer events
|
|
83
|
-
const pointerEvents = [
|
|
84
|
-
'onpointerenter',
|
|
85
|
-
'onpointerleave',
|
|
86
|
-
'onpointerdown',
|
|
87
|
-
'onpointerup',
|
|
88
|
-
'onpointermove'
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
pointerEvents.forEach((eventName) => {
|
|
92
|
-
const handler = this.getAttribute(eventName);
|
|
93
|
-
if (handler) {
|
|
94
|
-
const eventType = eventName.substring(2); // remove 'on' prefix
|
|
95
|
-
const eventHandler = (event: Event) => {
|
|
96
|
-
try {
|
|
97
|
-
/* eslint-disable-next-line no-new-func */
|
|
98
|
-
new Function('event', handler).call(this, event);
|
|
99
|
-
} catch (e) {
|
|
100
|
-
console.error('Error in event handler:', e);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
this.addEventListener(eventType, eventHandler);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
buildHierarchy(app: AppBase) {
|
|
109
|
-
if (!this.entity) return;
|
|
110
|
-
|
|
111
|
-
const closestEntity = this.closestEntity;
|
|
112
|
-
if (closestEntity?.entity) {
|
|
113
|
-
closestEntity.entity.addChild(this.entity);
|
|
114
|
-
} else {
|
|
115
|
-
app.root.addChild(this.entity);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this._onReady();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
connectedCallback() {
|
|
122
|
-
// Wait for app to be ready
|
|
123
|
-
const closestApp = this.closestApp;
|
|
124
|
-
if (!closestApp) return;
|
|
125
|
-
|
|
126
|
-
// If app is already running, create entity immediately
|
|
127
|
-
if (closestApp.hierarchyReady) {
|
|
128
|
-
const app = closestApp.app!;
|
|
129
|
-
|
|
130
|
-
this.createEntity(app);
|
|
131
|
-
this.buildHierarchy(app);
|
|
132
|
-
|
|
133
|
-
// Handle any child entities that might exist
|
|
134
|
-
const childEntities = this.querySelectorAll<EntityElement>('pc-entity');
|
|
135
|
-
childEntities.forEach((child) => {
|
|
136
|
-
child.createEntity(app);
|
|
137
|
-
});
|
|
138
|
-
childEntities.forEach((child) => {
|
|
139
|
-
child.buildHierarchy(app);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
disconnectedCallback() {
|
|
145
|
-
if (this.entity) {
|
|
146
|
-
// Notify all children that their entities are about to become invalid
|
|
147
|
-
const children = this.querySelectorAll('pc-entity');
|
|
148
|
-
children.forEach((child) => {
|
|
149
|
-
(child as EntityElement).entity = null;
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Destroy the entity
|
|
153
|
-
this.entity.destroy();
|
|
154
|
-
this.entity = null;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Sets the enabled state of the entity.
|
|
160
|
-
* @param value - Whether the entity is enabled.
|
|
161
|
-
*/
|
|
162
|
-
set enabled(value) {
|
|
163
|
-
this._enabled = value;
|
|
164
|
-
if (this.entity) {
|
|
165
|
-
this.entity.enabled = value;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Gets the enabled state of the entity.
|
|
171
|
-
* @returns Whether the entity is enabled.
|
|
172
|
-
*/
|
|
173
|
-
get enabled() {
|
|
174
|
-
return this._enabled;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Sets the name of the entity.
|
|
179
|
-
* @param value - The name of the entity.
|
|
180
|
-
*/
|
|
181
|
-
set name(value) {
|
|
182
|
-
this._name = value;
|
|
183
|
-
if (this.entity) {
|
|
184
|
-
this.entity.name = value;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Gets the name of the entity.
|
|
190
|
-
* @returns The name of the entity.
|
|
191
|
-
*/
|
|
192
|
-
get name() {
|
|
193
|
-
return this._name;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Sets the position of the entity.
|
|
198
|
-
* @param value - The position of the entity.
|
|
199
|
-
*/
|
|
200
|
-
set position(value) {
|
|
201
|
-
this._position = value;
|
|
202
|
-
if (this.entity) {
|
|
203
|
-
this.entity.setLocalPosition(this._position);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Gets the position of the entity.
|
|
209
|
-
* @returns The position of the entity.
|
|
210
|
-
*/
|
|
211
|
-
get position() {
|
|
212
|
-
return this._position;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Sets the rotation of the entity.
|
|
217
|
-
* @param value - The rotation of the entity.
|
|
218
|
-
*/
|
|
219
|
-
set rotation(value) {
|
|
220
|
-
this._rotation = value;
|
|
221
|
-
if (this.entity) {
|
|
222
|
-
this.entity.setLocalEulerAngles(this._rotation);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Gets the rotation of the entity.
|
|
228
|
-
* @returns The rotation of the entity.
|
|
229
|
-
*/
|
|
230
|
-
get rotation() {
|
|
231
|
-
return this._rotation;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Sets the scale of the entity.
|
|
236
|
-
* @param value - The scale of the entity.
|
|
237
|
-
*/
|
|
238
|
-
set scale(value) {
|
|
239
|
-
this._scale = value;
|
|
240
|
-
if (this.entity) {
|
|
241
|
-
this.entity.setLocalScale(this._scale);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Gets the scale of the entity.
|
|
247
|
-
* @returns The scale of the entity.
|
|
248
|
-
*/
|
|
249
|
-
get scale() {
|
|
250
|
-
return this._scale;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Sets the tags of the entity.
|
|
255
|
-
* @param value - The tags of the entity.
|
|
256
|
-
*/
|
|
257
|
-
set tags(value) {
|
|
258
|
-
this._tags = value;
|
|
259
|
-
if (this.entity) {
|
|
260
|
-
this.entity.tags.clear();
|
|
261
|
-
this.entity.tags.add(this._tags);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Gets the tags of the entity.
|
|
267
|
-
* @returns The tags of the entity.
|
|
268
|
-
*/
|
|
269
|
-
get tags() {
|
|
270
|
-
return this._tags;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
static get observedAttributes() {
|
|
274
|
-
return [
|
|
275
|
-
'enabled',
|
|
276
|
-
'name',
|
|
277
|
-
'position',
|
|
278
|
-
'rotation',
|
|
279
|
-
'scale',
|
|
280
|
-
'tags',
|
|
281
|
-
'onpointerenter',
|
|
282
|
-
'onpointerleave',
|
|
283
|
-
'onpointerdown',
|
|
284
|
-
'onpointerup',
|
|
285
|
-
'onpointermove'
|
|
286
|
-
];
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
290
|
-
switch (name) {
|
|
291
|
-
case 'enabled':
|
|
292
|
-
this.enabled = newValue !== 'false';
|
|
293
|
-
break;
|
|
294
|
-
case 'name':
|
|
295
|
-
this.name = newValue;
|
|
296
|
-
break;
|
|
297
|
-
case 'position':
|
|
298
|
-
this.position = parseVec3(newValue);
|
|
299
|
-
break;
|
|
300
|
-
case 'rotation':
|
|
301
|
-
this.rotation = parseVec3(newValue);
|
|
302
|
-
break;
|
|
303
|
-
case 'scale':
|
|
304
|
-
this.scale = parseVec3(newValue);
|
|
305
|
-
break;
|
|
306
|
-
case 'tags':
|
|
307
|
-
this.tags = newValue.split(',').map(tag => tag.trim());
|
|
308
|
-
break;
|
|
309
|
-
case 'onpointerenter':
|
|
310
|
-
case 'onpointerleave':
|
|
311
|
-
case 'onpointerdown':
|
|
312
|
-
case 'onpointerup':
|
|
313
|
-
case 'onpointermove':
|
|
314
|
-
if (newValue) {
|
|
315
|
-
const eventName = name.substring(2);
|
|
316
|
-
// Use Function.prototype.bind to avoid new Function
|
|
317
|
-
const handler = (event: Event) => {
|
|
318
|
-
try {
|
|
319
|
-
const handlerStr = this.getAttribute(eventName) || '';
|
|
320
|
-
/* eslint-disable-next-line no-new-func */
|
|
321
|
-
new Function('event', handlerStr).call(this, event);
|
|
322
|
-
} catch (e) {
|
|
323
|
-
console.error('Error in event handler:', e);
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
this.addEventListener(eventName, handler);
|
|
327
|
-
}
|
|
328
|
-
break;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions) {
|
|
333
|
-
if (!this._listeners[type]) {
|
|
334
|
-
this._listeners[type] = [];
|
|
335
|
-
}
|
|
336
|
-
this._listeners[type].push(listener);
|
|
337
|
-
super.addEventListener(type, listener, options);
|
|
338
|
-
if (type.startsWith('pointer')) {
|
|
339
|
-
this.dispatchEvent(new CustomEvent(`${type}:connect`, { bubbles: true }));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions) {
|
|
344
|
-
if (this._listeners[type]) {
|
|
345
|
-
this._listeners[type] = this._listeners[type].filter(l => l !== listener);
|
|
346
|
-
}
|
|
347
|
-
super.removeEventListener(type, listener, options);
|
|
348
|
-
if (type.startsWith('pointer')) {
|
|
349
|
-
this.dispatchEvent(new CustomEvent(`${type}:disconnect`, { bubbles: true }));
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
hasListeners(type: string): boolean {
|
|
354
|
-
return Boolean(this._listeners[type]?.length);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
customElements.define('pc-entity', EntityElement);
|
|
359
|
-
|
|
360
|
-
export { EntityElement };
|
|
1
|
+
import { AppBase, Entity, Vec3 } from 'playcanvas';
|
|
2
|
+
|
|
3
|
+
import { AsyncElement } from './async-element';
|
|
4
|
+
import { parseVec3 } from './utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The EntityElement interface provides properties and methods for manipulating
|
|
8
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
9
|
+
* The EntityElement interface also inherits the properties and methods of the
|
|
10
|
+
* {@link HTMLElement} interface.
|
|
11
|
+
*/
|
|
12
|
+
class EntityElement extends AsyncElement {
|
|
13
|
+
/**
|
|
14
|
+
* Whether the entity is enabled.
|
|
15
|
+
*/
|
|
16
|
+
private _enabled = true;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The name of the entity.
|
|
20
|
+
*/
|
|
21
|
+
private _name = 'Untitled';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The position of the entity.
|
|
25
|
+
*/
|
|
26
|
+
private _position = new Vec3();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The rotation of the entity.
|
|
30
|
+
*/
|
|
31
|
+
private _rotation = new Vec3();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The scale of the entity.
|
|
35
|
+
*/
|
|
36
|
+
private _scale = new Vec3(1, 1, 1);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The tags of the entity.
|
|
40
|
+
*/
|
|
41
|
+
private _tags: string[] = [];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The pointer event listeners for the entity.
|
|
45
|
+
*/
|
|
46
|
+
private _listeners: { [key: string]: EventListener[] } = {};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The PlayCanvas entity instance.
|
|
50
|
+
*/
|
|
51
|
+
entity: Entity | null = null;
|
|
52
|
+
|
|
53
|
+
createEntity(app: AppBase) {
|
|
54
|
+
// Create a new entity
|
|
55
|
+
this.entity = new Entity(this.getAttribute('name') || this._name, app);
|
|
56
|
+
|
|
57
|
+
const enabled = this.getAttribute('enabled');
|
|
58
|
+
if (enabled) {
|
|
59
|
+
this.entity.enabled = enabled !== 'false';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const position = this.getAttribute('position');
|
|
63
|
+
if (position) {
|
|
64
|
+
this.entity.setLocalPosition(parseVec3(position));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const rotation = this.getAttribute('rotation');
|
|
68
|
+
if (rotation) {
|
|
69
|
+
this.entity.setLocalEulerAngles(parseVec3(rotation));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const scale = this.getAttribute('scale');
|
|
73
|
+
if (scale) {
|
|
74
|
+
this.entity.setLocalScale(parseVec3(scale));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const tags = this.getAttribute('tags');
|
|
78
|
+
if (tags) {
|
|
79
|
+
this.entity.tags.add(tags.split(',').map(tag => tag.trim()));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle pointer events
|
|
83
|
+
const pointerEvents = [
|
|
84
|
+
'onpointerenter',
|
|
85
|
+
'onpointerleave',
|
|
86
|
+
'onpointerdown',
|
|
87
|
+
'onpointerup',
|
|
88
|
+
'onpointermove'
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
pointerEvents.forEach((eventName) => {
|
|
92
|
+
const handler = this.getAttribute(eventName);
|
|
93
|
+
if (handler) {
|
|
94
|
+
const eventType = eventName.substring(2); // remove 'on' prefix
|
|
95
|
+
const eventHandler = (event: Event) => {
|
|
96
|
+
try {
|
|
97
|
+
/* eslint-disable-next-line no-new-func */
|
|
98
|
+
new Function('event', handler).call(this, event);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.error('Error in event handler:', e);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
this.addEventListener(eventType, eventHandler);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
buildHierarchy(app: AppBase) {
|
|
109
|
+
if (!this.entity) return;
|
|
110
|
+
|
|
111
|
+
const closestEntity = this.closestEntity;
|
|
112
|
+
if (closestEntity?.entity) {
|
|
113
|
+
closestEntity.entity.addChild(this.entity);
|
|
114
|
+
} else {
|
|
115
|
+
app.root.addChild(this.entity);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this._onReady();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
connectedCallback() {
|
|
122
|
+
// Wait for app to be ready
|
|
123
|
+
const closestApp = this.closestApp;
|
|
124
|
+
if (!closestApp) return;
|
|
125
|
+
|
|
126
|
+
// If app is already running, create entity immediately
|
|
127
|
+
if (closestApp.hierarchyReady) {
|
|
128
|
+
const app = closestApp.app!;
|
|
129
|
+
|
|
130
|
+
this.createEntity(app);
|
|
131
|
+
this.buildHierarchy(app);
|
|
132
|
+
|
|
133
|
+
// Handle any child entities that might exist
|
|
134
|
+
const childEntities = this.querySelectorAll<EntityElement>('pc-entity');
|
|
135
|
+
childEntities.forEach((child) => {
|
|
136
|
+
child.createEntity(app);
|
|
137
|
+
});
|
|
138
|
+
childEntities.forEach((child) => {
|
|
139
|
+
child.buildHierarchy(app);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
disconnectedCallback() {
|
|
145
|
+
if (this.entity) {
|
|
146
|
+
// Notify all children that their entities are about to become invalid
|
|
147
|
+
const children = this.querySelectorAll('pc-entity');
|
|
148
|
+
children.forEach((child) => {
|
|
149
|
+
(child as EntityElement).entity = null;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Destroy the entity
|
|
153
|
+
this.entity.destroy();
|
|
154
|
+
this.entity = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Sets the enabled state of the entity.
|
|
160
|
+
* @param value - Whether the entity is enabled.
|
|
161
|
+
*/
|
|
162
|
+
set enabled(value) {
|
|
163
|
+
this._enabled = value;
|
|
164
|
+
if (this.entity) {
|
|
165
|
+
this.entity.enabled = value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Gets the enabled state of the entity.
|
|
171
|
+
* @returns Whether the entity is enabled.
|
|
172
|
+
*/
|
|
173
|
+
get enabled() {
|
|
174
|
+
return this._enabled;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Sets the name of the entity.
|
|
179
|
+
* @param value - The name of the entity.
|
|
180
|
+
*/
|
|
181
|
+
set name(value) {
|
|
182
|
+
this._name = value;
|
|
183
|
+
if (this.entity) {
|
|
184
|
+
this.entity.name = value;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Gets the name of the entity.
|
|
190
|
+
* @returns The name of the entity.
|
|
191
|
+
*/
|
|
192
|
+
get name() {
|
|
193
|
+
return this._name;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Sets the position of the entity.
|
|
198
|
+
* @param value - The position of the entity.
|
|
199
|
+
*/
|
|
200
|
+
set position(value) {
|
|
201
|
+
this._position = value;
|
|
202
|
+
if (this.entity) {
|
|
203
|
+
this.entity.setLocalPosition(this._position);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Gets the position of the entity.
|
|
209
|
+
* @returns The position of the entity.
|
|
210
|
+
*/
|
|
211
|
+
get position() {
|
|
212
|
+
return this._position;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Sets the rotation of the entity.
|
|
217
|
+
* @param value - The rotation of the entity.
|
|
218
|
+
*/
|
|
219
|
+
set rotation(value) {
|
|
220
|
+
this._rotation = value;
|
|
221
|
+
if (this.entity) {
|
|
222
|
+
this.entity.setLocalEulerAngles(this._rotation);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Gets the rotation of the entity.
|
|
228
|
+
* @returns The rotation of the entity.
|
|
229
|
+
*/
|
|
230
|
+
get rotation() {
|
|
231
|
+
return this._rotation;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Sets the scale of the entity.
|
|
236
|
+
* @param value - The scale of the entity.
|
|
237
|
+
*/
|
|
238
|
+
set scale(value) {
|
|
239
|
+
this._scale = value;
|
|
240
|
+
if (this.entity) {
|
|
241
|
+
this.entity.setLocalScale(this._scale);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Gets the scale of the entity.
|
|
247
|
+
* @returns The scale of the entity.
|
|
248
|
+
*/
|
|
249
|
+
get scale() {
|
|
250
|
+
return this._scale;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Sets the tags of the entity.
|
|
255
|
+
* @param value - The tags of the entity.
|
|
256
|
+
*/
|
|
257
|
+
set tags(value) {
|
|
258
|
+
this._tags = value;
|
|
259
|
+
if (this.entity) {
|
|
260
|
+
this.entity.tags.clear();
|
|
261
|
+
this.entity.tags.add(this._tags);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Gets the tags of the entity.
|
|
267
|
+
* @returns The tags of the entity.
|
|
268
|
+
*/
|
|
269
|
+
get tags() {
|
|
270
|
+
return this._tags;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static get observedAttributes() {
|
|
274
|
+
return [
|
|
275
|
+
'enabled',
|
|
276
|
+
'name',
|
|
277
|
+
'position',
|
|
278
|
+
'rotation',
|
|
279
|
+
'scale',
|
|
280
|
+
'tags',
|
|
281
|
+
'onpointerenter',
|
|
282
|
+
'onpointerleave',
|
|
283
|
+
'onpointerdown',
|
|
284
|
+
'onpointerup',
|
|
285
|
+
'onpointermove'
|
|
286
|
+
];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
290
|
+
switch (name) {
|
|
291
|
+
case 'enabled':
|
|
292
|
+
this.enabled = newValue !== 'false';
|
|
293
|
+
break;
|
|
294
|
+
case 'name':
|
|
295
|
+
this.name = newValue;
|
|
296
|
+
break;
|
|
297
|
+
case 'position':
|
|
298
|
+
this.position = parseVec3(newValue);
|
|
299
|
+
break;
|
|
300
|
+
case 'rotation':
|
|
301
|
+
this.rotation = parseVec3(newValue);
|
|
302
|
+
break;
|
|
303
|
+
case 'scale':
|
|
304
|
+
this.scale = parseVec3(newValue);
|
|
305
|
+
break;
|
|
306
|
+
case 'tags':
|
|
307
|
+
this.tags = newValue.split(',').map(tag => tag.trim());
|
|
308
|
+
break;
|
|
309
|
+
case 'onpointerenter':
|
|
310
|
+
case 'onpointerleave':
|
|
311
|
+
case 'onpointerdown':
|
|
312
|
+
case 'onpointerup':
|
|
313
|
+
case 'onpointermove':
|
|
314
|
+
if (newValue) {
|
|
315
|
+
const eventName = name.substring(2);
|
|
316
|
+
// Use Function.prototype.bind to avoid new Function
|
|
317
|
+
const handler = (event: Event) => {
|
|
318
|
+
try {
|
|
319
|
+
const handlerStr = this.getAttribute(eventName) || '';
|
|
320
|
+
/* eslint-disable-next-line no-new-func */
|
|
321
|
+
new Function('event', handlerStr).call(this, event);
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error('Error in event handler:', e);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
this.addEventListener(eventName, handler);
|
|
327
|
+
}
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions) {
|
|
333
|
+
if (!this._listeners[type]) {
|
|
334
|
+
this._listeners[type] = [];
|
|
335
|
+
}
|
|
336
|
+
this._listeners[type].push(listener);
|
|
337
|
+
super.addEventListener(type, listener, options);
|
|
338
|
+
if (type.startsWith('pointer')) {
|
|
339
|
+
this.dispatchEvent(new CustomEvent(`${type}:connect`, { bubbles: true }));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions) {
|
|
344
|
+
if (this._listeners[type]) {
|
|
345
|
+
this._listeners[type] = this._listeners[type].filter(l => l !== listener);
|
|
346
|
+
}
|
|
347
|
+
super.removeEventListener(type, listener, options);
|
|
348
|
+
if (type.startsWith('pointer')) {
|
|
349
|
+
this.dispatchEvent(new CustomEvent(`${type}:disconnect`, { bubbles: true }));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
hasListeners(type: string): boolean {
|
|
354
|
+
return Boolean(this._listeners[type]?.length);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
customElements.define('pc-entity', EntityElement);
|
|
359
|
+
|
|
360
|
+
export { EntityElement };
|