前些日子公司让笔者写了一个帧动画控制工具,主要是用来控制聊天表情这些2D动画的,原本想偷懒在网上直接考了一份代码,没想到运行之后发现当帧率为负的时候还有bug,最后在他基础上做了改动,优化了一下并把bug修复了。
原文链接 https://blog.csdn.net/serenahaven/article/details/79273114
把每一帧的图片按顺序拖进数组中,设置好参数
每个参数注释已经写的非常详细了,直接贴代码吧。
using System;
using UnityEngine;
using UnityEngine.UI;
public class Animation2D : MonoBehaviour {
/// <summary>
/// 帧率
/// 为正时正向播放,为负时反向播放
/// </summary>
public float frameRate = 2;
/// <summary>
/// 延时播放
/// </summary>
public float delayTime=0;
/// <summary>
/// 动画曲线
/// </summary>
public AnimationCurve curve = new AnimationCurve(new Keyframe(0, 1, 0, 0), new Keyframe(1, 1, 0, 0));
/// <summary>
/// 结束事件
/// 在每次播放完一个周期时触发
/// 在循环模式下触发此事件时,当前帧不一定为结束帧
/// </summary>
public event Action FinishEvent;
/// <summary>
/// 动画是否循环播放
/// </summary>
public bool loop = true;
/// <summary>
/// 播放结束是否销毁
/// </summary>
public bool isEndDstory = false;
/// <summary>
/// 序列帧
/// </summary>
public Sprite[] frameSprites;
//************************************************
//显示的图片
private Image image;
//当前帧
private int currentFrameIndex=0;
//计时器
private float timer = 0;
// Use this for initialization
void Start ()
{
image = GetComponent<Image>();
#if UNITY_EDITOR
if (image == null)
Debug.LogError("请挂载 Image 组件,");
#endif
if(delayTime==0) image.sprite = frameSprites[currentFrameIndex];
}
// Update is called once per frame
void Update ()
{
if (image != null && frameRate != 0&&Time.time>=delayTime)
{
//计算 实际帧率=帧率*曲线值(由曲线横坐标,取得纵坐标的值)
float value = curve.Evaluate((float)currentFrameIndex / frameSprites.Length);
float actualFrameRate = value * frameRate;
if (actualFrameRate != 0)
{
//获取当前游戏运行时间
float time = Time.time;
//计算帧间隔时间
float interval = Mathf.Abs(1.0f / actualFrameRate);
//满足更新条件,执行更新操作
if (time - timer > interval)//大于时间间隔,执行更新
{
//计算新的索引 Mathf.Sign(float f) f为正返回1,为负返回-1
int nextIndex = currentFrameIndex + (int)Mathf.Sign(actualFrameRate);
//索引越界,表示已经到结束帧
if ((nextIndex <=-frameSprites.Length&& frameRate<0) || nextIndex >= frameSprites.Length)
{
//触发事件
if (FinishEvent != null) FinishEvent();
//非循环模式
if (!loop)
{
if (isEndDstory)//动画播放结束时销毁
Destroy(this.gameObject);
currentFrameIndex = Mathf.Clamp(currentFrameIndex, 0, frameSprites.Length-1);
this.enabled = false;
return;
}
}
//钳制索引
currentFrameIndex =frameRate<0? (frameSprites.Length+nextIndex) % frameSprites.Length : nextIndex % frameSprites.Length;
//更新当前帧图片
image.sprite = frameSprites[currentFrameIndex];
//设置计时器为当前时间
timer = Time.time;
}
}
}
}
/// <summary>
/// 重设动画
/// </summary>
public void Reset()
{
currentFrameIndex = frameRate < 0 ? frameSprites.Length - 1 : 0;
}
/// <summary>
/// 从停止的位置播放动画
/// </summary>
public void Play()
{
this.enabled = true;
}
/// <summary>
/// 暂停动画
/// </summary>
public void Pause()
{
this.enabled = false;
}
/// <summary>
/// 停止动画,将位置设为初始位置
/// </summary>
public void Stop()
{
Pause();
Reset();
}
}