unity Animator MatchTarget(目标匹配动画)IK动画

实现主角翻越障碍物的动画

准备工作:首先在动画状态机中做好两种动画状态的切换(行走-翻越/奔跑-翻越)如下

这里使用了动画混合树

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerBehavior : MonoBehaviour
{
    public GameObject woolGo;
    public Transform leftHandIKPos;
    public Transform rightHandIKPos;
    Animator anim;
    //int speedID = Animator.StringToHash("Speed");
    //int isSpwwdUpID = Animator.StringToHash("IsSpeedUp");
    //int horizontalID = Animator.StringToHash("Horizontal");

    int speedRotate = Animator.StringToHash("SpeedRotate");//PosX(Angle Speed(Deg))旋转角度
    int speedZ = Animator.StringToHash("SpeedZ");//PosY速度(最大速度为4.2)
    int vaultID = Animator.StringToHash("Vault");//翻越状态
    int slideID = Animator.StringToHash("Slide");
    int colliderID = Animator.StringToHash("Collider");
    int isHoldLogID = Animator.StringToHash("IsHoldLog");

    private Vector3 matchTarget = Vector3.zero;//目标匹配位置

    private CharacterController cc;



    void Start()
    {
        anim = this.GetComponent<Animator>();
        cc = this.GetComponent<CharacterController>();

    }

    void Update()
    {
        anim.SetFloat(speedZ, Input.GetAxis("Vertical") * 4.2f);
        anim.SetFloat(speedRotate, Input.GetAxis("Horizontal") * 126);

        ProcessVault();
        ProcessSlide();

        cc.enabled = anim.GetFloat(colliderID) < 0.5f;

        //anim.SetFloat(speedID, Input.GetAxis("Vertical")*4.1f);
        //anim.SetFloat(horizontalID, Input.GetAxis("Horizontal"));

        //if (Input.GetKeyDown(KeyCode.LeftShift))
        //{
        //    anim.SetBool(isSpwwdUpID, true);
        //}

        //if (Input.GetKeyUp(KeyCode.LeftShift))
        //{
        //    anim.SetBool(isSpwwdUpID, false);
        //}

    }

    private void ProcessSlide()
    {
        bool isSlide = false;

        if (anim.GetFloat(speedZ) >= 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("Locomotion"))
        {
            RaycastHit hitInfo;
            if (Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out hitInfo, 3f))
            {
                if (hitInfo.collider.tag == "Obstacle")
                {
                    if (hitInfo.distance > 2f)
                    {
                        Vector3 point = hitInfo.point;//射线碰撞的点
                        point.y = 0;
                        matchTarget = point + transform.forward * 2;
                        isSlide = true;
                    }
                }
            }
        }
        anim.SetBool(slideID, isSlide);
        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slide") && anim.IsInTransition(0) == false)
        {
            //匹配目标位置、旋转、和那个位置匹配、匹配目标权重遮罩、 (0.32f, 0.42f|开始匹配位置时间,这个时间是一个差值运算从前一个时间开始(开始起跳)到后一个时间结束(撑到目标位置)完成差值运算,)
            anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(1, 0, 1), 0), 0.17f, 0.67f);
        }
    }

    void ProcessVault()
    {
        bool isVault = false;

        //当速度大于3时检测翻越(并且当前状态是在Locomotion状态期间)
        if (anim.GetFloat(speedZ) >= 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("Locomotion"))
        {
            RaycastHit hitInfo;
            //通过射线检测来判断主角前方是否有障碍物
            if (Physics.Raycast(transform.position + Vector3.up * 0.3f, transform.forward, out hitInfo, 4.5f))
            {
                if (hitInfo.collider.tag == "Obstacle")
                {
                    //射线检测距离大于3的时候去检测
                    if (hitInfo.distance > 3f)
                    {
                        Vector3 point = hitInfo.point;//射线碰撞的点
                        point.y = hitInfo.collider.transform.position.y + hitInfo.collider.bounds.size.y + 0.05f;//取得射线碰到的点的高度+碰到物体的高度+(位置的高度偏差)
                        matchTarget = point;
                        isVault = true;//翻越
                    }
                }
            }
        }

        anim.SetBool(vaultID, isVault);//动画状态机设置翻越状态
        //设置匹配目标时限制在(当前状态为翻越状态并且动画融合为false)
        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Vault") && anim.IsInTransition(0) == false)
        {
            //匹配目标位置、旋转、和那个位置匹配、匹配目标权重遮罩、 (0.32f, 0.42f|开始匹配位置时间,这个时间是一个差值运算从前一个时间开始(开始起跳)到后一个时间结束(撑到目标位置)完成差值运算,)
            anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.42f);
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Log")
        {
            Destroy(other.gameObject);
            CarryWool();
        }
    }

    void CarryWool()
    {
        woolGo.SetActive(true);
        anim.SetBool(isHoldLogID, true);
    }
    
    //每帧都在调用
    private void OnAnimatorIK(int layerIndex)
    {
        
        if (layerIndex == 1)
        {
            int weight = anim.GetBool(isHoldLogID) ? 1 : 0;//设置权重
            anim.SetIKPosition(AvatarIKGoal.LeftHand, leftHandIKPos.position);
            anim.SetIKRotation(AvatarIKGoal.LeftHand, leftHandIKPos.rotation);
            anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, weight);
            anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, weight);

            anim.SetIKPosition(AvatarIKGoal.RightHand, rightHandIKPos.position);
            anim.SetIKRotation(AvatarIKGoal.RightHand, rightHandIKPos.rotation);
            anim.SetIKPositionWeight(AvatarIKGoal.RightHand, weight);
            anim.SetIKRotationWeight(AvatarIKGoal.RightHand, weight);
        }
    }
}

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值