c# - 2D Raycast 无法正确检测重叠碰撞器并忽略排序层

标签 c# unity-game-engine raycasting collider

我希望能够与我的游戏对象交互,同时使用排序层组织我的 Sprite 。 目前,排序层不会影响我的光线转换/碰撞器情况,只会改变我的订单的视觉外观。

在我的测试场景中,我有两个 Sprite :一个背景和一个对象。 两者都有一个 2D Box Collider 组件。 我的 Raycast 脚本应该检测我的鼠标悬停在哪个对象上;背景 (BG) 或位于 BG 之上的对象。

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

我尝试过:

  • 这是一个新的 2D 项目,因此我的相机投影设置为 Orthograph,我的 BG 和对象使用 Sprite Renderer 并使用 2D collider
  • 前后更改“层顺序”,包括负数。
  • 添加前景(和背景)“排序层” (两个选项仅具有视觉效果,不影响Raycast输出)

  • 更改层次结构中的位置。

  • 删除并重新添加碰撞器。 (!) 我观察到我最后添加的 2D Box 碰撞器将始终位于所有其他碰撞器之后。这是我现在可以处理的事情。但当项目变得更大时,就会成为一个问题。

我希望能够在 2D 点击冒险中与元素和门等进行交互(点击和对鼠标悬停的 react )。如果 2D Raycast 不是存档此内容的方法,我很高兴了解在这种情况下使用的正确技术。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class RayCast : MonoBehaviour
{
    [SerializeField] private Vector2 mousePosWorld2D;
    RaycastHit2D hit;

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

        hit = Physics2D.Raycast(mousePosWorld2D, Vector2.zero);
        if (hit.collider)
        {
            Debug.Log("Found collider: " + hit.collider.name);
        }
        else
        {
            Debug.Log("No collider found.");
        }
    }
}

我预计“排序图层”或“图层顺序”会对我的光线转换产生影响,而更改 Z 位置则不起作用。但事实恰恰相反。排序层仅具有视觉效果,将我的对象移近相机(Z 位置)有助于检测正确的碰撞器。

如何解决这个问题?

最佳答案

首先被射线击中的东西仅与碰撞器与摄像机的距离有关,与层次结构或排序层中的顺序无关。

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

我们使用 foreach 循环发射光线转换并迭代我们击中的所有碰撞体。然后该函数将返回具有最高 SortingLayer 的 GameObject。注意:如果有多个具有最高 SortingLayer 的 GameObject,该函数将返回找到的最后一个。

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;
    }
}

关于c# - 2D Raycast 无法正确检测重叠碰撞器并忽略排序层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57437400/

相关文章:

c# - CONTENT-AWARE FILL 在 Photoshop 中如何工作?

c# - 当您将 DTO 模式与某些缓存或 MVVM 结合使用时,DTO 模式不是才有用吗?

algorithm - 如何通过 2D 网格有效地实现光线转换?

javascript - 使用 raycaster 时如何防止背景着色?

C# Unity 3D - 有没有办法制作自定义光线转换形状?

c# - c# - 如何搜索文本文件中存在的两个或多个单词的单词

c# - 从 Main() c# 调用在非静态类中定义的非扩展方法

c# - 将 mp3 字节数组转换为 float 组以在 Unity 中播放

javascript - 在接近零之前,我可以将一个数字乘以小数/分数多少次

javascript - 在同一页面上运行 2 个 Emscripten 脚本