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