Unity Rigidbody实现爬坡功能


🎈 简介

人物爬坡

人物移动功能的实现或许用到Character Controller组件或许用到Rigidbody刚体组件,前者可以直接实现在某些高地不平的地面上移动,而后者想要在具有一定角度的坡面上进行移动则需要通过代码实现。本篇内容介绍如何通过Rigidbody刚体组件实现人物爬坡功能;

🎈 实现原理

Move Direction
实现人物爬坡功能前,通过获取用户HorizontalVertical轴输入形成了一个移动方向Move Direction,该方向平行于地面,驱动Rigidbody沿该方向移动,代码如下:

//根据输入获取方向
protected Vector3 GetInputDirection()
{
    //前方
    Vector3 forward = Vector3.ProjectOnPlane(mainCamera.forward, Vector3.up).normalized;
    //右方
    Vector3 right = Vector3.ProjectOnPlane(mainCamera.right, Vector3.up).normalized;
    //输入值
    input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    //返回值
    return input.x * right + input.y * forward;
}
protected override void Update()
{
    base.Update();
    //计算当前的移动速度
    speed = walkThreshold + ((sprintThreshold - walkThreshold) * sprintFactor);
    //获取方向
    Vector3 direction = GetInputDirection();
    //驱动刚体
    rb.velocity += direction * speed * Time.deltaTime;
    //目标旋转值
    Quaternion targetRot = Quaternion.Euler(new Vector3(0f, Vector3.SignedAngle(transform.forward, direction, Vector3.up), 0f)) * transform.rotation;
    //插值方式进行旋转
    transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, Time.deltaTime * rotateSpeed);
}

如下图所示,我们只需要在上述基础上,从脚底向下发射一条射线(红色线),射线检测碰撞的法线(黄色线)会与向量Vector3.Up形成一个角度a,角度a与坡度b(绿色线与蓝色线夹角)相等,因此求得角度a的值便知坡面的坡度。

坡度
得知坡度后,只需要根据坡度调整Rigidbody刚体的移动方向Move Direction即可。

实现原理

🎈 实现代码

protected override void Update()
{
    base.Update();
    //计算当前的移动速度
    speed = walkThreshold + ((sprintThreshold - walkThreshold) * sprintFactor);
    //获取方向
    Vector3 direction = GetInputDirection();
    //判断是否在坡面上
    if (IsOnSlope(out Vector3 hitNormal))
    {
        direction = Vector3.ProjectOnPlane(direction, hitNormal).normalized;
    }
    //驱动刚体
    rb.velocity += direction * speed * Time.deltaTime;
    //目标旋转值
    Quaternion targetRot = Quaternion.Euler(new Vector3(0f, Vector3.SignedAngle(transform.forward, direction, Vector3.up), 0f)) * transform.rotation;
    //插值方式进行旋转
    transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, Time.deltaTime * rotateSpeed);
}

//是否在斜坡上
private bool IsOnSlope(out Vector3 hitNormal)
{
    Ray ray = new Ray(transform.position + Vector3.up * .1f, Vector3.down);
    if (Physics.Raycast(ray, out RaycastHit slopeHit, 1f))
    {
        hitNormal = slopeHit.normal;
        float slopeAngle = Vector3.Angle(hitNormal, Vector3.up);
        if (slopeAngle < maxSlopeAngle)
        {
            return true;
        }
    }
    hitNormal = Vector3.zero;
    return false;
}

maxSlopeAngle用于限制人物可以爬坡的最大角度,当实际坡度大于该值时,人物不可以向上爬坡。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CoderZ1010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值