1. 程式人生 > >Unity3D的2D幀動畫控制工具編寫

Unity3D的2D幀動畫控制工具編寫

前些日子公司讓筆者寫了一個幀動畫控制工具,主要是用來控制聊天表情這些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();
    }
}