在之前的基础上,新建了一个用OnEnable和OnDisable控制的脚本,添加了动态数字效果,可以在子物体上使用,实现大动画套小动画。
代码如下:
using UnityEngine;
using DG.Tweening; // 引入DoTween命名空间
using UnityEngine.UI; // 引入 UI 命名空间
public class UIAnimOnEnable : MonoBehaviour
{
public GameObject[] uiElements; // 在Inspector中设置要依次弹出的UI元素
public AnimationType[] animationTypes; // 为每个元素设置动画类型
public float duration = 0.5f; // 动画持续时间
public float delayBetweenElements = 0.2f; // 元素之间的延迟
public float flyDistance = 500f; // 从底部飞入的距离
// 保存原始位置和缩放状态
private Vector3[] originalPositions;
private Vector3[] originalScales;
// 保存原始text文本数值
public float originalfloat;
public enum AnimationType // 定义动画类型
{
Pop,
Fade,
Bounce,
FlyFromBottom,
DynamicNumbers,
No
}
void Awake()
{
InitializeUIElements();
}
private void OnEnable()
{
AnimateUIElements();
}
private void OnDisable()
{
AnimateUIElementsOut();
}
void InitializeUIElements()
{
// 检查数组长度是否匹配
if (uiElements.Length == 0 || animationTypes.Length != uiElements.Length)
{
Debug.LogError("UI元素和动画类型数组长度不匹配!");
return;
}
// 初始化原始位置和缩放数组
originalPositions = new Vector3[uiElements.Length];
originalScales = new Vector3[uiElements.Length];
for (int i = 0; i < uiElements.Length; i++)
{
var element = uiElements[i];
originalPositions[i] = element.transform.localPosition; // 保存原始位置
originalScales[i] = element.transform.localScale; // 保存原始缩放
// 检查并添加 CanvasGroup 组件
CanvasGroup canvasGroup = element.GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
canvasGroup = element.AddComponent<CanvasGroup>();
}
// 初始化为透明并缩放为0,并且隐藏所有元素
element.transform.localScale = Vector3.zero;
canvasGroup.alpha = 0;
element.SetActive(false); // 隐藏UI元素
}
Debug.Log("初始化");
}
void AnimateUIElements()
{
Debug.Log("播放入场动画");
for (int i = 0; i < uiElements.Length; i++)
{
var element = uiElements[i];
// 如果该元素已经激活并有动画在进行,跳出循环
if (element.activeSelf) continue;
// 停止该元素的所有动画
element.transform.DOKill();
CanvasGroup canvasGroup = element.GetComponent<CanvasGroup>();
// 重置状态为透明并缩放为初始状态
element.transform.localScale = Vector3.zero;
canvasGroup.alpha = 0;
// 激活UI元素
element.SetActive(true);
// 根据动画类型执行不同的动画
AnimationType currentAnimation = animationTypes[i];
switch (currentAnimation)
{
case AnimationType.Pop: // 弹出
element.transform.DOScale(originalScales[i], duration).SetDelay(i * delayBetweenElements);
canvasGroup.DOFade(1, duration).SetDelay(i * delayBetweenElements);
break;
case AnimationType.Fade: // 淡入
element.transform.DOScale(originalScales[i], duration).SetDelay(i * delayBetweenElements);
canvasGroup.DOFade(1, duration).SetDelay(i * delayBetweenElements);
break;
case AnimationType.Bounce: // 弹跳
element.transform.DOScale(originalScales[i], duration).SetEase(Ease.OutBounce).SetDelay(i * delayBetweenElements);
canvasGroup.DOFade(1, duration).SetDelay(i * delayBetweenElements);
break;
case AnimationType.FlyFromBottom: // 从底部飞到原位置
element.transform.localPosition = originalPositions[i] + new Vector3(0, -flyDistance, 0); // 从初始化位置偏移
element.transform.DOLocalMove(originalPositions[i], duration).SetDelay(i * delayBetweenElements);
canvasGroup.DOFade(1, duration).SetDelay(i * delayBetweenElements);
element.transform.DOScale(originalScales[i], duration).SetDelay(i * delayBetweenElements);
break;
case AnimationType.DynamicNumbers: // 动态数字效果
element.transform.localScale = originalScales[i];
canvasGroup.alpha = 1;
AnimateValue(element, duration*5); // 直接传递 duration
break;
case AnimationType.No: // 无动效
element.SetActive(true);
break;
}
}
}
void AnimateUIElementsOut()
{
Debug.Log("播放退场动画");
for (int i = 0; i < uiElements.Length; i++)
{
var element = uiElements[i];
// 停止该元素的所有动画
element.transform.DOKill();
CanvasGroup canvasGroup = element.GetComponent<CanvasGroup>();
// 根据动画类型执行不同的退场动画
AnimationType currentAnimation = animationTypes[i];
// 定义一个动画完成后的逻辑
Tween tween = null;
switch (currentAnimation)
{
case AnimationType.Pop: // 弹出
tween = canvasGroup.DOFade(0, duration);
break;
case AnimationType.Fade: // 淡出
tween = element.transform.DOScale(Vector3.zero, duration);
canvasGroup.DOFade(0, duration);
break;
case AnimationType.Bounce: // 弹跳
tween = element.transform.DOScale(Vector3.zero, duration).SetEase(Ease.InBounce);
canvasGroup.DOFade(0, duration);
break;
case AnimationType.FlyFromBottom: // 从底部飞出去
tween = element.transform.DOLocalMove(originalPositions[i] + new Vector3(0, -flyDistance, 0), duration);
canvasGroup.DOFade(0, duration);
element.transform.DOScale(Vector3.zero, duration);
break;
case AnimationType.DynamicNumbers: // 动态数字效果
tween = canvasGroup.DOFade(0, duration);
element.transform.DOScale(Vector3.zero, duration);
break;
case AnimationType.No: // 无动效
element.SetActive(false);
break;
}
// 在动画完成时禁用元素
if (tween != null)
{
tween.OnComplete(() =>
{
element.SetActive(false);
});
}
}
}
private void AnimateValue(GameObject targetObject, float duration)
{
// 检查目标对象上是否有 Text 组件
Text textComponent = targetObject.GetComponent<Text>();
if (textComponent == null)
{
Debug.LogError("目标对象无 Text 组件");
return;
}
// 从 0 开始的动画
float currentValue = 0;
DOTween.To(() => currentValue, x =>
{
currentValue = x;
textComponent.text = Mathf.Floor(currentValue).ToString(); // 更新文本显示
}, originalfloat, duration);
}
private void OnApplicationQuit()
{
DOTween.KillAll(); // 在应用程序退出时停止所有 DOTween 动画
}
}