292 lines
8.3 KiB
C#
292 lines
8.3 KiB
C#
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;
|
||
}
|
||
}
|