Unity之Animator

Unity之Animator

Animator IK MatchTarget StateMachine BlendTree


StateMachine

Animator 主要通过状态机控制人物动画状态改变
Animator 编辑器各个属性如图:
Animator编辑器属性
人物遮罩

属性 说明
融合方式 Override为覆盖,Additive为附加。附加将通过内部插值运算自动融合不同层级动画
权重 权重为1时 且 融合方式为Override时,该层将覆盖底层的动画
人物遮罩 人物遮罩应用于层级部分动画显示。如图,当该层(含遮罩)动画播放时,将播放双手、头部、body的动画,而处于红色的双腿动画将不会播放出来,显示别的层级的双腿动画
IK 勾选IK即可通过局部带动整体的骨骼显示。IK通过Unity自带的函数进行代码控制 private void OnAnimatorIK(int layIndex) 以及 private void OnAnimatorIK() layIndex为层级下标。Base Layer为0,逐级递增

BlendTree

混合树就是将多个相似的动作混合(混合造型与时间相似的动作)
混合类型:

类型 属性
1D 使用一个参数进行混合,最好混合同个方向的动画,例如:向前走,向前跑
2D Simple Direction 混合不同方向的动画,需要有一个位于(0,0)的动画,例如:Idle
2D Freeform Direction 类似上一种,但能混合同个方向的动画,同样需要原点动画
2D Freeform Cartesian 最好混合动作没有明显朝向区别的动画,可以在x轴和y轴使用不同的定义

MatchTarget

MatchTarget 通常用于设置人物身体的位置在规定时间内到达某个某个位置。例如,用手支撑身体时的动画,把手的位置通过MatchTarget设置到物体表面,达到更好的表现效果。与IK不同的是,存在一个变化的效果,IK直接把手放置到物体表面,不存在变化的效果。

if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight"))
{
    anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
    anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
}

说明:当动画位于第0层的 JumpHight 动画时,设置双手在 0.13s 到 0.26s 之间通过插值的方式移动到 targetLeft 和 targetRight 这两个目标点

IK

IK通过把身体位置设置到某个位置,达到更好的表现效果。例如:持枪设计时,通过把双手设置到正前方,通过双手带动整个身体动画。

private void OnAnimatorIK(int layIndex)
{
    if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh"))
    {
        anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);
        anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
        ik = false;
    }
}

说明:ik 为bool值变量,增加对IK的控制,当为第一层,名为“IdleGrab_FrontHigh”动画时,把右手设置到特定位置 ikPos.position 。
详情可以看官网例子,Inverse Kinematics


动画的其他控制
此处输入图片的描述

Curves

Curves可以为动画添加一条曲线,并在Animator编辑器中的参数面板添加相同的参数,则在动画播放过程中,该参数由动画自动控制,我们可以通过获取该参数的值得到相应的播放进度

Event

Events则可以添加在关键帧,并在动画播放到该位置时自动调用 Object 上的 Function ,不指定 Object 则默认挂载 Animator 上的脚本


实例

public class AnimController : MonoBehaviour
{

    private int jumpUpParameter = Animator.StringToHash("JumpUp");
    private int jumpDownParameter = Animator.StringToHash("JumpDown");
    private int walkParameter = Animator.StringToHash("Walk");
    private int turnParameter = Animator.StringToHash("Turn");
    private int colliderParameter = Animator.StringToHash("Collider");
    private int hookParameter = Animator.StringToHash("Hook");
    private int pickParameter = Animator.StringToHash("Pick");

    private Animator anim;
    private bool ik =false;
    [HideInInspector]
    public Vector3 targetLeft, targetRight;
    public Transform ikPos;
    public Transform t;
    // Use this for initialization
    void Start ()
    {
        anim = this.GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.W))
        {
            anim.SetBool(walkParameter, true);
        }
        if (Input.GetKeyUp(KeyCode.W))
        {
            anim.SetBool(walkParameter, false);
        }

        float turn = Input.GetAxis("Horizontal");
        anim.SetFloat(turnParameter, turn * 54f);

        if (Input.GetKeyDown(KeyCode.K))
        {
            //当前处于Idle时(Turn 等于 0)
            if (anim.GetFloat(turnParameter) == 0)
            {
                //跳起
                RaycastHit hitInfo;
                if (Physics.Raycast(transform.position + GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y * Vector3.up,
                    transform.forward, out hitInfo, 1))
                {
                    if (hitInfo.collider.tag == "Wall")
                    {
                        targetLeft = hitInfo.point +  (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.left);
                        targetRight = hitInfo.point + (hitInfo.collider.gameObject.GetComponent<Renderer>().bounds.size.y - GetComponentInChildren<SkinnedMeshRenderer>().bounds.size.y) * Vector3.up + (0.2f * Vector3.right);
                        t.position = targetLeft;
                        anim.SetTrigger(jumpUpParameter);
                    }
                }
            }
        }

        CharacterControllerEnable();
        if (anim.GetCurrentAnimatorStateInfo(0).IsName("JumpHight"))
        {
            anim.MatchTarget(targetLeft, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
            anim.MatchTarget(targetRight, Quaternion.identity, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), 0.13f, 0.26f);
        }
        Attack();
    }

    private void Attack()
    {
        if (Input.GetKeyDown(KeyCode.J))
        {
            anim.SetTrigger(hookParameter);
        }

        if (Input.GetKeyDown(KeyCode.I))
        {
            anim.SetTrigger(pickParameter);
        }
    }

    private void OnAnimatorIK(int layIndex)
    {
        if (layIndex == 1 && ik && anim.GetCurrentAnimatorStateInfo(1).IsName("IdleGrab_FrontHigh"))
        {
            anim.SetIKPosition(AvatarIKGoal.RightHand, ikPos.position);
            anim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
            ik = false;
        }
    }

    public void SetRightHandPos()
    {
        ik = true;
    }
    private void CharacterControllerEnable()
    {
        if (anim.GetFloat(colliderParameter) > 0.5)
        {
            anim.GetComponent<CharacterController>().enabled = false;
        }
        if (anim.GetFloat(colliderParameter) < 0.5)
        {
            anim.GetComponent<CharacterController>().enabled = true;
        }
    }
}

有错误的,麻烦到作业部落帮忙修改Animator,谢谢。
还是 CSDN 的 MarkDown 好用!

猜你喜欢

转载自blog.csdn.net/u014147126/article/details/81452059