yyl
3 天以前 a178792731891bcd477ab0812ced1ab5fb9229fc
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
127
128
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 = 2;
 
    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, 0.5f)
            .SetTarget(objTest);
 
        // 安全销毁,移除引用
        _ = DestroyIllusionShadowAfterAsync(objTest, 0.5f);
 
    }
 
    // 用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);
    }
}