Unity使用dotween实现UI依次出现的动画效果

在这里插入图片描述给UI界面加点入场动效,退场就直接倒放。
预设了四种效果,弹出、淡入、弹跳、从底部飞到原位置,用枚举定义动画类型方便切换效果。
挂载到场景物体上:
在这里插入图片描述
效果如下:

屏幕录制 2024-10-24 100120

代码如下:

using UnityEngine;
using DG.Tweening; // 引入DoTween命名空间

public class UIAnimator : 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;

    public enum AnimationType // 定义动画类型
    {
    
    
        Pop,
        Fade,
        Bounce,
        FlyFromBottom
    }

    void Start()
    {
    
    
        InitializeUIElements();
    }

    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.Space))
        {
    
    
            AnimateUIElements();//入场
        }
        else if (Input.GetKeyDown(KeyCode.Return))
        {
    
    
            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元素
        }
    }

    void AnimateUIElements()
    {
    
    
        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;
            }
        }
    }

    void AnimateUIElementsOut()
    {
    
    
        for (int i = 0; i < uiElements.Length; i++)
        {
    
    
            var element = uiElements[i];
            // 如果该元素没有激活,则跳过
            if (!element.activeSelf) continue;

            // 停止该元素的所有动画
            element.transform.DOKill();
            CanvasGroup canvasGroup = element.GetComponent<CanvasGroup>();

            // 根据动画类型执行不同的退场动画
            AnimationType currentAnimation = animationTypes[i];

            switch (currentAnimation)
            {
    
    
                case AnimationType.Pop: // 弹出
                case AnimationType.Fade: // 淡出
                    element.transform.DOScale(Vector3.zero, duration);
                    canvasGroup.DOFade(0, duration);
                    break;

                case AnimationType.Bounce: // 弹跳
                    element.transform.DOScale(Vector3.zero, duration).SetEase(Ease.InBounce);
                    canvasGroup.DOFade(0, duration);
                    break;

                case AnimationType.FlyFromBottom: // 从底部飞出去
                    element.transform.DOLocalMove(originalPositions[i] + new Vector3(0, -flyDistance, 0), duration);
                    canvasGroup.DOFade(0, duration);
                    element.transform.DOScale(Vector3.zero, duration);
                    break;
            }

            // 动画完成后禁用元素
            StartCoroutine(DisableElementAfterAnimation(element, duration));
        }
    }

    private System.Collections.IEnumerator DisableElementAfterAnimation(GameObject element, float waitTime)
    {
    
    
        yield return new WaitForSeconds(waitTime);
        element.SetActive(false);
    }
}