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

如何在2D项目中实现圆形射线与盒形射线检测?

问题与需求
  • 2D项目中,原通过RayCast实现两类检测功能:
    • 蓝色检测:识别"Balloon A"层水气球,修改其Layer以阻止玩家攀爬
    • 红色检测:限制同一位置重复放置水气球,检测层包括"Balloon A/B"、"Balloon Hard A/B"
  • 现有问题:RayCast对角检测存在遗漏,导致重复放置水气球、离开水气球后仍可爬回的BUG
  • 尝试将蓝色检测改为CircleCast未达预期,需调整为:
    • 蓝色检测替换为圆形范围检测
    • 红色检测替换为盒形范围检测
    • 检测范围需匹配Gizmos显示的图形边界

原有RayCast实现代码

void Ray()
{
    if (moveVec.x == 0 && moveVec.y == 1)
    {
        PlusVec = new Vector2(0, 1.41f);
        MakeVec = new Vector2(0, -0.6f);
        dirVec = Vector2.up;
    }
    else if (moveVec.x == 0 && moveVec.y == -1)
    {
        PlusVec = new Vector2(0, -1.41f);
        MakeVec = new Vector2(0, 0.6f);
        dirVec = Vector2.down;
    }
    else if (moveVec.x == -1 && moveVec.y == 0)
    {
        PlusVec = new Vector2(-1.41f, 0);
        MakeVec = new Vector2(0.6f, 0);
        dirVec = Vector2.left;
    }
    else if (moveVec.x == 1 && moveVec.y == 0)
    {
        PlusVec = new Vector2(1.41f, 0);
        MakeVec = new Vector2(-0.6f, 0);
        dirVec = Vector2.right;
    }

    // 蓝色射线检测(攀爬限制)
    Debug.DrawRay(rigid.position + PlusVec, dirVec * 0.3f, new Color(0, 0, 1));
    rayHit = Physics2D.Raycast(rigid.position + PlusVec, dirVec, 0.3f, LayerMask.GetMask("Balloon A"));

    if (rayHit.collider != null)
    {
        scanObject = rayHit.collider.gameObject;
        scanObject.layer = 10;
        Debug.Log(scanObject.name);
    }
    else
    {
        scanObject = null;
    }

    // 红色射线检测(放置限制)
    Debug.DrawRay(rigid.position + MakeVec, dirVec * 1.2f, new Color(1, 0, 0));
    RaycastHit2D rayHitForMake = Physics2D.Raycast(rigid.position + MakeVec, dirVec, 1.2f, 
        LayerMask.GetMask("Balloon A") | LayerMask.GetMask("Balloon B") | 
        LayerMask.GetMask("Balloon Hard A") | LayerMask.GetMask("Balloon Hard B"));

    playerAmakeBalloon = rayHitForMake.collider == null;
}

尝试过的无效CircleCast代码

rayHit = Physics2D.CircleCast(rigid.position, 1f, Vector2.up, LayerMask.GetMask("Balloon A"));

修改后的解决方案

核心调整说明

  1. 蓝色圆形检测:用Physics2D.CircleCast替代RayCast,补充完整参数(尤其是距离和正确原点),同时用Debug.DrawCircle匹配Gizmos显示
  2. 红色盒形检测:用Physics2D.BoxCast替代RayCast,定义合适的盒体尺寸,用Debug.DrawWireCube绘制盒形Gizmos
  3. 提前定义LayerMask变量,避免重复计算提升性能

修改后完整代码

// 提前定义LayerMask,避免重复计算
private LayerMask balloonAMask;
private LayerMask allBalloonMask;
// 圆形检测半径、盒形检测尺寸
private float blueCircleRadius = 0.3f;
private Vector2 redBoxSize = new Vector2(0.5f, 0.5f);

void Awake()
{
    balloonAMask = LayerMask.GetMask("Balloon A");
    allBalloonMask = LayerMask.GetMask("Balloon A") | LayerMask.GetMask("Balloon B") | 
                     LayerMask.GetMask("Balloon Hard A") | LayerMask.GetMask("Balloon Hard B");
}

void CheckBalloonCollisions()
{
    // 方向向量逻辑保持不变
    if (moveVec.x == 0 && moveVec.y == 1)
    {
        PlusVec = new Vector2(0, 1.41f);
        MakeVec = new Vector2(0, -0.6f);
        dirVec = Vector2.up;
    }
    else if (moveVec.x == 0 && moveVec.y == -1)
    {
        PlusVec = new Vector2(0, -1.41f);
        MakeVec = new Vector2(0, 0.6f);
        dirVec = Vector2.down;
    }
    else if (moveVec.x == -1 && moveVec.y == 0)
    {
        PlusVec = new Vector2(-1.41f, 0);
        MakeVec = new Vector2(0.6f, 0);
        dirVec = Vector2.left;
    }
    else if (moveVec.x == 1 && moveVec.y == 0)
    {
        PlusVec = new Vector2(1.41f, 0);
        MakeVec = new Vector2(-0.6f, 0);
        dirVec = Vector2.right;
    }

    // 蓝色圆形检测(攀爬限制)
    Vector2 blueOrigin = rigid.position + PlusVec;
    // 绘制圆形Gizmos
    Debug.DrawCircle(blueOrigin, blueCircleRadius, Color.blue);
    // CircleCast参数:原点、半径、方向、检测距离、LayerMask(距离0为重叠检测)
    rayHit = Physics2D.CircleCast(blueOrigin, blueCircleRadius, dirVec, 0f, balloonAMask);

    if (rayHit.collider != null)
    {
        scanObject = rayHit.collider.gameObject;
        scanObject.layer = 10;
        Debug.Log(scanObject.name);
    }
    else
    {
        scanObject = null;
    }

    // 红色盒形检测(放置限制)
    Vector2 redOrigin = rigid.position + MakeVec;
    // 计算盒体中心与旋转角度,匹配移动方向
    Vector2 redEnd = redOrigin + dirVec * 1.2f;
    Vector2 boxCenter = (redOrigin + redEnd) / 2;
    float boxAngle = Vector2.SignedAngle(Vector2.right, dirVec);
    // 绘制盒形Gizmos
    Debug.DrawWireCube(boxCenter, redBoxSize, Color.red, 0f, boxAngle);
    // BoxCast参数:原点、尺寸、旋转角度、方向、检测距离、LayerMask
    RaycastHit2D rayHitForMake = Physics2D.BoxCast(redOrigin, redBoxSize, boxAngle, dirVec, 1.2f, allBalloonMask);

    playerAmakeBalloon = rayHitForMake.collider == null;
}

关键细节说明

  • 蓝色CircleCast的distance设为0时,等价于圆形重叠检测,完全覆盖原射线的检测范围,解决对角遗漏问题
  • 红色BoxCast的尺寸可根据水气球实际大小调整,boxAngle根据方向向量计算,确保盒体与移动方向对齐
  • 替换原Debug.DrawRay为对应图形的Gizmos绘制,保证编辑器中看到的范围与实际检测范围一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 08:51:03