lcy
4 天以前 29fd27541c91dc1bf6147c1de5cf5680dfc6cb38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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);
    }
}