122 lines
4.9 KiB
C#
122 lines
4.9 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using DG.Tweening;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
|
||
namespace Ichni.UI
|
||
{
|
||
public class TextCatapult : MonoBehaviour
|
||
{
|
||
[Header("UI 元素")] [Tooltip("第一个文本组件")] [SerializeField]
|
||
private TMP_Text textA;
|
||
|
||
[Tooltip("第二个文本组件")] [SerializeField] private TMP_Text textB;
|
||
|
||
[Header("动画参数")] [Tooltip("文本在中央停留显示的时间")] [SerializeField]
|
||
private float displayDuration = 4f;
|
||
|
||
[Tooltip("向上移动和淡入淡出的动画时间")] [SerializeField]
|
||
private float animationDuration = 1f;
|
||
|
||
[Tooltip("文本向上移动的距离")] [SerializeField]
|
||
private float moveDistance = 200f;
|
||
|
||
// --- 可选: 如果你想让文字内容循环变化 ---
|
||
[Header("可选的文本内容")] [Tooltip("在这里填入你想循环显示的文字列表")] [SerializeField]
|
||
private List<string> textContents = new List<string>();
|
||
|
||
private TMP_Text[] _textElements;
|
||
private int _currentTextIndex = 0; // 当前显示在中央的文本的索引 (0 或 1)
|
||
private int _contentIndex = 0; // 当前显示内容的索引
|
||
|
||
private Vector2 _centerPosition;
|
||
private Sequence _animationSequence;
|
||
|
||
void Start()
|
||
{
|
||
Setup();
|
||
// 直接启动第一个动画过渡
|
||
AnimateTransition();
|
||
}
|
||
|
||
void OnDestroy()
|
||
{
|
||
// 安全地杀死所有相关的DoTween动画,防止在场景切换或对象销毁时出错
|
||
_animationSequence?.Kill();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化设置
|
||
/// </summary>
|
||
private void Setup()
|
||
{
|
||
_textElements = new[] { textA, textB };
|
||
|
||
// 记录中心位置
|
||
_centerPosition = textA.rectTransform.anchoredPosition;
|
||
|
||
// 设置 textA 的初始状态
|
||
textA.rectTransform.anchoredPosition = _centerPosition;
|
||
textA.alpha = 1f;
|
||
UpdateTextContent(textA); // 设置初始文字
|
||
|
||
// 设置 textB 的初始状态 (在下方,透明)
|
||
textB.rectTransform.anchoredPosition = _centerPosition - new Vector2(0, moveDistance);
|
||
textB.alpha = 0f;
|
||
// textB 的内容将在它动画开始前更新,所以这里无需设置
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行一次完整的文本过渡动画,并在完成后自我调用以形成循环
|
||
/// </summary>
|
||
private void AnimateTransition()
|
||
{
|
||
// 确定哪个文本要移出,哪个要移入
|
||
TMP_Text textToAnimateOut = _textElements[_currentTextIndex];
|
||
TMP_Text textToAnimateIn = _textElements[(_currentTextIndex + 1) % 2];
|
||
|
||
// 创建一个新的动画序列
|
||
_animationSequence = DOTween.Sequence();
|
||
_animationSequence
|
||
.AppendInterval(displayDuration) // 1. 等待当前文本显示4秒
|
||
.AppendCallback(() => {
|
||
// 2. 在动画开始前,更新即将进入的文本的内容
|
||
UpdateTextContent(textToAnimateIn);
|
||
})
|
||
// 3. 同时执行两个文本的动画
|
||
.Append(textToAnimateOut.rectTransform.DOAnchorPosY(_centerPosition.y + moveDistance, animationDuration).SetEase(Ease.OutCubic))
|
||
.Join(textToAnimateOut.DOFade(0f, animationDuration).SetEase(Ease.OutCubic))
|
||
.Join(textToAnimateIn.rectTransform.DOAnchorPosY(_centerPosition.y, animationDuration).SetEase(Ease.OutCubic))
|
||
.Join(textToAnimateIn.DOFade(1f, animationDuration).SetEase(Ease.OutCubic))
|
||
.OnComplete(() => {
|
||
// 4. 当整个过渡动画完成时
|
||
|
||
// 将刚刚移出的文本复位到起始位置,为下一次进入做准备
|
||
textToAnimateOut.rectTransform.anchoredPosition = _centerPosition - new Vector2(0, moveDistance);
|
||
|
||
// 切换当前文本的索引,为下个循环做准备
|
||
_currentTextIndex = (_currentTextIndex + 1) % 2;
|
||
|
||
// 启动下一次动画过渡,形成循环
|
||
AnimateTransition();
|
||
});
|
||
|
||
_animationSequence.Play();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新文本内容(如果列表不为空)
|
||
/// </summary>
|
||
private void UpdateTextContent(TMP_Text textElement)
|
||
{
|
||
if (textContents == null || textContents.Count == 0)
|
||
{
|
||
return; // 如果列表为空,则不改变文字
|
||
}
|
||
|
||
textElement.text = textContents[_contentIndex];
|
||
_contentIndex = (_contentIndex + 1) % textContents.Count; // 移动到下一个内容索引,并循环
|
||
}
|
||
}
|
||
} |