Unity動畫控制器Animator功能非常強大,總結一些具體使用細節,在動作游戲中很實用;
1.動畫烘焙
不同動畫之間,可能存在角色朝向,重心高度不一致;
可以在動畫Eidt界面設置RootTransform Rotation重新烘焙旋轉;
RootTransformPosition(Y)烘焙高度,地面動作選擇feet,烘焙在腳上;
設置完烘焙必須點Apply才能生效;
2.動作鏡像
有些單手動作,左右手都可以做,動畫機添加bool參數,動作Inspector界面Mirror勾選Parameter;
將bool參數設置進去,代碼動態調節bool參數切換左右手;
3.StateMachineBehaviour
Unity動畫機沒有直接的api判斷動畫播放結束,StateMachineBehaviour可以做到;
動畫狀態機生命周期:
OnStateEnter
OnStateUpdate
OnStateExit
創建FSMOnExit腳本繼承StateMachineBehaviour,重寫OnStateExit方法,監聽到有退出消息向上傳遞方法名,在角色控制腳本中實現該方法;
該腳本掛載在動畫機中需要監聽的state上;
TIps:SendMessageUpwards效率很低,建議改成事件機制;
public class FSMOnExit : StateMachineBehaviour
{
public string[] onExitMessages;
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
for (int i = 0; i < onExitMessages.Length; ++i)
{
animator.gameObject.SendMessageUpwards(onExitMessages[i]);
}
}
}
4.trigger累積清空
Unity動畫機的trigger有個出名的”bug“,trigger會累積1次;
造成的效果就是,起跳后空中按跳,落地會再次起跳;
同樣攻擊也會如此;
解決辦法與上述方法相同,在OnStateExit、OnStateEnter按需求重置trigger;
也可以選中在關鍵幀動畫事件中重置Trigger,可以實現連擊時機判定(前置動作過半再次按下攻擊才可連擊);
public class FSMClearSignals : StateMachineBehaviour
{
public string[] clearAtEnter;
public string[] clearAtExit;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach (string key in clearAtEnter)
{
animator.ResetTrigger(key);
}
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach (string key in clearAtExit)
{
animator.ResetTrigger(key);
}
}
}
5.連擊動作混合
連擊動作之間不需要收招,如果是同一個Layer的動作,使用官方混合,拖動時間線同時可以預覽效果;
ExitTime:該狀態有多個后續連線狀態,中間沒有其他條件的情況下,ExitTime決定先進入的狀態;
InterruptionSoure:在混合狀態時(重疊部分),該狀態被打斷返回的狀態,默認返回Next;
可設置Current State,Next State;
6.動畫Layer設置
Layer可用隔開常規行為動作、攻擊、面部表情、以及不同職業動作;
創建動畫層可以設置weight權重,和Mask骨骼遮罩;
Defend層,由於防御只需要右手動作一直舉盾,其他動作一致,添加RightHandMask;
Asset面板右鍵Create-Avatar Mask,把不需要的骨骼都標紅;
層與層之間會更具weight混合——這就讓我們可以通過代碼來插值計算在不同之間做動畫連貫處理;
比如BaseLayer=>Attack層做了插值計算后;
7.動畫曲線
動畫過程中可以設置曲線,通過代碼可獲得曲線的值;
比如這里,我希望攻擊時,角色向前跨出一步,但是又不希望勻速滑步,要求起手時跨出一大段距離,逐漸減少,有個慣性的效果;設置如下曲線;
代碼中:通過動畫機獲取參數attack1hAVelocity,會返回動畫時間對應的曲線值;
model.transform.forward * mAnima.GetFloat("attack1hAVelocity");
8.RootMotion
有些動畫播放時位置會改變,Animator動畫機勾選Apply Root Motion,表示使用動畫中的位移;
Unity腳本生命周期中有一個OnAnimaRootMove,實現該方法動畫中的位移只會受到腳本控制;
代碼中,當播放attack1hC動畫時,OnAnimaRootMove累積動畫中的位置,在FixedUpdate中賦予Rigidbody;
這樣可以做到前面動畫曲線的效果,這種方法會更符合美術需求;
9.onAnimationIK
在OnAnimationIK周期方法中代碼控制骨骼節點的位置;
我就動作不符合需求且沒有美術配合的時候用用;
也有很多高級IK算法,可以模擬出各種炫酷飄逸的效果;油管大佬
public class LeftArmAnimaFix : MonoBehaviour
{
private Transform leftArmLow;
[SerializeField]private Vector3 offset;
private Animator mAnima;
private void Start()
{
mAnima = GetComponent<Animator>();
leftArmLow = mAnima.GetBoneTransform(HumanBodyBones.LeftLowerArm);
}
public void OnAnimatorIK(int layerIndex)
{
leftArmLow.localEulerAngles += offset;
mAnima.SetBoneLocalRotation(HumanBodyBones.LeftLowerArm,Quaternion.Euler(leftArmLow.localEulerAngles));
}
}