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

292 lines
8.3 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 System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 定义动画序列的循环类型。
/// </summary>
public enum MyLoopType
{
Once, // 播放一次
Count, // 播放指定次数
Forever // 无限循环
}
/// <summary>
/// 定义动画组的循环类型。
/// </summary>
public enum GroupLoopType
{
Once, // 动画组循环一次后销毁
Count, // 动画组循环指定次数后销毁
Forever // 动画组无限循环
}
/// <summary>
/// 表示一个动画序列,包括一系列精灵、每帧的显示时间和循环类型。
/// </summary>
[System.Serializable]
public class AnimationSequence
{
[Tooltip("动画序列中的精灵列表")]
public List<Sprite> sprites = new List<Sprite>();
[Tooltip("每一帧的时间,单位秒")]
public float frameTime = 0.1f; // 每帧的持续时间(秒)
[Tooltip("动画序列的循环类型")]
public MyLoopType loopType = MyLoopType.Forever; // 动画序列的循环类型
[Tooltip("动画序列的循环次数(仅当 LoopType 为 Count 时生效)")]
public int loopCount = 1; // 动画序列的循环次数
}
/// <summary>
/// 控制精灵动画播放的类,支持组循环并允许为每个动画序列设置循环类型和循环次数。
/// </summary>
public class SpriteAnimator : MonoBehaviour
{
[Header("动画序列列表")]
[Tooltip("所有动画序列")]
public List<AnimationSequence> animationSequences = new List<AnimationSequence>();
[Header("SpriteRenderer组件")]
[Tooltip("用于显示动画的SpriteRenderer")]
public SpriteRenderer spriteRenderer;
[Header("组循环设置")]
[Tooltip("选择动画组的循环类型")]
public GroupLoopType groupLoopType = GroupLoopType.Forever;
[Tooltip("动画组循环次数(仅当 GroupLoopType 为 Count 时生效)")]
public int groupLoopCount = 1;
// 内部变量
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 int currentAnimationIndex = 0; // 当前播放的动画序列索引
private int currentGroupLoopIteration = 0; // 当前动画组已循环次数
private int currentSequenceLoopIteration = 0; // 当前动画序列已循环次数
/// <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();
// 获取当前动画序列的循环类型
MyLoopType currentLoopType = currentAnimation.loopType;
switch (currentLoopType)
{
case MyLoopType.Once:
if (currentFrameIndex == currentAnimation.sprites.Count - 1)
{
MoveToNextSequence();
}
break;
case MyLoopType.Count:
if (currentFrameIndex == currentAnimation.sprites.Count - 1)
{
currentSequenceLoopIteration++;
if (currentSequenceLoopIteration >= currentAnimation.loopCount)
{
MoveToNextSequence();
}
else
{
ResetCurrentSequence();
}
}
break;
case MyLoopType.Forever:
// 无需特殊处理,继续循环
break;
}
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;
frameTimer = currentAnimation.frameTime;
currentSequenceLoopIteration = 0;
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;
// 不重置 currentSequenceLoopIteration以免影响循环次数控制
}
}
/// <summary>
/// 前进到下一帧并更新SpriteRenderer的精灵。
/// </summary>
private void AdvanceFrame()
{
if (currentAnimation.sprites.Count == 0)
return;
currentFrameIndex++;
if (currentFrameIndex >= currentAnimation.sprites.Count)
{
currentFrameIndex = currentAnimation.sprites.Count - 1;
}
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
}
/// <summary>
/// 重置当前动画序列的播放状态,以便重新循环。
/// </summary>
private void ResetCurrentSequence()
{
currentFrameIndex = 0;
frameTimer = currentAnimation.frameTime;
spriteRenderer.sprite = currentAnimation.sprites[currentFrameIndex];
}
/// <summary>
/// 切换到下一个动画序列,并根据组循环类型决定是否继续循环或销毁动画组。
/// </summary>
private void MoveToNextSequence()
{
currentAnimationIndex++;
if (currentAnimationIndex >= animationSequences.Count)
{
// 完整播放了一遍动画组
currentAnimationIndex = 0;
currentGroupLoopIteration++;
switch (groupLoopType)
{
case GroupLoopType.Once:
isPlaying = false;
Destroy(gameObject); // 销毁动画组
return;
case GroupLoopType.Count:
if (currentGroupLoopIteration >= groupLoopCount)
{
isPlaying = false;
Destroy(gameObject); // 销毁动画组
return;
}
break;
case GroupLoopType.Forever:
// 无限循环,继续播放
break;
}
}
SetAnimation(currentAnimationIndex);
}
/// <summary>
/// 在销毁对象时清理缓存。
/// </summary>
private void OnDestroy()
{
animationDictionary.Clear();
animationSequences = null;
currentAnimation = null;
}
}