| 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<GameObject> illusionShadows = new List<GameObject>(); | 
|     private SkeletonAnimation skeletonAnimation; | 
|   | 
|     private bool createSwitch = false; | 
|   | 
|     private int curFrame = 0; | 
|     private int frameInteral = 4; | 
|   | 
|     public void SetSkeletonAnimation(SkeletonAnimation _skeletonAnimation) | 
|     { | 
|         skeletonAnimation = _skeletonAnimation; | 
|     } | 
|   | 
|     public void Show(bool v) | 
|     { | 
|         createSwitch = v; | 
|         curFrame = 0; | 
|          | 
|         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; | 
|         sa.AnimationState.TimeScale = 0; | 
|         playedEntry.TimeScale = 0; | 
|   | 
|         RendererAdjuster parent = skeletonAnimation.GetComponentInParent<RendererAdjuster>(); | 
|         objTest.AddMissingComponent<RendererAdjuster>().SetSortingOrder(parent.sortingOrder); | 
|   | 
|         sa.skeleton.A = 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); | 
|     } | 
| } |