🎈 简介
人物移动功能的实现或许用到Character Controller 组件或许用到Rigidbody 刚体组件,前者可以直接实现在某些高地不平的地面上移动,而后者想要在具有一定角度的坡面上进行移动则需要通过代码实现。本篇内容介绍如何通过Rigidbody 刚体组件实现人物爬坡功能;
🎈 实现原理
实现人物爬坡功能前,通过获取用户Horizontal 和Vertical 轴输入形成了一个移动方向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 用于限制人物可以爬坡的最大角度,当实际坡度大于该值时,人物不可以向上爬坡。
|