Unity-動畫狀態機使用細節記錄
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));
}
}