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

使用2D Raycast检测地面碰撞时物体与地面穿模如何解决

问题核心原因

  • 你当前的2D射线检测设置了检测距离为0,只有当射线起点刚好和地面碰撞体重叠时才会触发检测,下落速度过快时,单帧下落位移超过了碰撞体的半高,射线完全错过地面,导致重力持续叠加直接穿模,属于典型的物理检测「隧道效应」问题。
  • 没有对下落位移做预判处理,就算检测到碰撞也只是停止下落,残留的位移余量还是会导致穿模。

具体修复方案

  1. 把射线的检测长度调整为当前帧下落位移 + 碰撞体下半部分的偏移量,提前预判接下来的位移路径上会不会碰到地面
  2. 如果检测到碰撞,直接把角色位置对齐到地面,抵消多余的下落位移
  3. 条件允许可以额外在碰撞体左右边缘各加一条射线,避免边缘位置检测失效

修复后的参考代码:

public class PlayerMove : MonoBehaviour
{
    Transform _tr;
    [SerializeField] float speed = 4;
    [SerializeField] float gravity = 9.81f;
    [SerializeField] LayerMask mask;
    // 角色碰撞体半高,可手动填写也可动态获取
    [SerializeField] float colliderHalfHeight = 0.5f;
    float xAxe;

    void Awake()
    {
        _tr = GetComponent<Transform>();
        // 如果用BoxCollider2D可以动态获取半高,不用手动填
        // BoxCollider2D col = GetComponent<BoxCollider2D>();
        // colliderHalfHeight = col.size.y / 2 * _tr.localScale.y;
    }

    void Update()
    {
       xAxe = Input.GetAxis("Horizontal");
       _tr.position += Vector3.right * xAxe * speed * Time.deltaTime;
    }

    void FixedUpdate()
    {
        // 先计算当前帧预计的下落位移
        float fallDistance = gravity * Time.fixedDeltaTime;
        Vector2 rayOrigin = _tr.position;
        // 射线长度 = 半高 + 预计下落距离,覆盖完整的移动路径
        RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.down, colliderHalfHeight + fallDistance, mask);
        
        if (hit.collider == null)
        {
            // 无碰撞,正常下落
            _tr.position += Vector3.down * fallDistance;
        }
        else
        {
            // 检测到碰撞,直接对齐到地面位置
            _tr.position = new Vector3(_tr.position.x, hit.point.y + colliderHalfHeight, _tr.position.z);
        }
    } 
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:24:04