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

如何在有障碍物遮挡时阻止Raycast拾取物体?

Raycast拾取物体穿透障碍物的修复方案

问题现状

使用Raycast实现物体拾取功能时,玩家直视可拾取物体准星变红表示可拾取,但存在穿透障碍物拾取的问题:即使Raycast与可拾取物体之间有遮挡(如关闭的抽屉),物体仍能被触发拾取,不符合"仅直接命中暴露物体才可拾取"的预期。

问题根源

  1. Raycast未限制检测层,可能穿透了障碍物的碰撞体
  2. 未验证Raycast命中的第一个对象是否为可拾取物体,只要射线能触碰到可拾取物体(哪怕中间有遮挡)就触发拾取

修复步骤

1. 配置Raycast层掩码

在Unity编辑器中创建并分配对应层(如Pickable层放可拾取物体,Obstacle层放障碍物),然后在代码中定义层掩码,让Raycast只与这些层的对象交互。

2. 修改Raycast检测逻辑

确保只有当Raycast命中的第一个对象带有canPickUp_组件时,才触发拾取逻辑;若命中障碍物(无该组件),则不执行拾取并恢复准星状态。

3. 检查障碍物碰撞体设置

确保障碍物的碰撞体处于启用状态,若使用Mesh Collider需勾选Convex,否则Raycast无法正确检测到遮挡。

修改后的代码示例

// 在类中添加层掩码变量,需在Unity编辑器中配置
public LayerMask pickableAndObstacleLayers;
public float pickUpRange;
public Transform holdPos;
public GameObject player;
public Image reticle; // 准星UI
private GameObject heldObj;
private Rigidbody heldObjRb;
private List<GameObject> targetObjectsList = new List<GameObject>();

if (PickingUp) 
{
    if (heldObj == null) // 当前未持有物体
    {
        RaycastHit hit;
        // 发射射线,仅检测指定层的对象
        if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, pickUpRange, pickableAndObstacleLayers))
        {
            var pickUpComponent = hit.transform.GetComponent<canPickUp_>();
            if (pickUpComponent != null)
            {
                Debug.Log("准星应变红");
                // 准星变红逻辑
                reticle.color = Color.red;
                
                if (hit.transform.CompareTag("TargetObj") && !targetObjectsList.Contains(hit.transform.gameObject))
                {
                    targetObjectsList.Add(hit.transform.gameObject); 
                }
                PickUpObject(hit.transform.gameObject);
            }
            else
            {
                // 命中障碍物,恢复准星默认颜色
                reticle.color = new Color(1, 1, 1, 0.75f);
            }
        }
        else
        {
            // 未命中任何对象,恢复准星默认颜色
            reticle.color = new Color(1, 1, 1, 0.75f);
        }
    }
    else
    {
        if (canDrop == true)
        {
            StopClipping(); // 防止物体穿墙
            DropObject();
        }
    }
}

private void PickUpObject(GameObject pickUpObj)
{
    if (pickUpObj.GetComponent<Rigidbody>())
    {
        heldObj = pickUpObj;
        heldObjRb = pickUpObj.GetComponent<Rigidbody>();
        heldObjRb.isKinematic = true;
        heldObjRb.transform.parent = holdPos.transform;
        heldObj.layer = LayerNumber;
        Physics.IgnoreCollision(heldObj.GetComponent<Collider>(), player.GetComponent<Collider>(), true);
        reticle.enabled = false;
    }
}

void DropObject()
{
    Physics.IgnoreCollision(heldObj.GetComponent<Collider>(), player.GetComponent<Collider>(), false);
    heldObj.layer = 0;
    heldObjRb.isKinematic = false;
    heldObj.transform.parent = null;
    heldObj = null;
    reticle.color = new Color(1, 1, 1, 0.75f);
    reticle.enabled = true;
}

关键说明

  • 层掩码pickableAndObstacleLayers需在编辑器中勾选Pickable和Obstacle层,确保Raycast不会穿透无关对象
  • 修改后的逻辑优先检测第一个命中对象,彻底避免了"射线穿透障碍物触发拾取"的问题
  • 补充了准星颜色的状态切换,确保只有命中可拾取物体时才变红

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:46:04