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


系列目錄

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

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

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

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

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

原理

看過前篇的朋友,一定能猜到這篇的內容了,2D人物動畫,這是一個老生常談的話題,很多人都寫過或者提供過類似的代碼,本文還是遵守着重原理,代碼次之的原則。下面是根據以前自己學習的時候學習“深藍色右手”WPF游戲教程的“WPF/Silverlight動畫及游戲系列教程”,先結合Unity3d技術改編的原理文字

動態實現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的動作圖片即可,但我們知道幀就是和時間相關的。

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

1(1)

實現

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

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

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

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

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

    spriteRenderer.sprite = textureArray[currentTexture];
}

一、定時器,稍微麻煩點,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偏偏沒有封裝定時器,所以就需要我們深刻了解其的特性,然后選最優的方式(雖然前人已經栽樹了),萬里長征第一步繼續吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM