美文网首页
Unity播放序列帧

Unity播放序列帧

作者: 爱学习的狗头 | 来源:发表于2020-06-23 18:34 被阅读0次

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

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

    相关文章

      网友评论

          本文标题:Unity播放序列帧

          本文链接:https://www.haomeiwen.com/subject/unkujftx.html