前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity动画☀️8. 添加角色控制器、Curves、添加滑动

Unity动画☀️8. 添加角色控制器、Curves、添加滑动

作者头像
星河造梦坊官方
发布2024-08-14 16:12:12
770
发布2024-08-14 16:12:12
举报
文章被收录于专栏:星河造梦坊专栏

🟥给跳跃添加角色控制器

添加角色控制器Character Controller后,人物不会因动画问题而导致Y轴变化,人物会始终位于水平地面上

但任务可能因为和墙体碰撞,而无法翻越,我们需在特定时刻禁用角色控制器

思路1:判断当前是否处于Vault状态,是则禁用

思路2:思路一缺陷在于Vault未跳跃或跳跃结束后的部分动画的Character Controller处于禁用状态,它的Y轴位置还是会发生变化,或处于地面以下。通过编辑动画,给动画添加Curve(Curve全程与动画match),在特定的起跳和落地两个区域添加关键帧,将这块区域的Curve值设置的与其他区域不同,通过判断Curve值是否位于这个区间,来禁用启用Character Controller

    我们可以在Animator—Parameters里另外添加和Curve同名的参数,系统会自动识别这个参数与Curve名相同,而产生关联,Curve值运行时便在这里显示,同时我们通过判断这个值的大小,来启用或关闭角色控制器

代码:

AvatarTarget.Root:角色的根节点

代码语言:javascript
复制
using UnityEngine;

public class Player : MonoBehaviour {

    private Animator anim;
    private int speedRotateID = Animator.StringToHash("SpeedRotate");
    private int speedZID = Animator.StringToHash("SpeedZ");
    int vaultID = Animator.StringToHash("Vault");
    private Vector3 matchTarget;  //用来匹配目标点

    private CharacterController characterController;
    private int controllerID = Animator.StringToHash("Controller");

    void Start () {
        anim = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
	}
	
	void Update () {

        anim.SetFloat(speedZID, Input.GetAxis("Vertical") * 4.5f);
        anim.SetFloat(speedRotateID, Input.GetAxis("Horizontal")*126);

        if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
        {
            RaycastHit hit;
            if(Physics.Raycast(transform.position+Vector3.up*0.3f,transform.forward,out hit, 4.5f))
            {
                if (hit.collider.tag == "Obstacle")
                {
                    if (hit.distance > 3)
                    {
                        Vector3 point = hit.point;
                        point.y = hit.transform.position.y+ hit.collider.bounds.size.y+0.09f;  //普通的cube在水平面时默认中心高度y=0.5,但此模型水平中心高度为0(和底边一致)!,所以是它最低点位置+Y轴的大小
                        matchTarget =point;

                        anim.SetBool(vaultID, true);
                    }
                    
                }
            }
            else anim.SetBool(vaultID, false);
        }

        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Vault"))
        {
            anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.4f);
        }

        //if (anim.GetFloat(controllerID) > 0.5f)
        //{
        //    characterController.enabled = false;
        //}
        //else
        //{
        //    characterController.enabled = true;
        //}
        characterController.enabled = anim.GetFloat(controllerID) < 0.5f;
    }
}

🟧 添加滑动动画,并给滑动添加角色控制器和MatchTarget()

在滑动动画,我们会发现角色脚部运动不正常,我们可以重新配置下骨骼,修改脚部骨骼角度,并添加Curve、Parameter

    pose—Enforce T-Pose

代码:

思路:在1.5m高度检测前方是否有障碍物,此位置既不会检测到墙,且又能检测到栏杆

1️⃣ 如图所示,修改Parameters名字

2️⃣ 代码

    注意:Character Controller激活关闭方式要分开判断,避免第二个表达式将第一个表达式覆盖

    MatchTarget目的用于匹配滑动后滑到射线碰撞点前方两米处,避免滑行中由于滑行距离不足造成的干涉现象

代码语言:javascript
复制
using UnityEngine;

public class Player : MonoBehaviour {

    private Animator anim;
    private int speedRotateID = Animator.StringToHash("SpeedRotate");
    private int speedZID = Animator.StringToHash("SpeedZ");
    int vaultID = Animator.StringToHash("Vault");
    private Vector3 matchTarget;

    private CharacterController characterController;
    private int vaultCurveID = Animator.StringToHash("vaultCurve");
    private int sliderID = Animator.StringToHash("Slider");
    private int sliderCurveID = Animator.StringToHash("sliderCurve");

    void Start () {
        anim = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
	}
	
	void Update () {

        anim.SetFloat(speedZID, Input.GetAxis("Vertical") * 4.5f);
        anim.SetFloat(speedRotateID, Input.GetAxis("Horizontal")*126);

        ProcessVault();
        ProcessSlider();
    }

    private void ProcessVault()
    {
        if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
        {
            RaycastHit hit;
            if (Physics.Raycast(transform.position + Vector3.up * 0.3f, transform.forward, out hit, 4.5f))
            {
                if (hit.collider.tag == "Obstacle")
                {
                    if (hit.distance > 3)
                    {
                        Vector3 point = hit.point;
                        point.y = hit.transform.position.y + hit.collider.bounds.size.y + 0.09f;  //普通的cube在水平面时默认中心高度y=0.5,但此模型水平中心高度为0(和底边一致)!,所以是它最低点位置+Y轴的大小
                        matchTarget = point;

                        anim.SetBool(vaultID, true);
                    }

                }
            }
            else anim.SetBool(vaultID, false);
        }

        characterController.enabled = anim.GetFloat(vaultCurveID) < 0.5f;

        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Vault"))
        {
            anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.4f);
        }

        //if (anim.GetFloat(controllerID) > 0.5f)
        //{
        //    characterController.enabled = false;
        //}
        //else
        //{
        //    characterController.enabled = true;
        //}
        
    }
    private void ProcessSlider()
    {
        if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
        {
            RaycastHit hit;
            if (Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out hit, 5f))
            {
                if (hit.collider.tag == "Obstacle")
                {
                    if (hit.distance <2.8)
                    {
                        Vector3 point = hit.point;
                        point.y = 0 ; 
                        matchTarget = point+transform.forward*2;
                        anim.SetBool(sliderID, true);
                    }
                }
            }
        }
        else anim.SetBool(sliderID, false);

        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slider"))
        {
            anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(1,0,1), 0), 0.38f, 0.67f);
        }

        if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slider" ))
        {
            characterController.enabled = anim.GetFloat(sliderCurveID) < 0.5f;
        }
    }
}

动画展示:

大家还有什么问题,欢迎在下方留言!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档