一、初識Blend Trees(混合樹)
● 混合樹 用於兩個或多個類似動畫的融合。如從walk到run的速度的變化,或在奔跑的時候向左、向右的傾斜角度。
● 2D Simple Directional(簡單的定向): 表示在二維每個空間方向只能有一個動作
適用於當你的動作片段代表不同方向時,如“向前行走”、“向后行走”、“向左行走”和“向右行走”或是“向上瞄准”、“向下瞄准”、“向左瞄准”和“向右瞄准”。選一個基礎動作放在位置 (0, 0) 處,如 “idle” 和“aim straight”等。在簡單方向 (Simple Directional) 類型中,相同方向上不應存在多個運動,如“向前行走”和“向前奔跑”。
● 2D Freeform Directional(自由的定向): 表示在二維每個空間方向可以有多個動作
這種類型同樣用於當你的動作片段代表不同方向時使用,但是你可以在相同方向上具有多個動作,例如“向前行走”和“向前奔跑”。在任意方向 (Freeform Directional) 類型中,在該類型中應設置一個動作在位置 (0, 0)處,如“idle”。
● 2D Freeform Cartesian(自由的坐標):
適用於你的動作中不需要代表不同方向時。如你要做的游戲中包括“向前行走不轉彎”、“向前奔跑不轉彎”、同時可以“向前行走並右轉”、“向前奔跑並右轉”等運動時,使用這種類型。
● Direct:能夠精准的控制每個動畫所占的權重(每個動畫占用一個不同的float值)。如下圖:
● Automate Threshold: 自動化闕值(闕值:臨界值)
1、1D 混合樹
● Parameter: 參數類型
● Thresholds:闕值。當“Blend Tree”的數值達到某個動畫的闕值時,則完全播放該動畫
● 在“1D 混合樹”中用代碼實現walk到run的過度
//按下W、S鍵實現"WalkRun"參數由-1到1的動態變化
float y = Input.GetAxis("Vertical"); _animator.SetFloat("WalkRun", y);
2、2D 混合樹
● 2D Freeform Cartesian
//按下W、S、A、D鍵實現行走動畫的過度
float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical"); _animator.SetFloat("h", x); _animator.SetFloat("v", y);
二、Mecanim動畫系統的簡單應用
1、遮罩(用於兩種動畫的不同部位同時播放,如邊奔跑邊射擊等)
● Weight:權重。基礎層的權重為默認
● Mask : 遮罩
● Blending:該層動畫與其他層動畫的混合方式,包括Override(復寫方式,即取不同層動畫的中間值)和additive(直接疊加)。
● Sync:同步。同步是本層動畫直接同步其他層動畫狀態之間的邏輯狀態,一般需要選取同步源。同步之后需要給本層的動畫狀態添加動畫剪輯。
● IK Pass:即本層動畫是否支持IK動畫。
1)在Layers中新建一個圖層“Layer_attack”,調整權重(Weight)、添加動畫。
2)右鍵新建一個Avatar Mask遮罩並調節Humanoid屬性,然后在Mask圖層中添加遮罩。新建Avatar Mask如下圖:
3)可以在Blending屬性中將Override改為additive(直接疊加),得到不同的效果
2、動畫重定向
1、直接將建好的Animator Controller賦給角色模型
2、在Project視圖中右鍵新建一個Animator Override Controller然后將Animator Controller賦給他。方法二的好處是可以將“Animator Controller”重新命名便於區分。
注意:需要注意Avatar下面有沒有Configure Avatar選項,如果沒有則需要重新設置Animation Type和Avatar Definition。否則無法進行動畫重定向。如下圖
3、IK
IK(Inverse Kinematics)即反向動力學,即可以使用場景中的各種物體來控制和影響角色身體部位的運動,一般來說骨骼動畫都是傳統的從父節點到子節點的帶動方式(即正向動力學),而IK則倒過來,由骨骼子節點帶動骨骼父節點。(插件:FinalIK)
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary>
/// 在Animator Controller添加一個idle /// 在Hierarchy窗口創建一個游戲物體給角色用 /// 開啟IK Pass,綁定腳本即可 /// </summary>
public class IKController : MonoBehaviour { //聲明
Animator _animator; public Transform lookAtObj = null; public Transform rightHandObj = null; void Start() { _animator = GetComponent<Animator>(); } void OnAnimatorIK() { if (_animator) { if (lookAtObj != null) { _animator.SetLookAtWeight(1);//設置權重
_animator.SetLookAtPosition(lookAtObj.position); } else _animator.SetLookAtWeight(0); if (rightHandObj != null) { //“AvatarIKGoal.RightHand”右手的權重為1
_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1); _animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1); //右手的位置和旋轉角度
_animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position); _animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation); } else { _animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0); _animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0); } } } }
4、用代碼觸發開門動畫
1)選中門利用Unity創建一個簡單的開門動畫;
2)在Project視圖創建一個Animation動畫(靜態的)作為默認動畫;
3)連接如下圖:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { private AudioSource _audioSource; private Animator _animation; void FixedUpdate() { Move(); } void Move() { //角色移動 //運行時需要在"Rigidbody"組件上設置constraints(軸約束),否則角色膠囊無法保持平衡 transform.Translate(0, 0, Input.GetAxis("Vertical") * Time.deltaTime * 5); transform.Rotate(0, Input.GetAxis("Horizontal") * Time.deltaTime * 50, 0); } void OnTriggerEnter(Collider other) { //使用OnTrigger方法必須在游戲物體或者角色上開啟“Is Trigger” //如果觸發標簽為"door"的游戲對象,則播放聲音及開門動畫 //如果獲取組件不添加“other”,則默認獲取的是當前綁定腳本的游戲對象 if (other.tag == "door") { _audioSource = other.GetComponent<AudioSource>(); _audioSource.Play(); _animation = other.GetComponent<Animator>(); _animation.SetTrigger("door1"); } } void OnTriggerExit(Collider other) { if (other.tag == "door") { _audioSource = other.GetComponent<AudioSource>(); _audioSource.Play(); _animation.SetTrigger("door0"); } } }