import { _decorator, Component, sp } from 'cc'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { ensureSpineSkeletonDataRuntime } from 'db://assets/mx/module/lang/spineRuntimePatch'; import { BattleSpinePlayback } from 'db://assets/script/battle/presentation/BattleSpinePlayback'; const { ccclass } = _decorator; /** 受击/爆炸 Spine 预制体播放组件(prefab/爆炸/*) */ @ccclass('BombSpine') export class BombSpine extends Component { Sk: sp.Skeleton | null = null; private _baseTimeScale = 1; protected onLoad(): void { this.Sk = this.node.getComponent(sp.Skeleton) ?? this.node.getComponentInChildren(sp.Skeleton); } protected onEnable(): void { GEvent.Ins.on(GEvent.BattleTimeScaleChanged, this._syncBattleTimeScale, this); this._syncBattleTimeScale(); } protected onDisable(): void { GEvent.Ins.off(GEvent.BattleTimeScaleChanged, this._syncBattleTimeScale, this); } playSpine(name: string, callback: (() => void) | null = null, timeScale = 1, loop = false): void { if (!this.Sk) { this.Sk = this.node.getComponent(sp.Skeleton) ?? this.node.getComponentInChildren(sp.Skeleton); } if (!this.Sk) { callback?.(); return; } this.Sk.enabled = true; this._baseTimeScale = timeScale; this.Sk.setAnimationCacheMode(sp.SpineAnimationCacheMode.REALTIME); if (this.Sk.skeletonData) { ensureSpineSkeletonDataRuntime(this.Sk.skeletonData); } BattleSpinePlayback.resetTracks(this.Sk); this._syncBattleTimeScale(); // BattleSpinePlayback 失败路径已回调 onComplete,此处禁止再调,避免 double destoryNode BattleSpinePlayback.play(this.Sk, name, { loop, timeScale, onComplete: callback ?? undefined, }); } /** 战斗暂停/恢复时同步 timeScale,避免暂停中加载的受击特效永久定格 */ private _syncBattleTimeScale(): void { if (!this.Sk?.isValid) return; const battleScale = gg.game.CurentBattle?.TimeScale ?? 1; this.Sk.timeScale = this._baseTimeScale * battleScale; } destoryNode(): void { gg.res.putNode(this.node); } }