Unity Rigidbody实现爬坡功能

文章目录

  • 简介
  • 实现原理
  • 实现代码


简介

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

实现原理


实现人物爬坡功能前,通过获取用户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用于限制人物可以爬坡的最大角度,当实际坡度大于该值时,人物不可以向上爬坡。

你可能感兴趣的:(Unity,Metaverse,1024程序员节,Unity,Rigidbody,爬坡,人物控制)