You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity角色跳跃撞墙后粘墙无法下落问题求助及代码排查

修复RigidBody角色空中粘墙问题

问题现状

使用RigidBody实现FPS角色移动控制器时,角色跳跃后在空中撞到墙体,会出现粘在墙上无法下落的情况,甚至可以在墙面上左右移动。

问题根源

  1. 强制覆盖水平速度:原代码中无论角色是否在地面,都会直接设置X/Z轴的速度值。当空中撞墙时,持续的水平速度会将角色“压”在墙上,抵消重力的下落作用,导致角色无法下落。
  2. 空中移动逻辑未区分状态:地面和空中的移动逻辑没有分离,空中时没有让物理引擎主导下落过程,而是强行干预速度,破坏了物理系统的自然反馈。
  3. 物理摩擦系数过高:角色或墙体的物理材质摩擦系数过大,碰撞时产生的摩擦力会阻碍角色下落。

修复方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:47:06