@combos-fun/engine 0.0.53 → 0.2.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/agent-skill.md +1 -1
- package/combos-plugin.json +0 -1
- package/dist/engine.cjs.js +87 -198
- package/dist/engine.cjs.js.map +1 -1
- package/dist/engine.cjs.prod.js +1 -1
- package/dist/engine.d.ts +20 -115
- package/dist/engine.esm.js +88 -198
- package/dist/engine.esm.js.map +1 -1
- package/package.json +3 -3
- package/references/public-api.md +2 -2
package/agent-skill.md
CHANGED
|
@@ -8,7 +8,7 @@ Read when starting an engine task or resolving an engine API/lifecycle question.
|
|
|
8
8
|
|
|
9
9
|
## Microkernel model
|
|
10
10
|
|
|
11
|
-
- Core: `Game`, `Scene`, `GameObject`, `Component`, `System`, `
|
|
11
|
+
- Core: `Game`, `Scene`, `GameObject`, `Component`, `System`, `resource`, `decorators`. Hierarchy is `GameObject.parent` / `children` / `addChild`. 2D pose is `Transform2D` in `@combos-fun/plugin-renderer`; 3D pose is `Transform3D` in `@combos-fun/plugin-renderer-3d`.
|
|
12
12
|
- Register an instance with `await game.addSystem(new XxxSystem(...))`; `Game({ systems })` awaits each system's `init`. Avoid `addSystem(XxxSystem, [params])`: runtime passes the tuple as one constructor argument.
|
|
13
13
|
- Observe components with `@decorators.componentObserver({ Name: ['prop'] })`, then drain `componentObserver.clear()` in `update()`.
|
|
14
14
|
- Frame order: all `Component.update` → all `Component.lateUpdate` → all `System.update` → all `System.lateUpdate`. `start()` runs on the first update tick.
|
package/combos-plugin.json
CHANGED
package/dist/engine.cjs.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
var EventEmitter = require('eventemitter3');
|
|
4
4
|
var lodashEs = require('lodash-es');
|
|
5
|
-
var tslib = require('tslib');
|
|
6
|
-
var inspectorDecorator = require('@combos-fun/inspector-decorator');
|
|
7
5
|
var resourceLoader$1 = require('resource-loader');
|
|
8
6
|
|
|
9
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -16,10 +14,10 @@ var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
|
16
14
|
* @returns component' name
|
|
17
15
|
* @example
|
|
18
16
|
* ```typescript
|
|
19
|
-
* import {
|
|
17
|
+
* import { Component } from '@combos-fun/engine'
|
|
20
18
|
*
|
|
21
|
-
* assert(getComponentName(
|
|
22
|
-
* assert(getComponentName(new
|
|
19
|
+
* assert(getComponentName(MyComponent) === 'MyComponent')
|
|
20
|
+
* assert(getComponentName(new MyComponent()) === 'MyComponent')
|
|
23
21
|
* ```
|
|
24
22
|
*/
|
|
25
23
|
function getComponentName(component) {
|
|
@@ -114,14 +112,38 @@ function removeObjectCache(component) {
|
|
|
114
112
|
* @param {pureObserverProp} param0.prop - pure observer prop
|
|
115
113
|
* @param {ObserverType} param0.type - observer type
|
|
116
114
|
*/
|
|
117
|
-
function addObserver({ systemName, componentName, component, prop, type }) {
|
|
115
|
+
function addObserver({ systemName, componentName, component, prop, type, gameObject }) {
|
|
118
116
|
systemInstance[systemName]?.componentObserver?.add({
|
|
119
117
|
component,
|
|
120
118
|
prop,
|
|
121
119
|
type,
|
|
122
120
|
componentName,
|
|
121
|
+
gameObject,
|
|
123
122
|
});
|
|
124
123
|
}
|
|
124
|
+
const GAME_OBJECT_OBSERVER = 'GameObject';
|
|
125
|
+
/**
|
|
126
|
+
* Push a GameObject field change (parent / inScene) to systems that observe `GameObject`.
|
|
127
|
+
* Hierarchy is not a Component; callers must notify explicitly from addChild / scene.
|
|
128
|
+
*/
|
|
129
|
+
function notifyGameObjectProp(gameObject, propName, type = exports.OBSERVER_TYPE.CHANGE) {
|
|
130
|
+
if (!gameObject)
|
|
131
|
+
return;
|
|
132
|
+
const prop = { prop: [propName], deep: false };
|
|
133
|
+
for (const systemName in observerInfos) {
|
|
134
|
+
const info = observerInfos[systemName]?.[GAME_OBJECT_OBSERVER];
|
|
135
|
+
if (!info?.some(p => p.prop[0] === propName))
|
|
136
|
+
continue;
|
|
137
|
+
addObserver({
|
|
138
|
+
systemName,
|
|
139
|
+
componentName: GAME_OBJECT_OBSERVER,
|
|
140
|
+
component: undefined,
|
|
141
|
+
gameObject,
|
|
142
|
+
prop,
|
|
143
|
+
type,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
125
147
|
function pushToQueue({ prop, component, componentName, }) {
|
|
126
148
|
for (const systemName in observerInfos) {
|
|
127
149
|
const observerInfo = observerInfos[systemName] || {};
|
|
@@ -297,154 +319,6 @@ function setSystemObserver(system, S) {
|
|
|
297
319
|
systemInstance[S.systemName] = system;
|
|
298
320
|
}
|
|
299
321
|
|
|
300
|
-
/** Basic component for gameObject, See {@link TransformParams} */
|
|
301
|
-
class Transform extends Component {
|
|
302
|
-
constructor() {
|
|
303
|
-
super(...arguments);
|
|
304
|
-
this.name = 'Transform';
|
|
305
|
-
this._parent = null;
|
|
306
|
-
/** Whether this transform in a scene object */
|
|
307
|
-
this.inScene = false;
|
|
308
|
-
/** Child transform components */
|
|
309
|
-
this.children = [];
|
|
310
|
-
this.position = { x: 0, y: 0 };
|
|
311
|
-
this.size = { width: 0, height: 0 };
|
|
312
|
-
this.origin = { x: 0, y: 0 };
|
|
313
|
-
this.anchor = { x: 0, y: 0 };
|
|
314
|
-
this.scale = { x: 1, y: 1 };
|
|
315
|
-
this.skew = { x: 0, y: 0 };
|
|
316
|
-
this.rotation = 0;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* component's name
|
|
320
|
-
* @readonly
|
|
321
|
-
*/
|
|
322
|
-
static { this.componentName = 'Transform'; }
|
|
323
|
-
/**
|
|
324
|
-
* Init component
|
|
325
|
-
* @param params - Transform init data
|
|
326
|
-
*/
|
|
327
|
-
init(params = {}) {
|
|
328
|
-
const props = ['position', 'size', 'origin', 'anchor', 'scale', 'skew'];
|
|
329
|
-
for (const key of props) {
|
|
330
|
-
Object.assign(this[key], params[key]);
|
|
331
|
-
}
|
|
332
|
-
this.rotation = params.rotation ?? this.rotation;
|
|
333
|
-
}
|
|
334
|
-
set parent(val) {
|
|
335
|
-
if (val) {
|
|
336
|
-
val.addChild(this);
|
|
337
|
-
}
|
|
338
|
-
else if (this.parent) {
|
|
339
|
-
this.parent.removeChild(this);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Get parent of this component
|
|
344
|
-
*/
|
|
345
|
-
get parent() {
|
|
346
|
-
return this._parent;
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Add Child Transform
|
|
350
|
-
* @remarks
|
|
351
|
-
* If `child` is already a child of this component, `child` will removed to the last of children list
|
|
352
|
-
* If `child` is already a child of other component, `child` will removed from its parent first
|
|
353
|
-
* @param child - child gameObject's transform component
|
|
354
|
-
*/
|
|
355
|
-
addChild(child) {
|
|
356
|
-
if (child.parent === this) {
|
|
357
|
-
const index = this.children.findIndex(item => item === child);
|
|
358
|
-
this.children.splice(index, 1);
|
|
359
|
-
}
|
|
360
|
-
else if (child.parent) {
|
|
361
|
-
child.parent.removeChild(child);
|
|
362
|
-
}
|
|
363
|
-
child._parent = this;
|
|
364
|
-
this.children.push(child);
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Remove child transform
|
|
368
|
-
* @param child - child gameObject's transform component
|
|
369
|
-
*/
|
|
370
|
-
removeChild(child) {
|
|
371
|
-
const index = this.children.findIndex(item => item === child);
|
|
372
|
-
if (index > -1) {
|
|
373
|
-
this.children.splice(index, 1);
|
|
374
|
-
child._parent = null;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
/** Clear all child transform */
|
|
378
|
-
clearChildren() {
|
|
379
|
-
this.children.length = 0;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
tslib.__decorate([
|
|
383
|
-
inspectorDecorator.Field({
|
|
384
|
-
type: 'vector2',
|
|
385
|
-
step: 1,
|
|
386
|
-
group: 'Transform',
|
|
387
|
-
label: 'Position',
|
|
388
|
-
description: 'Position on the design canvas (x right, y down).',
|
|
389
|
-
})
|
|
390
|
-
], Transform.prototype, "position", void 0);
|
|
391
|
-
tslib.__decorate([
|
|
392
|
-
inspectorDecorator.Field({
|
|
393
|
-
type: 'size',
|
|
394
|
-
step: 1,
|
|
395
|
-
min: 0,
|
|
396
|
-
group: 'Transform',
|
|
397
|
-
label: 'Size',
|
|
398
|
-
description: 'Width and height of the object in design pixels.',
|
|
399
|
-
})
|
|
400
|
-
], Transform.prototype, "size", void 0);
|
|
401
|
-
tslib.__decorate([
|
|
402
|
-
inspectorDecorator.Field({
|
|
403
|
-
type: 'vector2',
|
|
404
|
-
step: 0.1,
|
|
405
|
-
group: 'Transform',
|
|
406
|
-
label: 'Origin',
|
|
407
|
-
description: 'Local origin used for layout math.',
|
|
408
|
-
})
|
|
409
|
-
], Transform.prototype, "origin", void 0);
|
|
410
|
-
tslib.__decorate([
|
|
411
|
-
inspectorDecorator.Field({
|
|
412
|
-
type: 'vector2',
|
|
413
|
-
step: 0.1,
|
|
414
|
-
group: 'Transform',
|
|
415
|
-
label: 'Anchor',
|
|
416
|
-
description: 'Anchor point (0–1) used when positioning and scaling.',
|
|
417
|
-
})
|
|
418
|
-
], Transform.prototype, "anchor", void 0);
|
|
419
|
-
tslib.__decorate([
|
|
420
|
-
inspectorDecorator.Field({
|
|
421
|
-
type: 'vector2',
|
|
422
|
-
step: 0.1,
|
|
423
|
-
group: 'Transform',
|
|
424
|
-
label: 'Scale',
|
|
425
|
-
description: 'Scale multipliers on X and Y (1 = original size).',
|
|
426
|
-
})
|
|
427
|
-
], Transform.prototype, "scale", void 0);
|
|
428
|
-
tslib.__decorate([
|
|
429
|
-
inspectorDecorator.Field({
|
|
430
|
-
type: 'vector2',
|
|
431
|
-
step: 0.1,
|
|
432
|
-
group: 'Transform',
|
|
433
|
-
label: 'Skew',
|
|
434
|
-
description: 'Skew amounts on X and Y.',
|
|
435
|
-
})
|
|
436
|
-
], Transform.prototype, "skew", void 0);
|
|
437
|
-
tslib.__decorate([
|
|
438
|
-
inspectorDecorator.Field({
|
|
439
|
-
type: 'number',
|
|
440
|
-
step: 0.1,
|
|
441
|
-
group: 'Transform',
|
|
442
|
-
label: 'Rotation',
|
|
443
|
-
description: 'Rotation in radians.',
|
|
444
|
-
editor: 'number-stepper',
|
|
445
|
-
})
|
|
446
|
-
], Transform.prototype, "rotation", void 0);
|
|
447
|
-
|
|
448
322
|
let _id = 0;
|
|
449
323
|
/** Generate unique id for gameObject */
|
|
450
324
|
function getId() {
|
|
@@ -456,28 +330,23 @@ function getId() {
|
|
|
456
330
|
*/
|
|
457
331
|
class GameObject {
|
|
458
332
|
/**
|
|
459
|
-
*
|
|
333
|
+
* Construct a new gameObject
|
|
460
334
|
* @param name - the name of this gameObject
|
|
461
|
-
* @param obj - optional transform parameters for default Transform component
|
|
462
335
|
*/
|
|
463
|
-
constructor(name
|
|
336
|
+
constructor(name) {
|
|
337
|
+
this._parent = null;
|
|
464
338
|
/** A key-value map for components on this gameObject */
|
|
465
339
|
this._componentCache = {};
|
|
340
|
+
/** Child gameObjects in sibling order */
|
|
341
|
+
this.children = [];
|
|
342
|
+
/** Whether this gameObject is registered on a scene */
|
|
343
|
+
this.inScene = false;
|
|
466
344
|
/** Components apply to this gameObject */
|
|
467
345
|
this.components = [];
|
|
468
346
|
/** GameObject has been destroyed */
|
|
469
347
|
this.destroyed = false;
|
|
470
348
|
this._name = name;
|
|
471
349
|
this.id = getId();
|
|
472
|
-
this.addComponent(Transform, obj);
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Get default transform component
|
|
476
|
-
* @returns transform component on this gameObject
|
|
477
|
-
* @readonly
|
|
478
|
-
*/
|
|
479
|
-
get transform() {
|
|
480
|
-
return this.getComponent(Transform);
|
|
481
350
|
}
|
|
482
351
|
/**
|
|
483
352
|
* Get parent gameObject
|
|
@@ -485,7 +354,7 @@ class GameObject {
|
|
|
485
354
|
* @readonly
|
|
486
355
|
*/
|
|
487
356
|
get parent() {
|
|
488
|
-
return this.
|
|
357
|
+
return this._parent;
|
|
489
358
|
}
|
|
490
359
|
/**
|
|
491
360
|
* Get the name of this gameObject
|
|
@@ -499,10 +368,8 @@ class GameObject {
|
|
|
499
368
|
return;
|
|
500
369
|
const scene = this._scene;
|
|
501
370
|
this._scene = val;
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
child.gameObject.scene = val;
|
|
505
|
-
}
|
|
371
|
+
for (const child of this.children) {
|
|
372
|
+
child.scene = val;
|
|
506
373
|
}
|
|
507
374
|
if (val) {
|
|
508
375
|
val.addGameObject(this);
|
|
@@ -524,16 +391,28 @@ class GameObject {
|
|
|
524
391
|
* @param gameObject - child gameobject
|
|
525
392
|
*/
|
|
526
393
|
addChild(gameObject) {
|
|
527
|
-
if (!gameObject ||
|
|
394
|
+
if (!gameObject || gameObject === this)
|
|
528
395
|
return;
|
|
529
396
|
if (!(gameObject instanceof GameObject)) {
|
|
530
397
|
throw new Error('addChild only receive GameObject');
|
|
531
398
|
}
|
|
532
|
-
if (
|
|
399
|
+
if (this.destroyed) {
|
|
533
400
|
throw new Error(`gameObject '${this.name}' has been destroy`);
|
|
534
401
|
}
|
|
535
|
-
gameObject.
|
|
402
|
+
if (gameObject.parent === this) {
|
|
403
|
+
const index = this.children.indexOf(gameObject);
|
|
404
|
+
if (index > -1)
|
|
405
|
+
this.children.splice(index, 1);
|
|
406
|
+
this.children.push(gameObject);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (gameObject.parent) {
|
|
410
|
+
gameObject.parent.removeChild(gameObject);
|
|
411
|
+
}
|
|
412
|
+
gameObject._parent = this;
|
|
413
|
+
this.children.push(gameObject);
|
|
536
414
|
gameObject.scene = this.scene;
|
|
415
|
+
notifyGameObjectProp(gameObject, 'parent', exports.OBSERVER_TYPE.CHANGE);
|
|
537
416
|
}
|
|
538
417
|
/**
|
|
539
418
|
* Remove child gameObject
|
|
@@ -543,8 +422,12 @@ class GameObject {
|
|
|
543
422
|
if (!(gameObject instanceof GameObject) || !gameObject.parent || gameObject.parent !== this) {
|
|
544
423
|
return gameObject;
|
|
545
424
|
}
|
|
546
|
-
|
|
425
|
+
const index = this.children.indexOf(gameObject);
|
|
426
|
+
if (index > -1)
|
|
427
|
+
this.children.splice(index, 1);
|
|
428
|
+
gameObject._parent = null;
|
|
547
429
|
gameObject.scene = null;
|
|
430
|
+
notifyGameObjectProp(gameObject, 'parent', exports.OBSERVER_TYPE.CHANGE);
|
|
548
431
|
return gameObject;
|
|
549
432
|
}
|
|
550
433
|
addComponent(C, obj) {
|
|
@@ -586,9 +469,6 @@ class GameObject {
|
|
|
586
469
|
else if (c.componentName) {
|
|
587
470
|
componentName = c.componentName;
|
|
588
471
|
}
|
|
589
|
-
if (componentName === 'Transform') {
|
|
590
|
-
throw new Error("Transform can't be removed");
|
|
591
|
-
}
|
|
592
472
|
return this._removeComponent(componentName);
|
|
593
473
|
}
|
|
594
474
|
_removeComponent(componentName) {
|
|
@@ -631,15 +511,15 @@ class GameObject {
|
|
|
631
511
|
}
|
|
632
512
|
/** Destroy this gameObject */
|
|
633
513
|
destroy() {
|
|
634
|
-
if (
|
|
514
|
+
if (this.destroyed) {
|
|
635
515
|
console.error('Cannot destroy gameObject that have already been destroyed.');
|
|
636
516
|
return;
|
|
637
517
|
}
|
|
638
|
-
Array.from(this.
|
|
639
|
-
|
|
518
|
+
Array.from(this.children).forEach(child => {
|
|
519
|
+
child.destroy();
|
|
640
520
|
});
|
|
641
521
|
this.remove();
|
|
642
|
-
this.
|
|
522
|
+
this.children.length = 0;
|
|
643
523
|
for (const key in this._componentCache) {
|
|
644
524
|
this._removeComponent(key);
|
|
645
525
|
}
|
|
@@ -671,22 +551,30 @@ class ComponentObserver {
|
|
|
671
551
|
* @param type - change event type
|
|
672
552
|
* @param componentName - `component.name` this parameter will deprecated
|
|
673
553
|
*/
|
|
674
|
-
add({ component, prop, type, componentName }) {
|
|
554
|
+
add({ component, prop, type, componentName, gameObject }) {
|
|
555
|
+
const go = gameObject ?? component?.gameObject;
|
|
675
556
|
if (type === exports.OBSERVER_TYPE.REMOVE) {
|
|
676
|
-
|
|
677
|
-
|
|
557
|
+
const sameTarget = (changed) => component
|
|
558
|
+
? changed.component === component
|
|
559
|
+
: changed.gameObject === go && changed.componentName === componentName;
|
|
560
|
+
if (this.events.find(changed => sameTarget(changed) && changed.type === exports.OBSERVER_TYPE.ADD)) {
|
|
561
|
+
this.events = this.events.filter(changed => !sameTarget(changed));
|
|
678
562
|
return;
|
|
679
563
|
}
|
|
680
|
-
this.events = this.events.filter(changed => changed
|
|
564
|
+
this.events = this.events.filter(changed => !sameTarget(changed));
|
|
681
565
|
}
|
|
682
|
-
const index = this.events.findIndex(changed => changed.
|
|
566
|
+
const index = this.events.findIndex(changed => changed.gameObject === go &&
|
|
567
|
+
changed.component === component &&
|
|
568
|
+
changed.componentName === componentName &&
|
|
569
|
+
lodashEs.isEqual(changed.prop, prop) &&
|
|
570
|
+
changed.type === type);
|
|
683
571
|
if (index > -1) {
|
|
684
572
|
this.events.splice(index, 1);
|
|
685
573
|
}
|
|
686
574
|
this.events.push({
|
|
687
|
-
gameObject:
|
|
575
|
+
gameObject: go,
|
|
688
576
|
component,
|
|
689
|
-
prop
|
|
577
|
+
prop,
|
|
690
578
|
type,
|
|
691
579
|
componentName,
|
|
692
580
|
});
|
|
@@ -961,8 +849,8 @@ class Ticker {
|
|
|
961
849
|
* Scene is a gameObject container
|
|
962
850
|
*/
|
|
963
851
|
class Scene extends GameObject {
|
|
964
|
-
constructor(name
|
|
965
|
-
super(name
|
|
852
|
+
constructor(name) {
|
|
853
|
+
super(name);
|
|
966
854
|
this.gameObjects = [];
|
|
967
855
|
this.scene = this; // gameObject.scene = this
|
|
968
856
|
}
|
|
@@ -972,9 +860,10 @@ class Scene extends GameObject {
|
|
|
972
860
|
*/
|
|
973
861
|
addGameObject(gameObject) {
|
|
974
862
|
this.gameObjects.push(gameObject);
|
|
975
|
-
if (gameObject.
|
|
976
|
-
|
|
977
|
-
|
|
863
|
+
if (gameObject.inScene)
|
|
864
|
+
return;
|
|
865
|
+
gameObject.inScene = true;
|
|
866
|
+
notifyGameObjectProp(gameObject, 'inScene', exports.OBSERVER_TYPE.CHANGE);
|
|
978
867
|
}
|
|
979
868
|
/**
|
|
980
869
|
* Remove gameObject
|
|
@@ -984,8 +873,9 @@ class Scene extends GameObject {
|
|
|
984
873
|
const index = this.gameObjects.indexOf(gameObject);
|
|
985
874
|
if (index === -1)
|
|
986
875
|
return;
|
|
987
|
-
if (gameObject.
|
|
988
|
-
gameObject.
|
|
876
|
+
if (gameObject.inScene) {
|
|
877
|
+
gameObject.inScene = false;
|
|
878
|
+
notifyGameObjectProp(gameObject, 'inScene', exports.OBSERVER_TYPE.CHANGE);
|
|
989
879
|
}
|
|
990
880
|
this.gameObjects.splice(index, 1);
|
|
991
881
|
}
|
|
@@ -1001,7 +891,7 @@ class Scene extends GameObject {
|
|
|
1001
891
|
}
|
|
1002
892
|
|
|
1003
893
|
/** Generated at build from package.json */
|
|
1004
|
-
const version = "0.0
|
|
894
|
+
const version = "0.2.0";
|
|
1005
895
|
|
|
1006
896
|
/**
|
|
1007
897
|
* Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
|
|
@@ -2188,7 +2078,6 @@ exports.IDEProp = IDEProp;
|
|
|
2188
2078
|
exports.RESOURCE_TYPE_STRATEGY = RESOURCE_TYPE_STRATEGY;
|
|
2189
2079
|
exports.Scene = Scene;
|
|
2190
2080
|
exports.System = System;
|
|
2191
|
-
exports.Transform = Transform;
|
|
2192
2081
|
exports.componentObserver = componentObserver;
|
|
2193
2082
|
exports.decorators = decorators;
|
|
2194
2083
|
exports.isAllowedMessageOrigin = isAllowedMessageOrigin;
|