Unity-動畫狀態機使用細節記錄


Unity動畫控制器Animator功能非常強大,總結一些具體使用細節,在動作游戲中很實用;

1.動畫烘焙

不同動畫之間,可能存在角色朝向,重心高度不一致;

可以在動畫Eidt界面設置RootTransform Rotation重新烘焙旋轉;

RootTransformPosition(Y)烘焙高度,地面動作選擇feet,烘焙在腳上;

設置完烘焙必須點Apply才能生效;

image-20220408122255534

2.動作鏡像

有些單手動作,左右手都可以做,動畫機添加bool參數,動作Inspector界面Mirror勾選Parameter;

將bool參數設置進去,代碼動態調節bool參數切換左右手;

image-20220408123000521

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]);
        }
    }
}

image-20220408132529631

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.連擊動作混合

att1

連擊動作之間不需要收招,如果是同一個Layer的動作,使用官方混合,拖動時間線同時可以預覽效果;

ExitTime:該狀態有多個后續連線狀態,中間沒有其他條件的情況下,ExitTime決定先進入的狀態;

InterruptionSoure:在混合狀態時(重疊部分),該狀態被打斷返回的狀態,默認返回Next;

可設置Current State,Next State;

image-20220408134021720

6.動畫Layer設置

Layer可用隔開常規行為動作、攻擊、面部表情、以及不同職業動作;

image-20220408135916667

創建動畫層可以設置weight權重,和Mask骨骼遮罩;

Defend層,由於防御只需要右手動作一直舉盾,其他動作一致,添加RightHandMask;

Asset面板右鍵Create-Avatar Mask,把不需要的骨骼都標紅;

image-20220408135837706

層與層之間會更具weight混合——這就讓我們可以通過代碼來插值計算在不同之間做動畫連貫處理;

比如BaseLayer=>Attack層做了插值計算后;

cahzhi2

image-20220408140115570

7.動畫曲線

動畫過程中可以設置曲線,通過代碼可獲得曲線的值;

比如這里,我希望攻擊時,角色向前跨出一步,但是又不希望勻速滑步,要求起手時跨出一大段距離,逐漸減少,有個慣性的效果;設置如下曲線;

代碼中:通過動畫機獲取參數attack1hAVelocity,會返回動畫時間對應的曲線值;

model.transform.forward * mAnima.GetFloat("attack1hAVelocity");

image-20220408141831283

8.RootMotion

有些動畫播放時位置會改變,Animator動畫機勾選Apply Root Motion,表示使用動畫中的位移;

Unity腳本生命周期中有一個OnAnimaRootMove,實現該方法動畫中的位移只會受到腳本控制;

image-20220408142558595

代碼中,當播放attack1hC動畫時,OnAnimaRootMove累積動畫中的位置,在FixedUpdate中賦予Rigidbody;

這樣可以做到前面動畫曲線的效果,這種方法會更符合美術需求;

9.onAnimationIK

在OnAnimationIK周期方法中代碼控制骨骼節點的位置;

我就動作不符合需求且沒有美術配合的時候用用;

也有很多高級IK算法,可以模擬出各種炫酷飄逸的效果;油管大佬

ik232

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));
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM