Unity角色跳跃撞墙后粘墙无法下落问题求助及代码排查
修复RigidBody角色空中粘墙问题
问题现状
使用RigidBody实现FPS角色移动控制器时,角色跳跃后在空中撞到墙体,会出现粘在墙上无法下落的情况,甚至可以在墙面上左右移动。
问题根源
- 强制覆盖水平速度:原代码中无论角色是否在地面,都会直接设置X/Z轴的速度值。当空中撞墙时,持续的水平速度会将角色“压”在墙上,抵消重力的下落作用,导致角色无法下落。
- 空中移动逻辑未区分状态:地面和空中的移动逻辑没有分离,空中时没有让物理引擎主导下落过程,而是强行干预速度,破坏了物理系统的自然反馈。
- 物理摩擦系数过高:角色或墙体的物理材质摩擦系数过大,碰撞时产生的摩擦力会阻碍角色下落。
修复方案
1. 分离地面与空中的移动逻辑
地面上保持原有的直接设置速度的手感,空中时改用AddForce让物理引擎处理碰撞,同时限制空中移动速度,避免速度过大抵消重力。
2. 优化地面检测
使用SphereCast替代Raycast,提升地面检测的准确性,减少误判。
3. 调整物理材质与刚体参数
降低角色和墙体的摩擦系数,确保刚体的重力、拖拽等参数设置合理。
修改后的完整代码
using UnityEngine; public class FPSInput2 : MonoBehaviour { public float speed = 6f; public float jumpForce = 5f; public float airMoveSpeedMultiplier = 0.5f; // 空中移动速度倍率 public float maxAirHorizontalSpeed = 4.2f; // 空中最大水平速度 Rigidbody rb; bool isGrounded; public float groundCheckRadius = 0.4f; // 地面检测球体半径 void Start() { rb = GetComponent<Rigidbody>(); rb.freezeRotation = true; rb.useGravity = true; // 确保重力开启 } private void FixedUpdate() { CheckGround(); HandleMove(); HandleJump(); } void HandleMove() { float moveX = Input.GetAxisRaw("Horizontal"); float moveZ = Input.GetAxisRaw("Vertical"); Vector3 moveDirection = (transform.right * moveX + transform.forward * moveZ).normalized; if (isGrounded) { // 地面移动:保持原有的直接设置速度逻辑 Vector3 velocity = rb.linearVelocity; if (moveX != 0 || moveZ != 0) { velocity.x = moveDirection.x * speed; velocity.z = moveDirection.z * speed; } else { velocity.x = Mathf.Lerp(velocity.x, 0, Time.deltaTime * speed * 0.5f); velocity.z = Mathf.Lerp(velocity.z, 0, Time.deltaTime * speed * 0.5f); } rb.linearVelocity = velocity; } else { // 空中移动:使用AddForce,让物理引擎处理碰撞 if (moveX != 0 || moveZ != 0) { rb.AddForce(moveDirection * speed * airMoveSpeedMultiplier, ForceMode.Force); // 限制空中水平速度,避免速度过大抵消重力 Vector3 horizontalVelocity = new Vector3(rb.linearVelocity.x, 0, rb.linearVelocity.z); if (horizontalVelocity.magnitude > maxAirHorizontalSpeed) { horizontalVelocity = horizontalVelocity.normalized * maxAirHorizontalSpeed; rb.linearVelocity = new Vector3(horizontalVelocity.x, rb.linearVelocity.y, horizontalVelocity.z); } } } } void HandleJump() { if (Input.GetAxis("Jump") > 0 && isGrounded) { rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } } void CheckGround() { // 使用SphereCast检测地面,更贴合角色胶囊碰撞体的形状 isGrounded = Physics.SphereCast(transform.position, groundCheckRadius, Vector3.down, out RaycastHit hit, 1.1f); // 可选:通过标签过滤地面,避免误判墙面或其他物体 // isGrounded = hit.collider != null && hit.collider.CompareTag("Ground"); } }
组件设置建议
- RigidBody参数:确保
Use Gravity勾选,Mass设置为1-2,Drag设为0.1,Angular Drag设为0.05,避免刚体运动过于生硬。 - 物理材质:创建新的物理材质,设置
Friction为0.1、Bounciness为0,将该材质赋值给角色的CapsuleCollider和场景中的墙体Collider,减少碰撞摩擦力。 - Collider:使用CapsuleCollider作为角色的碰撞体,调整半径和高度使其贴合角色模型,避免碰撞体过大导致的异常碰撞。
内容的提问来源于stack exchange,提问作者Velocity
相关产品推荐
相关产品推荐

