其他分享
首页 > 其他分享> > Unity-动画状态机使用细节记录

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

标签:动画,动作,OnStateExit,状态机,Unity,animator,public,Animator
来源: https://www.cnblogs.com/littleperilla/p/16116983.html