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; 
 | 
  
 | 
        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); 
 | 
    } 
 | 
} 
 |