2014年11月5日 星期三

【Unity】Animator教學-以Mecanim Example Scenes為例



Animator可以將動畫關聯性、切換參數等等獨立成圖形介面,透過Animator可以簡化許多程式碼需要撰寫的地方,是Unity提拱給版本4以上製作動畫的功能。
不過自己也還在摸索中,雖說是教學,但也只是把懂得那部分寫下來,歡迎批評指教。

首先提一下講解內容,開頭會提一些基本的場景配置,接著以Mecanim Example Scenes內名稱為Layer的Controller,以及名稱IdleRunJump的Script做講解。

1.在Windows->Assect store中下載並加入Mecanim Example Scenes。
Mecanim Example Input



2.將Characters->Teddy2->TeddyBear檔案拉進場景中,畫面中的熊就是這次的主角,接著
新增GameObject->Create Other->Cube,調整Cube位置與形狀作為立足點,
新增GameObject->Create Other->Directional light,加入後可以讓物件有打光的效果,
調整Main Camera的位置和角度,將Main Camera拉進模型的階層下。
camera, plane, light

3.將模型下Animator中的Controller加上Layer,並將Layer點開後可以在編輯Scene的場景中看到下圖的畫面。
Animator Controller

4.接著回到模型上,按Add Component新增Rigidbody(剛體)和Character Controller(腳色控制器),調整Character Controller下的Center和Height值,之後執行程式後看模型會不會掉出Cube,如果會就稍微調整一下模型位置。
Rigidbody Character Controlller

5.將Assets->Scripts>IdleRunJump新增到模型底下,執行程式後可以用鍵盤WASD或上下左右鍵移動看看,滑鼠左右鍵可以跳躍和揮手。
Animator Script

6.回到Layer,編輯介面可以分為三個區塊:
(1)左上角Layers可以將動畫檔分層。
(2)中央可以新增動畫狀態和狀態之間的移動。
(3)左下角可以新增參數,參數可做為狀態之間的移動的條件。
Controller Layer

7.動畫分層可將欲建立的動畫檔分層,Base Layer為基本的全身動畫建立,透過Layers右邊的+可以新增Layer,而新增的Layer可做部分骨架的操控。
Weight為權重,權重為1時揮手(Wave)這個動作會完全覆蓋Base Layer裡的動作。
Mask為遮罩,遮罩可以透過滑鼠右鍵Create->Avatar Mask新增,遮罩部分可以透過Avatar Mask底下的Humanoid調整,以下圖為例,揮手(Wave)這個動作只會在綠色區塊右手執行。
Mask

8.動畫狀態可以在Layer上透過右鍵->Create State->Empty新增,動畫狀態可以設定播放速度和播放動畫,而狀態之間的移動在狀態本身上右鍵->Make Transition建立。

9.在建立狀態移動後,動畫之間的Smooth會幫我們新增好,在這裡就不做太多的變更,Layer左下角的參數可以在作為切換的條件,條件可以新增float, bool, int等等型別。以float為例,動畫切換條件可設定參數名稱、大於小於和門檻值。

10.接著來到IdleRunJump的程式碼上,參數的變化就是在IdleRunJump內做調整:
using UnityEngine;
using System.Collections;

public class IdleRunJump : MonoBehaviour {

    protected Animator animator;
    public float DirectionDampTime = .25f;
    public bool ApplyGravity = true;

    void Start () {
        animator = GetComponent<Animator>();////(1)
        if(animator.layerCount >= 2)
            animator.SetLayerWeight(1, 1);////(2)
    }
 
    void Update (){
        if (animator){
            AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);////(3)  

            if (stateInfo.IsName("Base Layer.Run"))////(4){
                if (Input.GetButton("Fire1")) animator.SetBool("Jump", true);////(5)              
            }
            else{
                animator.SetBool("Jump", false);////(6)              
            }

            if(Input.GetButtonDown("Fire2") && animator.layerCount >= 2){
                animator.SetBool("Hi", !animator.GetBool("Hi"));////(7)
            }

            float h = Input.GetAxis("Horizontal");
            float v = Input.GetAxis("Vertical");////(8)
 
            animator.SetFloat("Speed", h*h+v*v);////(9)
            animator.SetFloat("Direction", h, DirectionDampTime, Time.deltaTime);
        }      
    }
}
(1)透過GetComponent抓取物件下的Animator。
(2)將第1層(Arms Layer)的權重設為1,也就是揮手(Wave)的權重設定。
(3)抓取現在狀態資訊。
(4)透過狀態名稱作為條件的判斷。
(5)在狀態名稱為Base Layer.Run的前提下,Input.GetButton("Fire1")條件成立時,將Jump這個布林參數設定為true,也就是在Run狀態下才可以做Jump的動作。
(6)在跳完之後將Jump設定回false。
(7)同(5)的條件,但要確保layerCount有兩層以上才執行。
(8)抓"Horizontal"和"Vertical"的Axis值,設為h和v。
(9)最後再將h*h+v*v設為Speed的值。

11.在程式碼中各種GetButtonDown內條件名稱,可以透過Edit->Project Settings->Input設定,如Fire1設定成滑鼠左鍵,Vertical設定成ws及方向鍵上下,同時還可以透過GetAxis抓取按下按鍵所設定的值。

這次差不多就寫到這裡,省略的部分還在考慮要不要補齊,省略的部分是run那邊的樹狀結構的切換、程式碼中的Direction和Animator一些參數的功用,不過文章內容就先這樣,下一篇可能是小朋友下樓梯的樣板或是回去繼續玩MMD的模型,最後感謝提供Mecanim Example Scenes的Unity官方。

6 則留言:

  1. 請問為什麼一定要確保layerCount有兩層以上才執行?

    回覆刪除
    回覆
    1. 因為Animator有Base和Arms兩層,
      所以做一個layer有兩層的判斷。

      刪除
    2. 請問如果是 2D的動畫 我用滑鼠點擊移動
      "Fire1" 要設定成什麼才能代表滑鼠左鍵
      還是會跟 3D 做法不一樣呢

      刪除
    3. Fire1預設就是滑鼠左鍵,
      與3D或2D動畫沒有關係的。

      刪除
  2. animator.SetLayerWeight(1, 1); 是不是會將每一層Layer權重全變成1?

    請問如果Layer 有3層的話 如要單獨設置某一層的權重要怎麼做呢? 求大大指點..

    回覆刪除

【自製小遊戲】水平思考猜謎(海龜湯)

遊戲連結 海龜湯的玩法是由出題者提出一個難以理解的事件,參與猜題者可以提出任何問題以試圖縮小範圍並找出事件背後真正的原因。但出題者僅能以「是」、「不是」或「沒有關係」來回答問題。 本遊戲蒐集各種論壇、平台的42個題目,提供給想玩海龜湯卻愁找不到題目的你們。 ...