Unity 播放序列帧

Posted chaos-delacroix

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 播放序列帧相关的知识,希望对你有一定的参考价值。

前一阵子写了一个播放序列帧的小脚本,本以为只是临时用一用,但是后来发现这个脚本能频繁的用在项目的其他地方,所以决定优化一下。
这个脚本参考了NGUI的 UI2DSpriteAnimation 脚本,里面有很多不错的思想,这里只是做了一些修修补补的工作。

只需要将这个脚本挂载到任意游戏物体上,animImage变量为要播放序列帧的UGUI Image
OK,上脚本

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 播放2D序列帧
/// </summary>

public class SpriteAnimation : MonoBehaviour
{
    /// <summary>
    /// 播放序列帧的UI Image
    /// </summary>
    [SerializeField]
    private Image animImage;

    /// <summary>
    /// 当前播放的帧在数组中的索引。
    /// 正向播放且不循环时 数字不可大于等于序列帧数组索引。
    /// 倒序播放且不循环时 数字不能小于等于0
    /// </summary>
    public int frameIndex = 0;

    /// <summary>
    /// 每秒播放多少多少帧(不可为0) 
    /// 数字大于0为正向播放,数字小于0为倒序播放
    /// </summary>
    [SerializeField]
    private int framerate = 20;

    /// <summary>
    /// 是否受TimeScale的影响
    /// </summary>
    public bool ignoreTimeScale = true;

    /// <summary>
    /// 是否循环播放
    /// </summary>
    public bool isLoop = true;

    /// <summary>
    /// 存放所有序列帧sprite的数组
    /// </summary>
    public Sprite[] frames;

    /// <summary>
    /// 序列帧更新时间
    /// </summary>
    private float mUpdate = 0f;

    /// <summary>
    /// Continue playing the animation. If the animation has reached the end, it will restart from beginning
    /// </summary>
    public void Play()
    {
        if (!enabled && !isLoop)
        {
            //判断是正向播放还是倒序播放
            int newIndex = framerate > 0 ? frameIndex + 1 : frameIndex - 1;

            //
            if (newIndex < 0 || newIndex >= frames.Length)
            {
                frameIndex = framerate < 0 ? frames.Length - 1 : 0;
            }
        }

        enabled = true;
        UpdateSprite();
    }

    /// <summary>
    /// 暂停播放
    /// </summary>
    public void Pause()
    {
        enabled = false;
    }

    /// <summary>
    /// 回到最初的序列帧,等待播放
    /// </summary>
    public void ResetToBeginning()
    {
        frameIndex = framerate < 0 ? frames.Length - 1 : 0;
        UpdateSprite();
    }

    void Update()
    {
        //获取当前的游戏内时间,用于和序列帧更新时间做比较
        float time = ignoreTimeScale ? Time.unscaledTime : Time.time;

        //这里将 当前游戏时间(time) 和 上次更新的序列帧时间(mUpdate) 进行比对
        //如果 mUpdate<time,说明:更新序列帧之前的时间+序列帧两张间隔时间 小于 游戏内时间,则需要将两个时间线统一,然后再更新序列帧图片
        //如果 mUpdate>=time,说明:更新序列帧之前的时间+序列帧两张间隔时间 大于等于 游戏内时间,需要等待游戏内时间继续增长,不用更新序列帧图片
        //这样做法可以最大程序上保证两张序列帧之间的间隔约等于 1/每秒播放帧数
        if (mUpdate < time)
        {
            mUpdate = time;

            //判断是正向播放还是倒序播放
            int newIndex = framerate > 0 ? frameIndex + 1 : frameIndex - 1;

            //判断 如果在不循环播放时
            //倒序播放 序列帧当前索引小于0,正向播放 序列帧索引大于序列帧总长度
            //则停止播放
            if (!isLoop && (newIndex < 0 || newIndex >= frames.Length))
            {
                enabled = false;
                return;
            }

            //判断序列帧索引是否越界
            frameIndex = RepeatIndex(newIndex, frames.Length);
            UpdateSprite();
        }
    }

    /// <summary>
    /// 更新序列帧图片
    /// </summary>
    void UpdateSprite()
    {
        float time = ignoreTimeScale ? Time.unscaledTime : Time.time;

        //每次更新序列帧图片时,将序列帧时间进行更新
        //新的序列帧时间为:当前游戏内时间+每两帧图片之间的间隔时间(间隔时间就是1秒/序列帧数量)
        mUpdate = time + Mathf.Abs(1f / framerate);

        //更新序列帧图片
        animImage.sprite = frames[frameIndex];
    }

    //用于判断序列帧索引是否越界
    public int RepeatIndex(int val, int max)
    {
        if (max < 1) return 0;
        while (val < 0) val += max;
        while (val >= max) val -= max;
        return val;
    }
}

以上是关于Unity 播放序列帧的主要内容,如果未能解决你的问题,请参考以下文章

Unity 播放序列帧

unity怎么让贴图序列播放

Unity Shader播放序列帧动画

转UNITY3D 游戏开发之四有关实现2D帧序列帧播放相关—Animating Tiledtexture

跟我一起学Unity3D代码中分割图片而且载入帧序列动画

Unity 2D:创建序列帧动画