UnityCommon/Aniatioon/SpriteAnimator.cs
2024-12-12 17:06:08 +08:00

218 lines
6.1 KiB
C#

using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 表示一个动画序列,包括一系列精灵和每帧的显示时间。
/// </summary>
[System.Serializable]
public class AnimationSequence
{
[Tooltip("动画序列中的精灵列表")]
public List<Sprite> sprites = new List<Sprite>();
[Tooltip("每一帧的时间,单位秒")]
public float frameTime = 0.1f; // 每帧的持续时间(秒)
}
/// <summary>
/// 控制精灵动画播放的类,使用 Dictionary 进行精灵缓存管理。
/// </summary>
public class SpriteAnimator : MonoBehaviour
{
/// <summary>
/// 定义动画的循环类型。
/// </summary>
public enum LoopType
{
Loop, // 无限循环
Once, // 播放一次
PingPong // 来回播放
}
[Header("动画序列列表")]
[Tooltip("所有动画序列")]
public List<AnimationSequence> animationSequences = new List<AnimationSequence>();
[Header("SpriteRenderer组件")]
[Tooltip("用于显示动画的SpriteRenderer")]
public SpriteRenderer spriteRenderer;
[Header("当前动画编号")]
[Tooltip("当前播放的动画编号")]
public int currentAnimationIndex = 0;
[Header("循环类型")]
[Tooltip("选择动画的循环类型")]
public LoopType loopType = LoopType.Loop;
// 内部变量
private Dictionary<int, AnimationSequence> animationDictionary = new Dictionary<int, AnimationSequence>();
private AnimationSequence currentAnimation;
private int currentFrameIndex = 0;
private float frameTimer = 0f;
private bool isPlaying = true;
private bool pingPongForward = true;
/// <summary>
/// 初始化动画缓存。
/// </summary>
private void Awake()
{
if (animationSequences == null || animationSequences.Count == 0)
{
Debug.LogError("动画序列列表为空。请在 Inspector 中添加动画序列。");
return;
}
for (int i = 0; i < animationSequences.Count; i++)
{
if (!animationDictionary.ContainsKey(i))
{
animationDictionary.Add(i, animationSequences[i]);
}
else
{
Debug.LogWarning($"发现重复的动画索引 {i}。跳过重复项。");
}
}
SetAnimation(currentAnimationIndex);
}
/// <summary>
/// 在开始时进行初始化。
/// </summary>
private void Start()
{
if (spriteRenderer == null)
{
Debug.LogError("SpriteRenderer 'spriteRenderer' 为空。请在 Inspector 中分配 SpriteRenderer。");
return;
}
if (currentAnimation != null && currentAnimation.sprites.Count > 0)
{
frameTimer = currentAnimation.frameTime;
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
}
else
{
Debug.LogError("当前动画序列为空或不包含精灵。");
}
}
/// <summary>
/// 每帧更新动画播放。
/// </summary>
private void Update()
{
if (!isPlaying || currentAnimation == null || currentAnimation.sprites.Count == 0)
return;
frameTimer -= Time.deltaTime;
if (frameTimer <= 0f)
{
AdvanceFrame();
frameTimer = currentAnimation.frameTime;
}
}
/// <summary>
/// 设置当前播放的动画序列。
/// </summary>
/// <param name="index">动画编号</param>
public void SetAnimation(int index)
{
if (animationDictionary.TryGetValue(index, out AnimationSequence selectedAnimation))
{
currentAnimation = selectedAnimation;
currentFrameIndex = 0;
pingPongForward = true;
frameTimer = currentAnimation.frameTime;
if (currentAnimation.sprites.Count > 0)
{
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
}
else
{
Debug.LogWarning($"选中的动画索引 {index} 没有包含任何精灵。");
}
}
else
{
Debug.LogError($"SetAnimation: 动画索引 {index} 在 animationDictionary 中未找到。");
}
}
/// <summary>
/// 控制动画的播放和暂停。
/// </summary>
/// <param name="play">true: 播放动画, false: 暂停动画</param>
public void PlayPauseAnimation(bool play)
{
isPlaying = play;
if (isPlaying && currentAnimation != null && currentAnimation.sprites.Count > 0)
{
// 确保当前帧显示正确
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
frameTimer = currentAnimation.frameTime;
}
}
/// <summary>
/// 前进到下一帧或根据循环类型处理帧索引。
/// </summary>
private void AdvanceFrame()
{
switch (loopType)
{
case LoopType.Loop:
currentFrameIndex = (currentFrameIndex + 1) % currentAnimation.sprites.Count;
break;
case LoopType.Once:
currentFrameIndex = Mathf.Min(currentFrameIndex + 1, currentAnimation.sprites.Count - 1);
if (currentFrameIndex == currentAnimation.sprites.Count - 1)
{
isPlaying = false; // 动画播放完毕后停止
}
break;
case LoopType.PingPong:
if (pingPongForward)
{
currentFrameIndex++;
if (currentFrameIndex >= currentAnimation.sprites.Count - 1)
{
currentFrameIndex = currentAnimation.sprites.Count - 1;
pingPongForward = false;
}
}
else
{
currentFrameIndex--;
if (currentFrameIndex <= 0)
{
currentFrameIndex = 0;
pingPongForward = true;
}
}
break;
}
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
}
/// <summary>
/// 在销毁对象时清理缓存。
/// </summary>
private void OnDestroy()
{
animationDictionary.Clear();
animationSequences = null;
currentAnimation = null;
}
}