時光煮雨 Unity3D實現2D人物動畫① UGUI&Native2D序列幀動畫

系列目錄

【Unity3D基礎】讓物體動起來①--基於UGUI的鼠標點擊移動html

【Unity3D基礎】讓物體動起來②--UGUI鼠標點擊逐幀移動數組

時光煮雨 Unity3D讓物體動起來③—UGUI DoTween&Unity Native2D實現網絡

時光煮雨 Unity3D實現2D人物動畫① UGUI&Native2D序列幀動畫函數

時光煮雨 Unity3D實現2D人物動畫② Unity2D 動畫系統&資源效率工具

原理

看過前篇的朋友,必定能猜到這篇的內容了,2D人物動畫,這是一個老生常談的話題,不少人都寫過或者提供過相似的代碼,本文仍是遵照着重原理,代碼次之的原則。下面是根據之前本身學習的時候學習「深藍色右手」WPF遊戲教程的「WPF/Silverlight動畫及遊戲系列教程」,先結合Unity3d技術改編的原理文字oop

動態實現2D人物角色動畫目前有兩種主流方法,下面我會分別進行介紹。
      第一種方法我稱之爲圖片切換法,準備工做:首先經過3DMAX等工具3D渲染2D的方法制做出角色,而後將角色每一個動做均導出8個方向每方向若干幀的系列圖片(若是是有方向的魔法圖片,不少2D-MMORPG每每會導出16個方向的系列幀圖片以求更爲逼真),即將每一個人物每一個動做的各方向的每幀均存成一張圖片,以下圖僅以從破天一劍遊戲中提取的素材爲例:性能

(特別申明:本系列教程所使用的若有註明歸屬權的圖片素材均來源於網絡,請勿用於商業用途,不然形成的一切後果均與本人無關。)學習

1

從上圖能夠看到,我將人物向右方跑步共8幀圖片經過Photoshop分別將畫布等比例擴大成150*150象素圖片(由於是提取的素材,初始寬和高是不均衡值,因此必須擴大成本身的需求,這樣人物會在圖片中居中,而且爲後期加入武器或坐騎留好餘地。稍微的偏離也能夠在後期進行微調),並將他們從開始到結束分別命名爲0.png,1.png,2.png,3.png,4.png,5.png,6.png,7.png,而後將這8張圖片保存到相關目錄下,到此準備工做終於結束了動畫

這裏在WPF中有一個UI線程級別的定時器DispatcherTimer,而Unity中沒有提供相似的機制(或許是我不知道),Unity主要是心跳來控制的也就是Update函數了,可是這裏的原理就是幀動畫,每一個多少幀變化一下player的動做圖片便可,但咱們知道幀就是和時間相關的。ui

簡單的說:就是定義一個圖片數組,而後實現一個定時器,時間到了就獲取數組裏的一張圖,替換精靈的背景圖片。

1(1)

實現

這裏咱們把問題分解主要是兩個子問題,1、定時獲取圖片替換精靈背景,簡稱定時器;2、數組的圖片循環獲取,簡稱數組順序遍歷

先從軟柿子開始,二比較簡單,一個數組,加一個全局基數器變量 搞定

private int currentTexture = 0;
public Sprite[] textureArray;
private SpriteRenderer spriteRenderer;

//遍歷數組 到數組未從新回到0索引

void NextTexture()
{
    currentTexture++;
    if (currentTexture >= textureArray.Length)
    {
        currentTexture = 0;
    }

    spriteRenderer.sprite = textureArray[currentTexture];
}

1、定時器,稍微麻煩點,Unity3d並無提供像樣的UI定時器封裝,這裏爲了驗證 這種定幀動畫的原理,我用幾種Unity3d中定時器機制分別實現了動畫功能,實際開發中用的A和D方法比較多,至少我查了很多教程基本是A和D

首先是變量

private float animationDeltaTime;
private float animationDelay = 5 / 60f;

A、Update 心跳延時定時器

void Update()
{
    animationDeltaTime += Time.deltaTime;
    // Debug.Log(animationDeltaTime);
    if (animationDeltaTime >= animationDelay)
    {
        animationDeltaTime = 0;

        NextTexture();
    }
}

B、協程遞歸定時器

void Start()
{
    spriteRenderer = GetComponent<SpriteRenderer>() as SpriteRenderer;
    StartCoroutine(TextureChanger()); 
}

IEnumerator TextureChanger()
{
    yield return new WaitForSeconds(animationDelay);
    if (true)
    {
        //Debug.Log(animationDeltaTime);
        NextTexture();
        StartCoroutine(TextureChanger());
    }
}

C、InvokeRepeating定時器

void Start()
{
    spriteRenderer = GetComponent<SpriteRenderer>() as SpriteRenderer;
    InvokeRepeating("NextTexture", 1, 0.1f);//1秒後調用LaunchProjectile () 函數,以後每5秒調用一次     
}

D、時長求餘法(我本身起的名字,比較巧妙可能也是用的比較多的方法)

 

using UnityEngine;
using System.Collections;

public class PlayerAnimator : MonoBehaviour {

    public Sprite[] sprites;
    public float framesPerSecond;

    private SpriteRenderer spriteRenderer;
    // Use this for initialization
	void Start () {
        spriteRenderer = GetComponent<Renderer>() as SpriteRenderer;
	}
	
	// Update is called once per frame
	void Update () {
        int timeIndex = (int)(Time.timeSinceLevelLoad * framesPerSecond);
        int index = timeIndex % sprites.Length;
        spriteRenderer.sprite = sprites[index];

	}
}

  

原理的代碼分析和代碼展現完畢,下面是本身在網上找的前人分享的一些代碼,自測能夠運行,主要的問題仍是一句老話,「原理很簡單,現實很殘酷」,實際一個簡單的2d動畫涉及的東西不少,好比性能效率,狀態控制,封裝合理性等等吧。

A、Unity3d UGUI序列幀動畫 實現 (原文地址:http://www.cnblogs.com/mrblue/p/5191183.html)

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using UnityEngine.UI;

using System;

[RequireComponent(typeof(Image))]

public class UGUISpriteAnimation : MonoBehaviour

{

    private Image ImageSource;

    private int mCurFrame = 0;

    private float mDelta = 0;

    public float FPS = 5;

    public List<Sprite> SpriteFrames;

    public bool IsPlaying = false;

    public bool Foward = true;

    public bool AutoPlay = false;

    public bool Loop = false;

    public int FrameCount

    {

        get

        {

            return SpriteFrames.Count;

        }

    }

    void Awake()

    {

        ImageSource = GetComponent<Image>();

    }

    void Start()

    {

        if (AutoPlay)

        {

            Play();

        }

        else

        {

            IsPlaying = false;

        }

    }

    private void SetSprite(int idx)

    {

        ImageSource.sprite = SpriteFrames[idx];

        ImageSource.SetNativeSize();

    }

    public void Play()

    {

        IsPlaying = true;

        Foward = true;

    }

    public void PlayReverse()

    {

        IsPlaying = true;

        Foward = false;

    }

    void Update()

    {

        if (!IsPlaying || 0 == FrameCount)

        {

            return;

        }

        mDelta += Time.deltaTime;

        if (mDelta > 1 / FPS)

        {

            mDelta = 0;

            if(Foward)

            {

                mCurFrame++;

            }

            else

            {

                mCurFrame--;

            }

            if (mCurFrame >= FrameCount)

            {

                if (Loop)

                {

                    mCurFrame = 0;

                }

                else

                {

                    IsPlaying = false;

                    return;

                }

            }

            else if (mCurFrame<0)

            {

                if (Loop)

                {

                    mCurFrame = FrameCount-1;

                }

                else

                {

                    IsPlaying = false;

                    return;

                }        

            }

            SetSprite(mCurFrame);

        }

    }

    public void Pause()

    {

        IsPlaying = false;

    }

    public void Resume()

    {

        if (!IsPlaying)

        {

            IsPlaying = true;

        }

    }

    public void Stop()

    {

        mCurFrame = 0;

        SetSprite(mCurFrame);

        IsPlaying = false;

    }

    public void Rewind()

    {

        mCurFrame = 0;

        SetSprite(mCurFrame);

        Play();

    }

}

  

B、Native2D 序列幀動畫 實現

這部分代碼已經在上文「D、時長求餘法(我本身起的名字,比較巧妙可能也是用的比較多的方法)」中貼出,這裏再也不重複

總結

實際上「序列幀動畫」的實現原理很簡單,就是一個定時器,可是Unity3d恰恰沒有封裝定時器,因此就須要咱們深入瞭解其的特性,而後選最優的方式(雖然前人已經栽樹了),萬里長征第一步繼續吧。

相關文章
相關標籤/搜索