在U3D中播放序列帧应该算是一个非常常见的需求了,基本做过一些正式项目的朋友或多或少都会遇到,包括我自己,所以自己就写了一个非常简单但又好用的播放序列帧的小插件,今天就拿出来给大家分享分享,话不多说直接上图撸代码!
效果展示:
单组序列帧循环播放
多组序列帧顺序播放
OK说一下使用方法,方法很简单几张图一目了然
1.准备序列帧资源
2.在场景中给要播放的Image挂上FramesAnimation.cs脚本
3.在某个地方存储你要使用Sprite图片组(我这里为了演示图省事直接挂在场景中的的Test脚本上了,你们可以根据需要自动加载配置等)
4.然后调用播放方法(list1为你传入的图片数组,true表示循环)
OK下面放上源码
```
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class FramesAnimation : MonoBehaviour
{
protected enum anim_status
{
unstart,
running,
pause,
stop
}
protected Image image
{
get
{
return GetComponent<Image>();
}
}
//当前的序列帧动画
public List<Sprite> image_list = new List<Sprite>();
//一串连续播放的序列帧动画组
public List<List<Sprite>> Sequence = new List<List<Sprite>>();
//当前播放的序列帧ID(如果ID=-1,则不播放序列帧动画。其他时按照ID来播放动画,播完一个动画自动切到下一个动画,全部播完时停留在最后一个动画)
protected int SequenceID = -1;
protected bool loop = true;
protected anim_status status;
protected UnityAction onComplete;
//添加动画完成事件,动画第一次循环结束时执行
public void OnComplete(UnityAction _event)
{
onComplete = _event;
}
//动画停止时执行一次。
protected UnityAction EndEvent;
public void SetEndEvent(UnityAction _event)
{
EndEvent = _event;
}
//动画每次循环都执行
protected UnityAction CircleEvent;
public void SetCircleEvent(UnityAction _event)
{
CircleEvent = _event;
}
protected UnityAction Change_event;
//当前帧索引
private int currentFrameIndex = 0;
//动画帧率
private float Framerate = 20.0f;
void Update()
{
if (status == anim_status.running)
{
//按帧率播放
if (Time.frameCount % (30 / Framerate) == 0)
{
currentFrameIndex++;
}
//第一次播放结束
if (currentFrameIndex >= image_list.Count)
{
SequenceRule();
currentFrameIndex = 0;
CircleEvent?.Invoke();
onComplete?.Invoke();
if (onComplete != null)
{
onComplete = null;
}
Change_event?.Invoke();
if (!loop && SequenceID == -1)
{
status = anim_status.stop;
//停在最后一帧
currentFrameIndex = image_list.Count - 1;
}
}
if (image_list.Count != 0)
{
image.sprite = image_list[currentFrameIndex];
}
else
{
Debug.LogError("动画序列帧为空!");
}
}
}
public void ClearSequence()
{
status = anim_status.stop;
image_list.Clear();
Sequence.Clear();
}
void SequenceRule()
{
if (SequenceID != -1)
{
if (SequenceID < Sequence.Count - 1)
{
image_list.Clear();
SequenceID++;
Sequence[SequenceID].ForEach(i => image_list.Add(i));
}
else
{
SequenceID = -1;
}
}
}
/// <summary>
/// 多组序列帧播放
/// </summary>
/// <param name="_sequence">传入的多组图片</param>
public void AnimPlaySequence(List<List<Sprite>> _sequence)
{
ClearSequence();
SequenceID = 0;
currentFrameIndex = 0;
foreach (List<Sprite> _list in _sequence)
{
Sequence.Add(_list);
}
Sequence[0].ForEach(i => image_list.Add(i));
image.sprite = image_list[0];
loop = true;
status = anim_status.running;
}
public void AnimPlay(List<Sprite> _list, bool _loop = false, int frame = 0)
{
ClearSequence();
SequenceID = 0;
currentFrameIndex = 0;
_list.ForEach(i => image_list.Add(i));
image.sprite = image_list[0];
loop = _loop;
currentFrameIndex = frame;
status = anim_status.running;
}
public void AnimPause()
{
status = anim_status.pause;
}
public void AnimContinue()
{
status = anim_status.running;
}
public void AnimReplay()
{
currentFrameIndex = 0;
}
public void AnimStop()
{
status = anim_status.stop;
currentFrameIndex = 0;
EndEvent?.Invoke();
}
public void ChangeClip(List<Sprite> new_list, bool Immediately = false)
{
Change_event = delegate
{
image_list.Clear();
new_list.ForEach(i => image_list.Add(i));
};
if (Immediately)
{
Change_event?.Invoke();
}
else
{
Change_event += delegate
{
Change_event = null;
};
}
}
}
```
代码中基本功能都差不多已经有了,包括:
1.帧率的设定
2.是否受TimeScale影响
3.不同播放节点的回调
序列帧播放的原理没啥好说的,Update里按照一定的帧率或时间逐帧切换图片。
但下面额外讲讲AnimPlaySequence()这个方法
如果你只是用一组序列帧播放的话AnimPlay()就很方便使用了,
但我们播放的需求往往没有这么简单,往往是多组序列帧来回切换或拼接播放的,那么你就可以使用队列播放这个方法
_sequence这个参数就是传入的多组图片
调用这个方法动画就会按照你传入的数组顺序播放,然后在最后一组动画内循环播放(各位可按需修改为需要的效果)
OK内容差不多就是这些了,上面GIF的效果我做成了Demo上传到了Github上,有需要的朋友可以前去自行下载。传送门
原创不易!转发的朋友记得加上转载声明哦,喜欢的朋友可以顺手点个赞哈,谢谢啦!
网友评论