Unity播放序列帧

在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上,有需要的朋友可以前去自行下载。传送门

 

原创不易!转发的朋友记得加上转载声明哦,喜欢的朋友可以顺手点个赞哈,谢谢啦!

 

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值