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

RigidBody穿墙问题(PHYSICS):常规方案无效,求代码修改指导

Unity 控制器穿墙问题解决方案

已尝试以下常规碰撞体调整方案,均无效:

  • 确保碰撞体非触发器
  • 玩家模型与碰撞体尺寸匹配
  • 碰撞检测设置为Continuous Dynamic

问题根源在控制器代码而非碰撞体,实际运行中存在大量穿墙现象。

原控制器代码

void Update()
{
    RaycastHit hit;
    if (Physics.Raycast(transform.position, Vector3.down, out hit, raycastDist, groundLayer))
        isGrounded = true;
    else
        isGrounded = false;

    transform.rotation = Quaternion.Euler(0, angle, 0);
    float horizontalInput = Input.GetAxis("Horizontal");


    angle -= horizontalInput * angleSpeed * Time.deltaTime;

    Vector3 newPosition = Quaternion.Euler(0, angle, 0) * new Vector3(0, 0, radius);

    newPosition.y = rb.position.y; // leave Y unchanged to allow for jumps
    rb.position = newPosition;

    //jump
    if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
    {
        Debug.Log("Jumping");
        rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    }
}

问题分析

直接通过angle计算位置并赋值给rb.position会忽略物理碰撞:当刚体因碰撞被推离计算出的位置时,angle并未同步更新,下一帧会强制把刚体拉回angle对应的位置,导致穿墙。

修改方案

核心是让angle与刚体实际位置同步,并将物理相关操作移到FixedUpdate(Unity物理更新的专用回调),输入逻辑留在Update:

  1. 拆分输入与物理操作:Update只处理输入和地面检测,FixedUpdate处理角度更新和位置同步
  2. 在FixedUpdate开头,根据刚体当前位置反向计算angle,保证角度与实际位置一致
  3. 用rb.MovePosition替代直接赋值rb.position,让物理系统正确处理碰撞

修改后的代码

private float horizontalInput;

void Update()
{
    // 地面检测
    RaycastHit hit;
    isGrounded = Physics.Raycast(transform.position, Vector3.down, out hit, raycastDist, groundLayer);

    // 输入处理(Update中捕获输入更及时)
    horizontalInput = Input.GetAxis("Horizontal");

    // 跳跃(Input.GetKeyDown在Update中检测更准确)
    if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
    {
        Debug.Log("Jumping");
        rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    }
}

void FixedUpdate()
{
    // 从刚体当前位置反向计算angle,同步物理碰撞后的位置变化
    Vector3 localPos = transform.InverseTransformPoint(rb.position);
    angle = Mathf.Atan2(localPos.x, localPos.z) * Mathf.Rad2Deg;

    // 更新角度
    angle -= horizontalInput * angleSpeed * Time.fixedDeltaTime;

    // 计算目标位置
    Vector3 targetPosition = Quaternion.Euler(0, angle, 0) * new Vector3(0, 0, radius);
    targetPosition.y = rb.position.y;

    // 使用MovePosition让物理系统处理碰撞
    rb.MovePosition(targetPosition);

    // 更新旋转
    transform.rotation = Quaternion.Euler(0, angle, 0);
}

关键修改说明

  • 同步angle与物理位置:通过InverseTransformPoint将刚体世界坐标转成局部坐标,再用Atan2计算当前角度,确保碰撞后角度不会脱节
  • 物理操作移到FixedUpdate:Unity的物理引擎在FixedUpdate中更新,这里处理位置和角度能避免抖动,保证物理交互正确
  • 使用rb.MovePosition:替代直接赋值rb.position,让物理系统参与位置更新,碰撞检测会生效,不会强制穿墙

内容的提问来源于stack exchange,提问作者7F7cc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:57:20