C# 2D光线投射无法正确检测重叠碰撞器并忽略排序层

C# 2D光线投射无法正确检测重叠碰撞器并忽略排序层,c#,unity3d,raycasting,collider,C#,Unity3d,Raycasting,Collider,我希望能够与我的游戏对象进行交互,同时使用排序层组织我的精灵。 现在,排序层不会影响光线投射/碰撞器的情况,只会更改订单的视觉外观 在我的测试场景中,我有两个精灵:一个背景和一个对象。 两者都有一个二维长方体碰撞器组件。 我的Raycast脚本应该检测鼠标悬停在哪个对象上;背景(BG)或位于BG顶部的对象 只要在inspector中启用BG碰撞器,我的脚本将只识别BG,即使其他对象位于我的BG顶部(视觉上并根据排序层)(Z位置均为0,排序层默认值(BG:0,对象1))。 碰撞器具有正确的大小,如

我希望能够与我的游戏对象进行交互,同时使用排序层组织我的精灵。 现在,排序层不会影响光线投射/碰撞器的情况,只会更改订单的视觉外观

在我的测试场景中,我有两个精灵:一个背景和一个对象。 两者都有一个二维长方体碰撞器组件。 我的Raycast脚本应该检测鼠标悬停在哪个对象上;背景(BG)或位于BG顶部的对象

只要在inspector中启用BG碰撞器,我的脚本将只识别BG,即使其他对象位于我的BG顶部(视觉上并根据排序层)(Z位置均为0,排序层默认值(BG:0,对象1))。 碰撞器具有正确的大小,如果我禁用或从BG中删除碰撞器,我的脚本将检测到另一个对象。 在激活BG碰撞器时,确保检测到我的对象的唯一方法是将对象Z位置更改为BG和相机之间的位置(介于较小的0和较大的-10之间)

我试图:

  • 这是一个全新的2D项目,所以我的相机投影设置为正交,我的背景和对象使用精灵渲染器,使用2D碰撞器
  • 前后更改“层中的顺序”,包括负数
  • 添加前景(和背景)“排序层” (两个选项仅具有视觉效果,不影响光线投射输出)

  • 更改层次结构中的位置

  • 删除并重新添加碰撞器。(!)我观察到,我最后添加的2D长方体碰撞器将始终位于其他碰撞器的后面。这是我现在可以处理的事情。但在将来,当项目变得更大时,这将成为一个问题
我希望能够在我的2D点击冒险中与物品和门等(点击和鼠标悬停的反应)进行交互。如果2D Raycast不是归档此文件的方法,我很高兴了解在这种情况下使用的适当技术

使用系统集合;
使用System.Collections.Generic;
使用UnityEngine;
公共类RayCast:MonoBehavior
{
[SerializeField]专用矢量2 mousePosWorld2D;
雷卡斯特2D命中;
无效更新()
{
mousepoworld2d=(Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
hit=Physics2D.Raycast(mousePostWorld2D,Vector2.zero);
if(命中对撞机)
{
Log(“找到碰撞器:+hit.collider.name”);
}
其他的
{
Log(“未找到碰撞器”);
}
}
}
我希望“排序层”或“层中顺序”对我的光线投射有影响,而更改Z位置则没有任何作用。但情况正好相反。排序层仅具有视觉效果,将我的对象移近摄影机(Z位置)有助于检测右侧碰撞器


如何解决这个问题?

您是否尝试过Unity官方文档中的脚本?

使用UnityEngine;
//举个例子。
公共类示例类:单一行为
{
无效更新()
{
//位移位层(8)的索引以获得位掩码

int layerMask=1光线首先击中的只是碰撞器与摄影机的距离,而与层次或SortinLayers中的顺序无关

为了根据排序层找到“最高”的RaycastTarget,我创建了下面的脚本

我们使用foreach循环触发光线投射并迭代所有碰撞器。然后该函数将返回具有最高排序层的游戏对象。注意:如果有多个游戏对象具有最高排序层,该函数将返回它找到的最后一个

using UnityEngine;

public class Raycast : MonoBehaviour
{
    // The name of the relevant Layer
    [SerializeField]  string layerToCheck = "Default";

    void Update()
    {
        Vector2 mousePosWorld2D = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);

        GameObject result = GetHighestRaycastTarget(mousePosWorld2D);


        // Do Stuff example:
        Debug.Log($"Highest Layer: {result}");

        if (Input.GetMouseButtonDown(0)
            && result != null)
        {
            Destroy(result);
        }
    }


    // Get highest RaycastTarget based on the Sortinglayer
    // Note: If multiple Objects have the same SortingLayer (e.g. 42) and this is also the highest SortingLayer, then the Function will return the last one it found
    private GameObject GetHighestRaycastTarget(Vector2 mousePos)
    {
        GameObject topLayer = null;
        RaycastHit2D[] hit = Physics2D.RaycastAll(mousePos, Vector2.zero);

        foreach (RaycastHit2D ray in hit)
        {
            SpriteRenderer spriteRenderer = ray.transform.GetComponent<SpriteRenderer>();

            // Check if RaycastTarget has a SpriteRenderer and
            // Check if the found SpriteRenderer uses the relevant SortingLayer
            if (spriteRenderer != null
                && spriteRenderer.sortingLayerName == layerToCheck)
            {
                if (topLayer == null)
                {
                    topLayer = spriteRenderer.transform.gameObject;
                }

                if (spriteRenderer.sortingOrder >= topLayer.GetComponent<SpriteRenderer>().sortingOrder)
                {
                    topLayer = ray.transform.gameObject;
                }
            }

        }

        return topLayer;
    }
}

使用UnityEngine;
公共类Raycast:MonoBehavior
{
//相关层的名称
[SerializeField]string layerToCheck=“默认”;
无效更新()
{
Vector2 mousePosWorld2D=(Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
游戏对象结果=GetHighestRaycastTarget(mousePosWorld2D);
//例如:
Log($“最高层:{result}”);
if(输入。GetMouseButtonDown(0)
&&结果!=空)
{
破坏(结果);
}
}
//根据排序层获取最高的光线目标
//注意:如果多个对象具有相同的排序层(例如42),并且这也是最高的排序层,则函数将返回找到的最后一个
私有游戏对象GetHighestRaycastTarget(Vector2鼠标点)
{
游戏对象顶层=空;
RaycastHit2D[]hit=Physics2D.RaycastAll(mousePos,Vector2.zero);
foreach(光线投射命中中的2D光线)
{
spritender spritender=ray.transform.GetComponent();
//检查RaycastTarget是否有喷洒器和
//检查找到的喷洒器是否使用相关的分拣层
如果(喷洒器!=null
&&SpriteRender.sortingLayerName==layerToCheck)
{
如果(顶层==null)
{
顶层=spriteRenderer.transform.gameObject;
}
if(spriteender.sortingOrder>=topLayer.GetComponent().sortingOrder)
{
顶层=ray.transform.gameObject;
}
}
}
返回顶层;
}
}

是的,我确实使用Unity文档。但是排除图层并不能真正帮助我。如果我使用LayerMask排除我的背景,当两个对象相互重叠时,我仍然会遇到问题。
using UnityEngine;

public class Raycast : MonoBehaviour
{
    // The name of the relevant Layer
    [SerializeField]  string layerToCheck = "Default";

    void Update()
    {
        Vector2 mousePosWorld2D = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);

        GameObject result = GetHighestRaycastTarget(mousePosWorld2D);


        // Do Stuff example:
        Debug.Log($"Highest Layer: {result}");

        if (Input.GetMouseButtonDown(0)
            && result != null)
        {
            Destroy(result);
        }
    }


    // Get highest RaycastTarget based on the Sortinglayer
    // Note: If multiple Objects have the same SortingLayer (e.g. 42) and this is also the highest SortingLayer, then the Function will return the last one it found
    private GameObject GetHighestRaycastTarget(Vector2 mousePos)
    {
        GameObject topLayer = null;
        RaycastHit2D[] hit = Physics2D.RaycastAll(mousePos, Vector2.zero);

        foreach (RaycastHit2D ray in hit)
        {
            SpriteRenderer spriteRenderer = ray.transform.GetComponent<SpriteRenderer>();

            // Check if RaycastTarget has a SpriteRenderer and
            // Check if the found SpriteRenderer uses the relevant SortingLayer
            if (spriteRenderer != null
                && spriteRenderer.sortingLayerName == layerToCheck)
            {
                if (topLayer == null)
                {
                    topLayer = spriteRenderer.transform.gameObject;
                }

                if (spriteRenderer.sortingOrder >= topLayer.GetComponent<SpriteRenderer>().sortingOrder)
                {
                    topLayer = ray.transform.gameObject;
                }
            }

        }

        return topLayer;
    }
}