using Cysharp.Threading.Tasks; using System; using System.Collections; using System.Collections.Generic; using DG.Tweening; using Spine; using Spine.Unity; using UnityEngine; public class SkeletonIllusionShadow : MonoBehaviour { // 记录所有残影对象,便于统一销毁 private readonly List illusionShadows = new List(); private SkeletonAnimation skeletonAnimation; private Color color = Color.white; private bool createSwitch = false; private int curFrame = 0; private int frameInteral = 6; public void SetSkeletonAnimation(SkeletonAnimation _skeletonAnimation) { skeletonAnimation = _skeletonAnimation; } public void Show(bool v, Color _color = default) { createSwitch = v; curFrame = 0; color = _color; if (!v) { // 清理所有残影对象 // for (int i = illusionShadows.Count - 1; i >= 0; i--) // { // var go = illusionShadows[i]; // if (go != null) // { // DOTween.Kill(go, complete: false); // if (Application.isPlaying) // Destroy(go); // else // DestroyImmediate(go); // } // } // illusionShadows.Clear(); } } public void Run() { if (createSwitch) { // 0.1秒创建一个残像 curFrame++; if (curFrame >= frameInteral) { curFrame -= frameInteral; CreateIllusionShadow(); } } } private void CreateIllusionShadow() { var src = skeletonAnimation.transform; // 保存源的世界变换 Vector3 worldPos = src.position; Quaternion worldRot = src.rotation; Vector3 worldScale = src.lossyScale; GameObject objTest = new GameObject("IllusionShadow"); illusionShadows.Add(objTest); objTest.transform.SetParent(null, false); objTest.transform.position = worldPos; objTest.transform.rotation = worldRot; objTest.transform.localScale = worldScale; // 当 parent == null 时 localScale == worldScale objTest.layer = LayerMask.NameToLayer("UI"); SkeletonAnimation sa = SkeletonAnimation.AddToGameObject(objTest, skeletonAnimation.skeletonDataAsset, false); TrackEntry trackEntry = skeletonAnimation.AnimationState.GetCurrent(0); TrackEntry playedEntry = sa.AnimationState.SetAnimation(0, trackEntry.Animation.Name, trackEntry.Loop); playedEntry.TrackTime = trackEntry.TrackTime; sa.timeScale = 0; RendererAdjuster parent = skeletonAnimation.GetComponentInParent(); if (parent == null) { BattleDebug.LogError("SkeletonIllusionShadow 创建残影失败,找不到 RendererAdjuster 组件"); GameObject.DestroyImmediate(objTest); return; } objTest.AddMissingComponent().SetSortingOrder(parent.sortingOrder - 1); sa.skeleton.R = color.r; sa.skeleton.G = color.g; sa.skeleton.B = color.b; sa.skeleton.A = 0.5F; //skeletonAnimation.skeleton.A; // 使用DoTween做alpha淡出,Tween与objTest绑定,便于统一Kill DOTween.To(() => sa.skeleton.A, x => { sa.skeleton.A = x; sa.LateUpdate(); }, 0f, 1f) .SetTarget(objTest); // 安全销毁,移除引用 _ = DestroyIllusionShadowAfterAsync(objTest, 1f); } // 用UniTask安全延迟销毁残影对象,多重安全检查 private async UniTaskVoid DestroyIllusionShadowAfterAsync(GameObject go, float delay) { try { await UniTask.Delay((int)(delay * 1000), cancellationToken: this.GetCancellationTokenOnDestroy()); } catch (OperationCanceledException) { // 对象已销毁,无需处理 return; } if (go == null) return; DOTween.Kill(go, complete: false); illusionShadows.Remove(go); if (Application.isPlaying) Destroy(go); else DestroyImmediate(go); } }