Files
Gen_Hack-and-Slash-Roguelit…/Client/Assets/Scripts/Prefab/TemporaryAnimatorText.cs

153 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Base;
using TMPro;
using UnityEngine;
namespace Prefab
{
/// <summary>
/// 临时动画文本组件,用于在指定时间内逐帧显示一系列文本动画。
/// 该组件假设 TemporaryAnimator 实现了 ITickable 接口,因此可以在游戏循环中接收更新。
/// </summary>
public class TemporaryAnimatorText : TemporaryAnimator
{
/// <summary>
/// 用于显示动画文本的 TMP_Text 组件。
/// 允许在编辑器中赋值,以增加灵活性和鲁棒性。
/// </summary>
[SerializeField] public TMP_Text text;
public RectTransform rectTransform;
/// <summary>
/// 当前播放的动画帧索引。
/// </summary>
private int currentFrameIndex = 0;
/// <summary>
/// 存储所有动画帧文本的字符串数组。每个元素代表一帧动画内容。
/// </summary>
private string[] animationsKey;
/// <summary>
/// 每帧动画的持续时间。根据帧率FPS计算得出。
/// </summary>
private float frameDuration;
/// <summary>
/// 用于跟踪当前帧已持续时间的计时器。
/// </summary>
private float timer;
/// <summary>
/// 初始化动画文本组件。
/// </summary>
/// <param name="s">包含所有动画帧文本的字符串,多个帧之间用逗号分隔。</param>
/// <param name="fps">动画播放的帧率Frames Per Second。</param>
public void Init(string s, float fps=3)
{
// 如果文本组件未赋值,尝试在子对象中查找。
// 如果仍未找到,则记录错误并提前退出。
if (!text)
{
text = GetComponentInChildren<TMP_Text>();
if (!text)
{
Debug.LogError("TemporaryAnimatorText: 未在子对象中找到或未指定 TMP_Text 组件。动画无法进行。", this);
return; // 提前退出 Init 方法,避免后续操作使用未初始化的 text
}
}
// 处理输入字符串为 null 或空字符串的情况。
// 在这种情况下,动画将显示空字符串或停止。
if (string.IsNullOrEmpty(s))
{
Debug.LogWarning("TemporaryAnimatorText: 输入的动画字符串为空或为 null。动画将显示空字符串或停止。", this);
animationsKey = new string[] { "" }; // 确保 animationsKey 不为 null 且至少包含一个空字符串元素
}
else
{
animationsKey = s.Split(',');
// 如果 s.Split(',') 结果为空数组(这种情况极少见,但在某些 Split 重载下可能发生),也应进行处理。
if (animationsKey.Length == 0)
{
Debug.LogWarning("TemporaryAnimatorText: 输入的动画字符串导致动画帧数组为空。动画将显示空字符串或停止。", this);
animationsKey = new string[] { "" };
}
}
// 检查帧率FPS的合法性。FPS 必须是大于 0 的正值。
// 如果帧率不合法,则设置为默认值,防止除以零或动画速度异常。
if (fps <= 0)
{
Debug.LogError("TemporaryAnimatorText: FPS 必须是大于 0 的正值。将动画帧持续时间设置为 1 秒。", this);
this.frameDuration = 1f; // 默认每帧1秒实际效果是动画暂停或非常慢
}
else
{
this.frameDuration = 1f / fps;
}
// 重新初始化动画时,将当前帧索引重置为第一帧。
currentFrameIndex = 0;
// 在 animationsKey 准备好后,设置初始文本为第一帧的内容。
if (text && animationsKey.Length > 0)
{
text.text = animationsKey[currentFrameIndex];
}
// 如果动画帧数组为空,但文本组件存在,则清空文本显示。
else if (text)
{
text.text = "";
}
// 重置计时器,从零开始计算新帧的持续时间。
timer = 0f;
}
/// <summary>
/// 每帧更新动画显示。该方法将在游戏循环中被 Clock 调用。
/// </summary>
public override void Tick()
{
base.Tick();
if (!text)
{
Debug.LogWarning("TemporaryAnimatorText: 在 Tick 方法执行期间 TMP_Text 组件为 null。正在从 Clock 中移除。", this);
return; // 无法执行动画,直接返回
}
// 检查动画帧数组是否已初始化或为空。
// 如果没有动画帧,则无需更新,直接返回。
if (animationsKey == null || animationsKey.Length == 0)
{
// Debug.LogWarning("TemporaryAnimatorText: 动画键未初始化或为空。跳过 Tick 更新。", this); // 这条日志已被注释掉,避免频繁输出不必要的警告
return; // 没有动画帧,直接返回
}
// 增加计时器。
timer += Time.deltaTime;
// 如果当前帧的持续时间已达到或超过预设的帧持续时间,则更新到下一帧。
if (!(timer >= frameDuration)) return;
// 减去一帧的持续时间,以便计算下一帧的剩余时间,或者处理帧率不精确导致的累计误差。
timer -= frameDuration;
// 移动到下一帧。
currentFrameIndex += 1;
// 如果当前帧索引超出动画帧数组的范围,则循环回到第一帧。
if (currentFrameIndex >= animationsKey.Length)
{
currentFrameIndex = 0;
}
// 更新文本组件显示为当前帧的文本内容。
text.text = animationsKey[currentFrameIndex];
}
}
}