Unity3D中角色的動畫腳本的編寫(二)

    在上一篇,咱們介紹了有關Animation這個類中的部分方法,我後來想了想,這麼介紹也不是個辦法(其實有些方法我本身也沒用過),該介紹點實際的東西了,畢竟咱們是要作東西出來的。那好,咱們就開始吧。 

            首先咱們要介紹的主題是:Animation Blending ,即動畫融合。咱們來看官方文檔上的描述:



用我本身的理解就是:在現今的遊戲中,動畫融合是一個必不可少的特性用以讓你的的角色可以產平生滑的動畫。動畫設計師首先爲角色建立了一些個動畫片斷,例如一個行走循環,跑步循環,還有站立或射擊的。在你運行遊戲期間,你須要從站立的動畫狀態轉換到行走的動畫狀態而且看上去要足夠平滑,不能忽然跳轉。 



此時咱們就須要 有一種處理方式來完成咱們所想要實現的效果。這就是「動畫融合」的用處。在Unity中,一個角色能夠有多種不一樣的動畫片斷,Unity能夠將這些動畫片斷融合起來並以一種組件的形式(即Animation)進行管理,並根據具體情形來好比腳原本生成最終的動畫。看來咱們其實一直在運用「動畫的融合」。
        那麼咱們來看一個例子吧,我就選官方的CharacterAnimation裏的goober爲例,直接給出代碼:

using UnityEngine;
using System.Collections;

public class SuperMarioAnimation : MonoBehaviour {
        
        public float landBounceTime = 0.6f;//該動畫在0播放到60%時以後當即結束,應該是後來根據主角在空中滯留的時間而調整的。
        
        private AnimationState lastJump;//存儲「jump」的動畫狀態
        // Use this for initialization
        void Start () {
                
                animation.wrapMode = WrapMode.Loop;//首先設置全部的動畫片斷播放時的播放模式爲循環播放模式,以後咱們也能夠修改單個動畫片斷播放時的循環模式,好比此函數最後一行。

                AnimationState jump = animation["jump"];//暫存「jump」的動畫狀態,記住,是暫存。僅僅只是用於下面三行代碼中的動畫設置。

                jump.layer = 1 ;//設置動畫狀態jump的動畫層值爲1,相對於默認層級值要高,爲的是有更多的優先級取得動畫權重。

                jump.enabled = false;//暫停該動畫的播放,這個我會在後面進行相應的講解,由於它有其獨特的應用情景。

                jump.wrapMode = WrapMode.Clamp;//設置動畫狀態jump的循環模式爲Once(單次,上一篇已經證實了)循環。
                        
        }
        void Update () {
                SuperMarioController marioController = gameObject.GetComponent<SuperMarioController>();
                //取得該角色的SuperMarioController腳本組件。                

                float currentSpeed = marioController.GetSpeed();
                //每幀獲取該角色的速度並存儲在臨時變量currentSpeed裏。
                
                if(currentSpeed > 0.1){//以速度判斷該播放何種動畫,淡入淡出效果的核心就在這裏
                        animation.CrossFade("walk");
                        //若是當前正在播放某個動畫片斷,那麼淡出它,淡入名爲「Walk」的動畫。
                }else{
                        animation.CrossFade("idle");
                }
                
                if(marioController.IsJumping()){//若是此時goober(咱們的主角)還在跳躍
                        if(lastJump.time > landBounceTime){//若是goober的跳躍動畫播放了60%以後
                                lastJump.speed = 0.0f;//讓這個動畫狀態從頭開始播放。
                        }
                }
                
        }
        public void DidJump(){//SendMessage方法調用的,在goober躍起時執行
                //lastJump = animation.CrossFadeQueued("Move",0.3f,QueueMode.PlayNow);
                lastJump = animation.CrossFadeQueued("jump", 0.3f, QueueMode.PlayNow);
                
        }

    public void DidLand()//SendMessage方法調用的,在goober着地時執行
    {
            lastJump.speed = 1;//將當前播放的動畫lastJump的幀數調到最後。
    }
        
}

        注意,要想理解好這段代碼,咱們必須結合另一個加在goober上的腳本:SuperMarioController。這個例子裏面出現了咱們以前提到的一個很是重要的類:AnimationState,即動畫狀態,還涉及到了動畫層的概念。所謂動畫層,即AnimationState.layer,AnimationState這個類中的一個很重要的屬性。在Unity的動畫體系中,默認狀況下,全部動畫狀態的layer值爲0,你能夠在腳本中動態的調節該動畫狀態的layer值。如上代碼,咱們在unity3d中點擊運行按鈕,咱們什麼都不作時,因爲此時得到的currentSpeed的值確定是小於0.1的,那麼此時goober就會播放idle(站立)動畫,見:


可是當咱們按下了空格鍵,此時就會當即播放跳躍動畫。假如咱們將不設置jump的layer值爲1,即註釋掉這行: 



咱們再運行工程,此時咱們仍是按下空格鍵,效果以下: 



錯誤定位到了: 





出錯了,爲何呢?因爲此時沒有設置跳躍動畫的layer,致使跳躍動畫的layer與idle的layer的值都爲0,擁有一樣的播放優先級,因此按下空格鍵時準備播放跳躍動畫,可是在下一幀時程序發現此時從marioController 腳本組件中獲得的currentSpeed變量的值小於0.1,因此又轉爲播放idle動畫,但是此時在此動畫腳本中執行到了上面藍先的這一行,發現lastJump此時是空的(由於此時沒有播放跳躍動畫嘛),因而才提示空引用錯誤。因此工程此時就會暫停,咱們能夠從上面這張圖中得以發現,看,goober此時是否是停在半空中,程序是否是暫停運行了?總結一下:若是某個動畫狀態的layer越高,執行起來就會比layer值較低的動畫狀態優先,且只有此動畫狀態被Stop或暫停時纔有可能執行其餘動畫狀態。官方的一個說明是:

Lower layer animations only receive blend weights if the higher layers didn't use up all blend weights.
翻譯過來就是:layer較低的動畫只能在layer較高的動畫沒有佔用所有混合權重時纔有可能收穫到混合權重,這也支持了咱們的結論。
        關於權重,即AnimationState.weight, 這是一個較容易誤解的概念,建議讀者事先看看文檔上的API解釋,我在後面會着重進行講解的。好了,此次就先講到這了,下一篇我會重點介紹動畫混合,若是容許的話,我還會介紹一下疊加。有興趣的朋友能夠關注一下,給點鼓勵吧!html

相關文章
相關標籤/搜索