@combos-fun/engine 0.0.54 → 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.
@@ -1,7 +1,5 @@
1
1
  import EventEmitter from 'eventemitter3';
2
2
  import { isEqual, isObject } from 'lodash-es';
3
- import { __decorate } from 'tslib';
4
- import { Field } from '@combos-fun/inspector-decorator';
5
3
  import { ResourceState, ResourceType, Resource as Resource$1, Loader, XhrLoadStrategy, VideoLoadStrategy, MediaElementLoadStrategy, XhrResponseType, ImageLoadStrategy, AudioLoadStrategy, AbstractLoadStrategy } from 'resource-loader';
6
4
 
7
5
  /**
@@ -10,10 +8,10 @@ import { ResourceState, ResourceType, Resource as Resource$1, Loader, XhrLoadStr
10
8
  * @returns component' name
11
9
  * @example
12
10
  * ```typescript
13
- * import { Transform } from '@combos-fun/engine'
11
+ * import { Component } from '@combos-fun/engine'
14
12
  *
15
- * assert(getComponentName(Transform) === 'Transform')
16
- * assert(getComponentName(new Transform()) === 'Transform')
13
+ * assert(getComponentName(MyComponent) === 'MyComponent')
14
+ * assert(getComponentName(new MyComponent()) === 'MyComponent')
17
15
  * ```
18
16
  */
19
17
  function getComponentName(component) {
@@ -108,14 +106,38 @@ function removeObjectCache(component) {
108
106
  * @param {pureObserverProp} param0.prop - pure observer prop
109
107
  * @param {ObserverType} param0.type - observer type
110
108
  */
111
- function addObserver({ systemName, componentName, component, prop, type }) {
109
+ function addObserver({ systemName, componentName, component, prop, type, gameObject }) {
112
110
  systemInstance[systemName]?.componentObserver?.add({
113
111
  component,
114
112
  prop,
115
113
  type,
116
114
  componentName,
115
+ gameObject,
117
116
  });
118
117
  }
118
+ const GAME_OBJECT_OBSERVER = 'GameObject';
119
+ /**
120
+ * Push a GameObject field change (parent / inScene) to systems that observe `GameObject`.
121
+ * Hierarchy is not a Component; callers must notify explicitly from addChild / scene.
122
+ */
123
+ function notifyGameObjectProp(gameObject, propName, type = ObserverType.CHANGE) {
124
+ if (!gameObject)
125
+ return;
126
+ const prop = { prop: [propName], deep: false };
127
+ for (const systemName in observerInfos) {
128
+ const info = observerInfos[systemName]?.[GAME_OBJECT_OBSERVER];
129
+ if (!info?.some(p => p.prop[0] === propName))
130
+ continue;
131
+ addObserver({
132
+ systemName,
133
+ componentName: GAME_OBJECT_OBSERVER,
134
+ component: undefined,
135
+ gameObject,
136
+ prop,
137
+ type,
138
+ });
139
+ }
140
+ }
119
141
  function pushToQueue({ prop, component, componentName, }) {
120
142
  for (const systemName in observerInfos) {
121
143
  const observerInfo = observerInfos[systemName] || {};
@@ -291,154 +313,6 @@ function setSystemObserver(system, S) {
291
313
  systemInstance[S.systemName] = system;
292
314
  }
293
315
 
294
- /** Basic component for gameObject, See {@link TransformParams} */
295
- class Transform extends Component {
296
- constructor() {
297
- super(...arguments);
298
- this.name = 'Transform';
299
- this._parent = null;
300
- /** Whether this transform in a scene object */
301
- this.inScene = false;
302
- /** Child transform components */
303
- this.children = [];
304
- this.position = { x: 0, y: 0 };
305
- this.size = { width: 0, height: 0 };
306
- this.origin = { x: 0, y: 0 };
307
- this.anchor = { x: 0, y: 0 };
308
- this.scale = { x: 1, y: 1 };
309
- this.skew = { x: 0, y: 0 };
310
- this.rotation = 0;
311
- }
312
- /**
313
- * component's name
314
- * @readonly
315
- */
316
- static { this.componentName = 'Transform'; }
317
- /**
318
- * Init component
319
- * @param params - Transform init data
320
- */
321
- init(params = {}) {
322
- const props = ['position', 'size', 'origin', 'anchor', 'scale', 'skew'];
323
- for (const key of props) {
324
- Object.assign(this[key], params[key]);
325
- }
326
- this.rotation = params.rotation ?? this.rotation;
327
- }
328
- set parent(val) {
329
- if (val) {
330
- val.addChild(this);
331
- }
332
- else if (this.parent) {
333
- this.parent.removeChild(this);
334
- }
335
- }
336
- /**
337
- * Get parent of this component
338
- */
339
- get parent() {
340
- return this._parent;
341
- }
342
- /**
343
- * Add Child Transform
344
- * @remarks
345
- * If `child` is already a child of this component, `child` will removed to the last of children list
346
- * If `child` is already a child of other component, `child` will removed from its parent first
347
- * @param child - child gameObject's transform component
348
- */
349
- addChild(child) {
350
- if (child.parent === this) {
351
- const index = this.children.findIndex(item => item === child);
352
- this.children.splice(index, 1);
353
- }
354
- else if (child.parent) {
355
- child.parent.removeChild(child);
356
- }
357
- child._parent = this;
358
- this.children.push(child);
359
- }
360
- /**
361
- * Remove child transform
362
- * @param child - child gameObject's transform component
363
- */
364
- removeChild(child) {
365
- const index = this.children.findIndex(item => item === child);
366
- if (index > -1) {
367
- this.children.splice(index, 1);
368
- child._parent = null;
369
- }
370
- }
371
- /** Clear all child transform */
372
- clearChildren() {
373
- this.children.length = 0;
374
- }
375
- }
376
- __decorate([
377
- Field({
378
- type: 'vector2',
379
- step: 1,
380
- group: 'Transform',
381
- label: 'Position',
382
- description: 'Position on the design canvas (x right, y down).',
383
- })
384
- ], Transform.prototype, "position", void 0);
385
- __decorate([
386
- Field({
387
- type: 'size',
388
- step: 1,
389
- min: 0,
390
- group: 'Transform',
391
- label: 'Size',
392
- description: 'Width and height of the object in design pixels.',
393
- })
394
- ], Transform.prototype, "size", void 0);
395
- __decorate([
396
- Field({
397
- type: 'vector2',
398
- step: 0.1,
399
- group: 'Transform',
400
- label: 'Origin',
401
- description: 'Local origin used for layout math.',
402
- })
403
- ], Transform.prototype, "origin", void 0);
404
- __decorate([
405
- Field({
406
- type: 'vector2',
407
- step: 0.1,
408
- group: 'Transform',
409
- label: 'Anchor',
410
- description: 'Anchor point (0–1) used when positioning and scaling.',
411
- })
412
- ], Transform.prototype, "anchor", void 0);
413
- __decorate([
414
- Field({
415
- type: 'vector2',
416
- step: 0.1,
417
- group: 'Transform',
418
- label: 'Scale',
419
- description: 'Scale multipliers on X and Y (1 = original size).',
420
- })
421
- ], Transform.prototype, "scale", void 0);
422
- __decorate([
423
- Field({
424
- type: 'vector2',
425
- step: 0.1,
426
- group: 'Transform',
427
- label: 'Skew',
428
- description: 'Skew amounts on X and Y.',
429
- })
430
- ], Transform.prototype, "skew", void 0);
431
- __decorate([
432
- Field({
433
- type: 'number',
434
- step: 0.1,
435
- group: 'Transform',
436
- label: 'Rotation',
437
- description: 'Rotation in radians.',
438
- editor: 'number-stepper',
439
- })
440
- ], Transform.prototype, "rotation", void 0);
441
-
442
316
  let _id = 0;
443
317
  /** Generate unique id for gameObject */
444
318
  function getId() {
@@ -450,28 +324,23 @@ function getId() {
450
324
  */
451
325
  class GameObject {
452
326
  /**
453
- * Consruct a new gameObject
327
+ * Construct a new gameObject
454
328
  * @param name - the name of this gameObject
455
- * @param obj - optional transform parameters for default Transform component
456
329
  */
457
- constructor(name, obj) {
330
+ constructor(name) {
331
+ this._parent = null;
458
332
  /** A key-value map for components on this gameObject */
459
333
  this._componentCache = {};
334
+ /** Child gameObjects in sibling order */
335
+ this.children = [];
336
+ /** Whether this gameObject is registered on a scene */
337
+ this.inScene = false;
460
338
  /** Components apply to this gameObject */
461
339
  this.components = [];
462
340
  /** GameObject has been destroyed */
463
341
  this.destroyed = false;
464
342
  this._name = name;
465
343
  this.id = getId();
466
- this.addComponent(Transform, obj);
467
- }
468
- /**
469
- * Get default transform component
470
- * @returns transform component on this gameObject
471
- * @readonly
472
- */
473
- get transform() {
474
- return this.getComponent(Transform);
475
344
  }
476
345
  /**
477
346
  * Get parent gameObject
@@ -479,7 +348,7 @@ class GameObject {
479
348
  * @readonly
480
349
  */
481
350
  get parent() {
482
- return this.transform && this.transform.parent && this.transform.parent.gameObject;
351
+ return this._parent;
483
352
  }
484
353
  /**
485
354
  * Get the name of this gameObject
@@ -493,10 +362,8 @@ class GameObject {
493
362
  return;
494
363
  const scene = this._scene;
495
364
  this._scene = val;
496
- if (this.transform && this.transform.children) {
497
- for (const child of this.transform.children) {
498
- child.gameObject.scene = val;
499
- }
365
+ for (const child of this.children) {
366
+ child.scene = val;
500
367
  }
501
368
  if (val) {
502
369
  val.addGameObject(this);
@@ -518,16 +385,28 @@ class GameObject {
518
385
  * @param gameObject - child gameobject
519
386
  */
520
387
  addChild(gameObject) {
521
- if (!gameObject || !gameObject.transform || gameObject === this)
388
+ if (!gameObject || gameObject === this)
522
389
  return;
523
390
  if (!(gameObject instanceof GameObject)) {
524
391
  throw new Error('addChild only receive GameObject');
525
392
  }
526
- if (!this.transform) {
393
+ if (this.destroyed) {
527
394
  throw new Error(`gameObject '${this.name}' has been destroy`);
528
395
  }
529
- gameObject.transform.parent = this.transform;
396
+ if (gameObject.parent === this) {
397
+ const index = this.children.indexOf(gameObject);
398
+ if (index > -1)
399
+ this.children.splice(index, 1);
400
+ this.children.push(gameObject);
401
+ return;
402
+ }
403
+ if (gameObject.parent) {
404
+ gameObject.parent.removeChild(gameObject);
405
+ }
406
+ gameObject._parent = this;
407
+ this.children.push(gameObject);
530
408
  gameObject.scene = this.scene;
409
+ notifyGameObjectProp(gameObject, 'parent', ObserverType.CHANGE);
531
410
  }
532
411
  /**
533
412
  * Remove child gameObject
@@ -537,8 +416,12 @@ class GameObject {
537
416
  if (!(gameObject instanceof GameObject) || !gameObject.parent || gameObject.parent !== this) {
538
417
  return gameObject;
539
418
  }
540
- gameObject.transform.parent = null;
419
+ const index = this.children.indexOf(gameObject);
420
+ if (index > -1)
421
+ this.children.splice(index, 1);
422
+ gameObject._parent = null;
541
423
  gameObject.scene = null;
424
+ notifyGameObjectProp(gameObject, 'parent', ObserverType.CHANGE);
542
425
  return gameObject;
543
426
  }
544
427
  addComponent(C, obj) {
@@ -580,9 +463,6 @@ class GameObject {
580
463
  else if (c.componentName) {
581
464
  componentName = c.componentName;
582
465
  }
583
- if (componentName === 'Transform') {
584
- throw new Error("Transform can't be removed");
585
- }
586
466
  return this._removeComponent(componentName);
587
467
  }
588
468
  _removeComponent(componentName) {
@@ -625,15 +505,15 @@ class GameObject {
625
505
  }
626
506
  /** Destroy this gameObject */
627
507
  destroy() {
628
- if (!this.transform) {
508
+ if (this.destroyed) {
629
509
  console.error('Cannot destroy gameObject that have already been destroyed.');
630
510
  return;
631
511
  }
632
- Array.from(this.transform.children).forEach(({ gameObject }) => {
633
- gameObject.destroy();
512
+ Array.from(this.children).forEach(child => {
513
+ child.destroy();
634
514
  });
635
515
  this.remove();
636
- this.transform.clearChildren();
516
+ this.children.length = 0;
637
517
  for (const key in this._componentCache) {
638
518
  this._removeComponent(key);
639
519
  }
@@ -665,22 +545,30 @@ class ComponentObserver {
665
545
  * @param type - change event type
666
546
  * @param componentName - `component.name` this parameter will deprecated
667
547
  */
668
- add({ component, prop, type, componentName }) {
548
+ add({ component, prop, type, componentName, gameObject }) {
549
+ const go = gameObject ?? component?.gameObject;
669
550
  if (type === ObserverType.REMOVE) {
670
- if (this.events.find((changed) => changed.component === component && changed.type === ObserverType.ADD)) {
671
- this.events = this.events.filter(changed => changed.component !== component);
551
+ const sameTarget = (changed) => component
552
+ ? changed.component === component
553
+ : changed.gameObject === go && changed.componentName === componentName;
554
+ if (this.events.find(changed => sameTarget(changed) && changed.type === ObserverType.ADD)) {
555
+ this.events = this.events.filter(changed => !sameTarget(changed));
672
556
  return;
673
557
  }
674
- this.events = this.events.filter(changed => changed.component !== component);
558
+ this.events = this.events.filter(changed => !sameTarget(changed));
675
559
  }
676
- const index = this.events.findIndex(changed => changed.component === component && isEqual(changed.prop, prop) && changed.type === type);
560
+ const index = this.events.findIndex(changed => changed.gameObject === go &&
561
+ changed.component === component &&
562
+ changed.componentName === componentName &&
563
+ isEqual(changed.prop, prop) &&
564
+ changed.type === type);
677
565
  if (index > -1) {
678
566
  this.events.splice(index, 1);
679
567
  }
680
568
  this.events.push({
681
- gameObject: component.gameObject,
569
+ gameObject: go,
682
570
  component,
683
- prop: prop,
571
+ prop,
684
572
  type,
685
573
  componentName,
686
574
  });
@@ -955,8 +843,8 @@ class Ticker {
955
843
  * Scene is a gameObject container
956
844
  */
957
845
  class Scene extends GameObject {
958
- constructor(name, obj) {
959
- super(name, obj);
846
+ constructor(name) {
847
+ super(name);
960
848
  this.gameObjects = [];
961
849
  this.scene = this; // gameObject.scene = this
962
850
  }
@@ -966,9 +854,10 @@ class Scene extends GameObject {
966
854
  */
967
855
  addGameObject(gameObject) {
968
856
  this.gameObjects.push(gameObject);
969
- if (gameObject.transform) {
970
- gameObject.transform.inScene = true;
971
- }
857
+ if (gameObject.inScene)
858
+ return;
859
+ gameObject.inScene = true;
860
+ notifyGameObjectProp(gameObject, 'inScene', ObserverType.CHANGE);
972
861
  }
973
862
  /**
974
863
  * Remove gameObject
@@ -978,8 +867,9 @@ class Scene extends GameObject {
978
867
  const index = this.gameObjects.indexOf(gameObject);
979
868
  if (index === -1)
980
869
  return;
981
- if (gameObject.transform) {
982
- gameObject.transform.inScene = false;
870
+ if (gameObject.inScene) {
871
+ gameObject.inScene = false;
872
+ notifyGameObjectProp(gameObject, 'inScene', ObserverType.CHANGE);
983
873
  }
984
874
  this.gameObjects.splice(index, 1);
985
875
  }
@@ -995,7 +885,7 @@ class Scene extends GameObject {
995
885
  }
996
886
 
997
887
  /** Generated at build from package.json */
998
- const version = "0.0.54";
888
+ const version = "0.2.0";
999
889
 
1000
890
  /**
1001
891
  * Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
@@ -2170,5 +2060,5 @@ const decorators = {
2170
2060
  };
2171
2061
  console.log(`@combos-fun/engine version: ${version}`);
2172
2062
 
2173
- export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, Transform, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, normalizeResourceSrc, normalizeSpritesheetData, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
2063
+ export { COMBOS_GAME_PLUGIN_INIT_SUCCESS, COMBOS_GAME_READY, COMBOS_GAME_SET_PLAYING, COMBOS_GAME_STATE_CHANGED, Component, DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES, Game, GameObject, IDEProp, LOAD_EVENT, LOAD_SCENE_MODE, ObserverType as OBSERVER_TYPE, RESOURCE_TYPE, RESOURCE_TYPE_STRATEGY, Scene, System, componentObserver, decorators, isAllowedMessageOrigin, mergeAllowedMessageOrigins, normalizeResourceSrc, normalizeSpritesheetData, parseSetPlayingMessage, postParentGameReady, postParentGameState, postParentPluginInitSuccess, resource, resourceLoader, version };
2174
2064
  //# sourceMappingURL=engine.esm.js.map