@eva/spine-base 2.0.1-beta.9 → 2.0.2-beta.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,21 +1,21 @@
1
1
  import { Component, resource, OBSERVER_TYPE, decorators } from '@eva/eva.js';
2
2
  import { Renderer, RendererSystem } from '@eva/plugin-renderer';
3
+ import { Container } from 'pixi.js';
3
4
  import { type } from '@eva/inspector-decorator';
4
- import { Assets } from 'pixi.js';
5
5
 
6
- /*! *****************************************************************************
7
- Copyright (c) Microsoft Corporation. All rights reserved.
8
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
9
- this file except in compliance with the License. You may obtain a copy of the
10
- License at http://www.apache.org/licenses/LICENSE-2.0
6
+ /******************************************************************************
7
+ Copyright (c) Microsoft Corporation.
11
8
 
12
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
14
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
15
- MERCHANTABLITY OR NON-INFRINGEMENT.
9
+ Permission to use, copy, modify, and/or distribute this software for any
10
+ purpose with or without fee is hereby granted.
16
11
 
17
- See the Apache Version 2.0 License for specific language governing permissions
18
- and limitations under the License.
12
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
13
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
15
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
17
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18
+ PERFORMANCE OF THIS SOFTWARE.
19
19
  ***************************************************************************** */
20
20
 
21
21
  function __decorate(decorators, target, key, desc) {
@@ -26,23 +26,98 @@ function __decorate(decorators, target, key, desc) {
26
26
  }
27
27
 
28
28
  function __awaiter(thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
29
30
  return new (P || (P = Promise))(function (resolve, reject) {
30
31
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
31
32
  function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
32
- function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
33
34
  step((generator = generator.apply(thisArg, _arguments || [])).next());
34
35
  });
35
- }
36
+ }
37
+
38
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
39
+ var e = new Error(message);
40
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
41
+ };
36
42
 
43
+ /**
44
+ * Spine 骨骼动画组件
45
+ *
46
+ * Spine 组件用于播放 Esoteric Software 的 Spine 骨骼动画。
47
+ * 支持骨骼动画播放控制、动画混合、附件替换等高级功能,
48
+ * 适用于角色动画、复杂特效等需要骨骼动画的场景。
49
+ *
50
+ * 主要功能:
51
+ * - 骨骼动画播放和控制
52
+ * - 动画轨道管理(多动画并行)
53
+ * - 动画混合过渡
54
+ * - 骨骼和附件访问
55
+ * - 支持 Spine 3.6 和 3.8 版本
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // 创建 Spine 动画
60
+ * const character = new GameObject('character');
61
+ * const spine = new Spine({
62
+ * resource: 'heroSpine', // Spine 资源
63
+ * animationName: 'idle', // 默认动画
64
+ * autoPlay: true, // 自动播放
65
+ * scale: 0.5 // 缩放比例
66
+ * });
67
+ * character.addComponent(spine);
68
+ *
69
+ * // 播放动画
70
+ * spine.play('walk', true); // 循环播放 walk 动画
71
+ *
72
+ * // 停止动画
73
+ * spine.stop();
74
+ *
75
+ * // 动画混合
76
+ * spine.setMix('idle', 'walk', 0.3); // 设置过渡时间
77
+ * spine.play('walk');
78
+ *
79
+ * // 添加动画队列
80
+ * spine.play('attack', false); // 播放攻击动画
81
+ * spine.addAnimation('idle', 0, true); // 攻击完成后回到 idle
82
+ *
83
+ * // 替换附件(换装)
84
+ * spine.setAttachment('weapon', 'sword'); // 将武器槽替换为剑
85
+ *
86
+ * // 访问骨骼
87
+ * const headBone = spine.getBone('head');
88
+ * if (headBone) {
89
+ * headBone.rotation = 15; // 旋转头部
90
+ * }
91
+ *
92
+ * // 多轨道动画
93
+ * spine.play('walk', true, 0); // 轨道0:身体动画
94
+ * spine.play('shoot', false, 1); // 轨道1:上半身动画
95
+ * ```
96
+ */
37
97
  class Spine extends Component {
38
98
  constructor() {
39
99
  super(...arguments);
100
+ /** Spine 资源名称 */
40
101
  this.resource = '';
102
+ /** 动画缩放比例 */
41
103
  this.scale = 1;
104
+ /** 当前播放的动画名称 */
42
105
  this.animationName = '';
106
+ /** 是否自动播放动画 */
43
107
  this.autoPlay = true;
108
+ /** 是否保留资源(销毁时不释放) */
109
+ this.keepResource = false;
110
+ /** 挂载到插槽的 GameObject 映射(GameObject -> { slot, wrapper }) */
111
+ this._slotGameObjects = new Map();
112
+ /** 等待容器就绪的 slot 挂载请求 */
113
+ this._pendingSlotObjects = [];
114
+ /** 等待执行的动画操作队列 */
44
115
  this.waitExecuteInfos = [];
45
116
  }
117
+ /**
118
+ * 设置骨架实例
119
+ * 当骨架加载完成后自动执行等待队列中的动画操作
120
+ */
46
121
  set armature(val) {
47
122
  this._armature = val;
48
123
  if (!val)
@@ -61,17 +136,36 @@ class Spine extends Component {
61
136
  }
62
137
  this.waitExecuteInfos = [];
63
138
  }
139
+ /** 获取骨架实例 */
64
140
  get armature() {
65
141
  return this._armature;
66
142
  }
143
+ /**
144
+ * 初始化组件
145
+ * @param obj - 初始化参数
146
+ * @param obj.resource - Spine 资源名称
147
+ * @param obj.animationName - 默认动画名称
148
+ * @param obj.scale - 缩放比例
149
+ * @param obj.autoPlay - 是否自动播放
150
+ */
67
151
  init(obj) {
68
152
  if (!obj)
69
153
  return;
70
154
  Object.assign(this, obj);
71
155
  }
156
+ /** 组件销毁时调用 */
72
157
  onDestroy() {
73
158
  this.destroied = true;
74
159
  }
160
+ /**
161
+ * 播放指定动画
162
+ *
163
+ * 如果骨架尚未加载完成,动画操作将被加入等待队列。
164
+ *
165
+ * @param name - 动画名称,不指定则使用 animationName 属性
166
+ * @param loopAnimation - 是否循环播放,默认跟随 autoPlay 属性
167
+ * @param track - 动画轨道编号,默认为 0
168
+ */
75
169
  play(name, loopAnimation, track) {
76
170
  try {
77
171
  const loop = loopAnimation !== null && loopAnimation !== void 0 ? loopAnimation : this.autoPlay;
@@ -81,6 +175,12 @@ class Spine extends Component {
81
175
  this.waitExecuteInfos.push({
82
176
  playType: true,
83
177
  name,
178
+ /**
179
+ * 在 v1.2.2 之前,Spine 动画的 autoPlay 为 true,动画会循环播放 https://github.com/eva-engine/eva.js/pull/164/files#diff-46e9ae36c04e7a0abedc1e14fd9d1c4e81d8386e9bb851f85971ccdba8957804L131
180
+ * 在 v1.2.2 之前,Spine 动画在每加载完( armature 设置之前)调用 play 是不生效的, 在 v1.2.2 [#164](https://github.com/eva-engine/eva.js/pull/164) 解决了这个问题
181
+ * 解决了不生效的问题以后,加载完成之前调用 play 默认循环是false,导致 autoPlay 下本来循环动画不循环了,和之前表现不一致
182
+ * 为了解决这个问题,在 autoPlay 的情况下,未加载完之前调用 play ,默认循环播放,除非设置不循环参数
183
+ */
84
184
  loop,
85
185
  track,
86
186
  });
@@ -96,6 +196,13 @@ class Spine extends Component {
96
196
  console.log(e);
97
197
  }
98
198
  }
199
+ /**
200
+ * 停止指定轨道的动画
201
+ *
202
+ * 如果骨架尚未加载完成,停止操作将被加入等待队列。
203
+ *
204
+ * @param track - 动画轨道编号,默认为 0
205
+ */
99
206
  stop(track) {
100
207
  if (!this.armature) {
101
208
  this.waitExecuteInfos.push({
@@ -109,6 +216,16 @@ class Spine extends Component {
109
216
  }
110
217
  this.armature.state.setEmptyAnimation(track, 0);
111
218
  }
219
+ /**
220
+ * 在当前动画之后添加新动画到队列
221
+ *
222
+ * 用于创建动画序列,当前动画播放完毕后自动播放下一个动画。
223
+ *
224
+ * @param name - 动画名称
225
+ * @param delay - 延迟时间(秒)
226
+ * @param loop - 是否循环播放
227
+ * @param track - 动画轨道编号,默认为 0
228
+ */
112
229
  addAnimation(name, delay, loop, track) {
113
230
  try {
114
231
  if (!this.armature) {
@@ -124,12 +241,27 @@ class Spine extends Component {
124
241
  console.log(e);
125
242
  }
126
243
  }
244
+ /**
245
+ * 设置两个动画之间的混合过渡时间
246
+ *
247
+ * 当从一个动画切换到另一个动画时,会在指定时间内进行平滑过渡。
248
+ *
249
+ * @param from - 起始动画名称
250
+ * @param to - 目标动画名称
251
+ * @param duration - 过渡时长(秒)
252
+ */
127
253
  setMix(from, to, duration) {
128
254
  if (!this.armature) ;
129
255
  else {
130
256
  this.armature.state.data.setMix(from, to, duration);
131
257
  }
132
258
  }
259
+ /**
260
+ * 获取指定轨道当前播放的动画名称
261
+ *
262
+ * @param track - 动画轨道编号,默认为 0
263
+ * @returns 动画名称,如果未找到则返回 undefined
264
+ */
133
265
  getAnim(track = 0) {
134
266
  try {
135
267
  if (!this.armature) {
@@ -142,25 +274,159 @@ class Spine extends Component {
142
274
  console.log(e);
143
275
  }
144
276
  }
277
+ /**
278
+ * 设置默认的动画混合时间
279
+ *
280
+ * 当没有为特定动画对指定混合时间时,将使用此默认值。
281
+ *
282
+ * @param duration - 默认混合时长(秒)
283
+ */
145
284
  setDefaultMix(duration) {
146
285
  if (!this.armature) ;
147
286
  else {
148
287
  this.armature.state.data.defaultMix = duration;
149
288
  }
150
289
  }
290
+ /**
291
+ * 替换指定插槽的附件
292
+ *
293
+ * 用于换装、武器切换等场景。
294
+ *
295
+ * @param slotName - 插槽名称
296
+ * @param attachmentName - 附件名称
297
+ */
151
298
  setAttachment(slotName, attachmentName) {
152
299
  if (!this.armature) {
153
300
  return;
154
301
  }
155
302
  this.armature.skeleton.setAttachment(slotName, attachmentName);
156
303
  }
304
+ /**
305
+ * 获取指定名称的骨骼
306
+ *
307
+ * 可用于直接操作骨骼的位置、旋转、缩放等属性。
308
+ *
309
+ * @param boneName - 骨骼名称
310
+ * @returns 骨骼对象,如果未找到则返回 undefined
311
+ */
157
312
  getBone(boneName) {
158
313
  if (!this.armature) {
159
314
  return;
160
315
  }
161
316
  return this.armature.skeleton.findBone(boneName);
162
317
  }
318
+ /**
319
+ * 将一个 GameObject 挂载到 Spine 的指定插槽上
320
+ *
321
+ * 挂载后 GameObject 会跟随骨骼运动。当 Spine 组件销毁时,
322
+ * 挂载的 GameObject 也会被自动销毁。
323
+ *
324
+ * @param slot - 插槽名称或索引
325
+ * @param gameObject - 要挂载的 GameObject
326
+ * @param options - 可选配置
327
+ * @param options.followAttachmentTimeline - 是否跟随插槽的附件时间线
328
+ */
329
+ addSlotObject(slot, gameObject, options) {
330
+ if (!this.armature) {
331
+ console.warn('Spine armature is not ready, cannot addSlotObject');
332
+ return;
333
+ }
334
+ if (!this._containerManager) {
335
+ console.warn('ContainerManager is not available');
336
+ return;
337
+ }
338
+ const container = this._containerManager.getContainer(gameObject.id);
339
+ if (!container) {
340
+ // 容器尚未就绪,加入 pending 队列,等待下一帧自动处理
341
+ this._pendingSlotObjects.push({ slot, gameObject, options });
342
+ return;
343
+ }
344
+ this._doAddSlotObject(slot, gameObject, container, options);
345
+ }
346
+ _doAddSlotObject(slot, gameObject, container, options) {
347
+ // 创建 wrapper 容器:Spine 骨骼矩阵作用在 wrapper 上,
348
+ // gameObject 的 container 作为子节点,其 transform 作为相对 slot 的局部偏移
349
+ const wrapper = new Container();
350
+ wrapper.addChild(container);
351
+ this.armature.addSlotObject(slot, wrapper, options);
352
+ this._slotGameObjects.set(gameObject, { slot, wrapper });
353
+ // slot object 可能不在 game.gameObjects 中,RendererSystem 不会自动同步 transform
354
+ // 手动同步 gameObject 及其子树的 transform 到 container
355
+ this._syncTransformTree(gameObject);
356
+ }
357
+ /**
358
+ * 递归同步 gameObject 及其子树的 transform 到对应的渲染容器
359
+ */
360
+ _syncTransformTree(gameObject) {
361
+ var _a;
362
+ if (!this._containerManager)
363
+ return;
364
+ this._containerManager.updateTransform({
365
+ name: gameObject.id,
366
+ transform: gameObject.transform,
367
+ });
368
+ if ((_a = gameObject.transform) === null || _a === void 0 ? void 0 : _a.children) {
369
+ for (const childTransform of gameObject.transform.children) {
370
+ if (childTransform.gameObject) {
371
+ this._syncTransformTree(childTransform.gameObject);
372
+ }
373
+ }
374
+ }
375
+ }
376
+ /**
377
+ * 处理等待容器就绪的 slot 挂载请求(由 SpineSystem 每帧调用)
378
+ */
379
+ _flushPendingSlotObjects() {
380
+ if (this._pendingSlotObjects.length === 0)
381
+ return;
382
+ if (!this.armature || !this._containerManager)
383
+ return;
384
+ const still = [];
385
+ for (const pending of this._pendingSlotObjects) {
386
+ const container = this._containerManager.getContainer(pending.gameObject.id);
387
+ if (container) {
388
+ this._doAddSlotObject(pending.slot, pending.gameObject, container, pending.options);
389
+ }
390
+ else {
391
+ still.push(pending);
392
+ }
393
+ }
394
+ this._pendingSlotObjects = still;
395
+ }
396
+ /**
397
+ * 从插槽上移除挂载的 GameObject
398
+ *
399
+ * @param gameObject - 要移除的 GameObject
400
+ */
401
+ removeSlotObject(gameObject) {
402
+ // 从 pending 队列中移除
403
+ this._pendingSlotObjects = this._pendingSlotObjects.filter(p => p.gameObject !== gameObject);
404
+ const entry = this._slotGameObjects.get(gameObject);
405
+ if (entry && this.armature) {
406
+ this.armature.removeSlotObject(entry.wrapper);
407
+ entry.wrapper.destroy({ children: false });
408
+ }
409
+ this._slotGameObjects.delete(gameObject);
410
+ }
411
+ /**
412
+ * 销毁所有挂载到插槽的 GameObject(内部使用)
413
+ */
414
+ _destroySlotGameObjects() {
415
+ for (const [gameObject, entry] of this._slotGameObjects) {
416
+ if (!gameObject.destroyed) {
417
+ // 先从 spine 插槽移除 wrapper,避免 destroy 时重复操作
418
+ if (this.armature) {
419
+ this.armature.removeSlotObject(entry.wrapper);
420
+ }
421
+ entry.wrapper.destroy({ children: false });
422
+ gameObject.destroy();
423
+ }
424
+ }
425
+ this._slotGameObjects.clear();
426
+ this._pendingSlotObjects = [];
427
+ }
163
428
  }
429
+ /** 组件名称 */
164
430
  Spine.componentName = 'Spine';
165
431
  __decorate([
166
432
  type('string')
@@ -173,7 +439,10 @@ __decorate([
173
439
  ], Spine.prototype, "animationName", void 0);
174
440
  __decorate([
175
441
  type('boolean')
176
- ], Spine.prototype, "autoPlay", void 0);
442
+ ], Spine.prototype, "autoPlay", void 0);
443
+ __decorate([
444
+ type('boolean')
445
+ ], Spine.prototype, "keepResource", void 0);
177
446
 
178
447
  let dataMap = {};
179
448
  function createSpineData(name, data, scale, pixiSpine) {
@@ -213,14 +482,6 @@ function releaseSpineData(res, _imageSrc) {
213
482
  data.ref--;
214
483
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
215
484
  if (data.ref <= 0) {
216
- yield Assets.unload([res.src.image.url, res.src.atlas.url, res.src.ske.url]);
217
- const resolver = Assets.resolver;
218
- delete resolver._assetMap[res.src.image.url];
219
- delete resolver._assetMap[res.src.atlas.url];
220
- delete resolver._assetMap[res.src.ske.url];
221
- delete resolver._resolverHash[res.src.image.url];
222
- delete resolver._resolverHash[res.src.atlas.url];
223
- delete resolver._resolverHash[res.src.ske.url];
224
485
  resource.destroy(resourceName);
225
486
  delete dataMap[resourceName];
226
487
  }
@@ -228,17 +489,41 @@ function releaseSpineData(res, _imageSrc) {
228
489
  }
229
490
 
230
491
  const MaxRetryCount = 20;
492
+ /**
493
+ * Spine 骨骼动画系统
494
+ *
495
+ * SpineSystem 负责管理所有 Spine 组件的骨架创建、动画更新和资源管理。
496
+ * 系统会监听 Spine 组件的变化,自动加载骨骼数据并创建动画实例,
497
+ * 并在每帧更新所有活跃的 Spine 动画。
498
+ *
499
+ * 主要功能:
500
+ * - 骨骼数据加载和缓存
501
+ * - 动画实例创建和销毁
502
+ * - 每帧动画状态更新
503
+ * - WebGL 上下文恢复处理
504
+ * - 资源重试机制
505
+ */
231
506
  let SpineSystem = class SpineSystem extends Renderer {
232
507
  constructor() {
233
508
  super(...arguments);
509
+ /** 骨架实例映射表(游戏对象 ID -> 骨架容器) */
234
510
  this.armatures = {};
511
+ /** Spine 组件实例映射(游戏对象 ID -> Spine 组件) */
512
+ this._spineComponents = {};
235
513
  }
514
+ /**
515
+ * 初始化系统
516
+ * @param obj - 初始化参数
517
+ * @param obj.pixiSpine - PixiJS Spine 插件实例
518
+ */
236
519
  init({ pixiSpine }) {
237
520
  this.renderSystem = this.game.getSystem(RendererSystem);
238
521
  this.renderSystem.rendererManager.register(this);
239
522
  this.pixiSpine = pixiSpine;
240
523
  this.game.canvas.addEventListener('webglcontextrestored', () => {
524
+ // 重建所有spine
241
525
  const objs = this.game.gameObjects;
526
+ // clearCache();
242
527
  let toAdd = [];
243
528
  for (let k in this.armatures) {
244
529
  const id = +k;
@@ -271,10 +556,20 @@ let SpineSystem = class SpineSystem extends Renderer {
271
556
  }, 1000);
272
557
  }, false);
273
558
  }
559
+ /**
560
+ * 每帧更新所有 Spine 动画
561
+ * @param e - 更新参数,包含帧间隔时间
562
+ */
274
563
  update(e) {
275
564
  for (let key in this.armatures) {
565
+ // TODO: 类型
566
+ // @ts-ignore
276
567
  this.armatures[key].update(e.deltaTime * 0.001);
277
568
  }
569
+ // 处理等待容器就绪的 slot 挂载请求
570
+ for (let key in this._spineComponents) {
571
+ this._spineComponents[key]._flushPendingSlotObjects();
572
+ }
278
573
  super.update();
279
574
  }
280
575
  componentChanged(changed) {
@@ -297,7 +592,7 @@ let SpineSystem = class SpineSystem extends Renderer {
297
592
  });
298
593
  }
299
594
  add(changed, count) {
300
- var _a, _b;
595
+ var _a, _b, _c;
301
596
  return __awaiter(this, void 0, void 0, function* () {
302
597
  const component = changed.component;
303
598
  clearTimeout(component.addHandler);
@@ -313,6 +608,7 @@ let SpineSystem = class SpineSystem extends Renderer {
313
608
  component.addHandler = setTimeout(() => {
314
609
  if (!component.destroied) {
315
610
  if (count === undefined) {
611
+ // 最大重试次数
316
612
  count = MaxRetryCount;
317
613
  }
318
614
  count--;
@@ -329,37 +625,48 @@ let SpineSystem = class SpineSystem extends Renderer {
329
625
  this.remove(changed);
330
626
  const container = (_b = (_a = this.renderSystem) === null || _a === void 0 ? void 0 : _a.containerManager) === null || _b === void 0 ? void 0 : _b.getContainer(changed.gameObject.id);
331
627
  if (!container) {
628
+ // console.warn('添加spine的container不存在');
332
629
  return;
333
630
  }
334
631
  component.lastResource = component.resource;
632
+ // @ts-ignore
335
633
  const armature = new this.pixiSpine.Spine({
336
634
  skeletonData: spineData,
337
635
  autoUpdate: false,
338
636
  });
339
637
  this.armatures[changed.gameObject.id] = armature;
638
+ this._spineComponents[changed.gameObject.id] = component;
340
639
  if (changed.gameObject && changed.gameObject.transform) {
341
640
  const tran = changed.gameObject.transform;
342
641
  armature.x = tran.size.width * tran.origin.x;
343
642
  armature.y = tran.size.height * tran.origin.y;
344
643
  }
345
644
  container.addChildAt(armature, 0);
645
+ /** 保证第一帧显示正常 */
346
646
  armature.update();
647
+ component._containerManager = (_c = this.renderSystem) === null || _c === void 0 ? void 0 : _c.containerManager;
347
648
  component.armature = armature;
649
+ // @ts-ignore
348
650
  component.emit('loaded', { resource: component.resource });
349
651
  armature.state.addListener({
652
+ // @ts-ignore
350
653
  start: (track, event) => {
351
654
  component.emit('start', { track, name: track.animation.name });
352
655
  },
656
+ // @ts-ignore
353
657
  complete: (track, event) => {
354
658
  component.emit('complete', { track, name: track.animation.name });
355
659
  },
660
+ // @ts-ignore
356
661
  interrupt: (track, event) => {
357
662
  component.emit('interrupt', { track, name: track.animation.name });
358
663
  },
359
- end: (track, event) => {
664
+ end: (track, // @ts-ignore
665
+ event) => {
360
666
  component.emit('end', { track, name: track.animation.name });
361
667
  },
362
668
  event: (track, event) => {
669
+ // @ts-ignore
363
670
  component.emit('event', track, event);
364
671
  },
365
672
  });
@@ -381,17 +688,23 @@ let SpineSystem = class SpineSystem extends Renderer {
381
688
  container.removeChild(armature);
382
689
  }
383
690
  if (component.armature) {
691
+ // 销毁所有挂载到插槽的 GameObject
692
+ component._destroySlotGameObjects();
384
693
  component.armature.destroy({ children: true });
385
- const res = yield resource.getResource(component.lastResource);
386
- ((_d = (_c = res.data) === null || _c === void 0 ? void 0 : _c.image) === null || _d === void 0 ? void 0 : _d.src) || ((_f = (_e = res.data) === null || _e === void 0 ? void 0 : _e.image) === null || _f === void 0 ? void 0 : _f.label);
387
- releaseSpineData(res);
694
+ if (!component.keepResource) {
695
+ const res = yield resource.getResource(component.lastResource);
696
+ ((_d = (_c = res.data) === null || _c === void 0 ? void 0 : _c.image) === null || _d === void 0 ? void 0 : _d.src) || ((_f = (_e = res.data) === null || _e === void 0 ? void 0 : _e.image) === null || _f === void 0 ? void 0 : _f.label);
697
+ releaseSpineData(res);
698
+ }
388
699
  }
389
700
  component.armature = null;
390
701
  delete this.armatures[changed.gameObject.id];
702
+ delete this._spineComponents[changed.gameObject.id];
391
703
  if (changed.type === OBSERVER_TYPE.CHANGE) ;
392
704
  });
393
705
  }
394
706
  };
707
+ /** 系统名称 */
395
708
  SpineSystem.systemName = 'SpineSystem';
396
709
  SpineSystem = __decorate([
397
710
  decorators.componentObserver({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eva/spine-base",
3
- "version": "2.0.1-beta.9",
3
+ "version": "2.0.2-beta.0",
4
4
  "description": "@eva/spine-base",
5
5
  "main": "index.js",
6
6
  "module": "dist/spine-base.esm.js",
@@ -18,9 +18,9 @@
18
18
  "license": "MIT",
19
19
  "homepage": "https://eva.js.org",
20
20
  "dependencies": {
21
- "@eva/eva.js": "2.0.1-beta.9",
22
- "@eva/plugin-renderer": "2.0.1-beta.9",
21
+ "@eva/eva.js": "2.0.2-beta.0",
22
+ "@eva/plugin-renderer": "2.0.2-beta.0",
23
23
  "@eva/inspector-decorator": "^0.0.5",
24
- "pixi.js": "^8.8.1"
24
+ "pixi.js": "^8.17.0"
25
25
  }
26
26
  }