如何阻止光线投射统一通过按钮?

问题描述 投票:0回答:2

我有一个脚本,它用于检测是否将鼠标悬停在或单击了一个省份,如果单击,则选择该省份,并在屏幕上显示UI。但是,当我选择一个省份,然后尝试单击 UI 中的构建按钮时,光线会穿过该按钮并取消选择该省份,而无需单击该按钮。

using UnityEngine;
using UnityEngine.UI;

public class ProvinceSelection : MonoBehaviour
{
    public GameObject actionPanel;
    public BuildStructure provinceBuilder;
    public float hoverBrightness = 1.5f;
    public float originalBrightness = 1.0f;

    private Material provinceMaterial;
    private bool isSelected = false;
    private static GameObject selectedProvince;
    private Camera mainCamera;

    void Start()
    {
        actionPanel.SetActive(false);
        mainCamera = GameObject.FindGameObjectWithTag("Player").GetComponent<Camera>();
        provinceMaterial = GetComponent<Renderer>().material;
    }

    void Update()
    {
        if (isSelected || IsHovering())
        {
            provinceMaterial.SetFloat("_Brightness", hoverBrightness);
        }
        else
        {
            provinceMaterial.SetFloat("_Brightness", originalBrightness);
        }

        if (isSelected && Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
            if (!Physics.Raycast(ray, out hit))
            {
                DeselectProvince();
            }
        }
    }

    void OnMouseDown()
    {
        if (selectedProvince != null && selectedProvince != gameObject)
        {
            selectedProvince.GetComponent<ProvinceSelection>().DeselectProvince();
        }

        isSelected = true;
        selectedProvince = gameObject;
        Debug.Log("Clicked on province: " + gameObject.name);

        actionPanel.SetActive(true);
        Text provinceNameText = actionPanel.GetComponentInChildren<Text>();
        if (provinceNameText != null)
        {
            provinceNameText.text = gameObject.name;
        }
        else
        {
            Debug.LogWarning("No Text component found in the action panel.");
        }

        provinceBuilder.SetSelectedProvince(gameObject);
    }

    public void DeselectProvince()
    {
        isSelected = false;
        selectedProvince = null;
        actionPanel.SetActive(false);
    }

    bool IsHovering()
    {
        if (mainCamera != null)
        {
            Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit))
            {
                return hit.collider.gameObject == gameObject;
            }
        }
        return false;
    }
}

我尝试过使用事件系统,但没有成功。当我使用事件系统时,当我单击地图之外时,它没有取消选择省份,并且当 UI 放大并覆盖地图时,光线仍然穿过。

c# user-interface unityscript raycasting
2个回答
0
投票

替换此代码:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class ProvinceSelection : MonoBehaviour
{

public GameObject actionPanel;
public BuildStructure provinceBuilder;
public float hoverBrightness = 1.5f;
public float originalBrightness = 1.0f;

private Material provinceMaterial;
private bool isSelected = false;
private static GameObject selectedProvince;
private Camera mainCamera;

void Start()
{
    actionPanel.SetActive(false);
    mainCamera = GameObject.FindGameObjectWithTag("Player").GetComponent<Camera>();
    provinceMaterial = GetComponent<Renderer>().material;
}

void Update()
{
    if (isSelected || IsHovering())
    {
        provinceMaterial.SetFloat("_Brightness", hoverBrightness);
    }
    else
    {
        provinceMaterial.SetFloat("_Brightness", originalBrightness);
    }

    if (isSelected && Input.GetMouseButtonDown(0) && !IsPointerOverUIObject())
    {
        DeselectProvince();
    }
}

void OnMouseDown()
{
    if (selectedProvince != null && selectedProvince != gameObject)
    {
        selectedProvince.GetComponent<ProvinceSelection>().DeselectProvince();
    }

    isSelected = true;
    selectedProvince = gameObject;
    Debug.Log("Clicked on province: " + gameObject.name);

    actionPanel.SetActive(true);
    Text provinceNameText = actionPanel.GetComponentInChildren<Text>();
    if (provinceNameText != null)
    {
        provinceNameText.text = gameObject.name;
    }
    else
    {
        Debug.LogWarning("No Text component found in the action panel.");
    }

    provinceBuilder.SetSelectedProvince(gameObject);
}

public void DeselectProvince()
{
    isSelected = false;
    selectedProvince = null;
    actionPanel.SetActive(false);
}

bool IsHovering()
{
    if (mainCamera != null)
    {
        Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit))
        {
            return hit.collider.gameObject == gameObject;
        }
    }
    return false;
}

bool IsPointerOverUIObject()
{
    PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
    eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    var results = new List<RaycastResult>();
    EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
    return results.Count > 0;
}

}


0
投票

您是否尝试过排除光线投射上的“UI”层?我假设你的所有 UI 都在 UI 层中(这是创建 Canvas 或 UI 元素时默认的层)

如果不是这种情况,只需将 UI 顶部 GameObject 的图层(例如画布)更改为 UI Layer。

图层按钮说明

单击“是,更改子项”将修改应用于所有子项

适用于儿童图像

编辑您的代码是“更新”功能:

 RaycastHit hit;
 Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
 if (!Physics.Raycast(ray, out hit))
 {
    DeselectProvince();
 }

对此:

RaycastHit hit;
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
int mask = ~(1 << LayerMask.NameToLayer("UI"));
if (!Physics.Raycast(ray, out hit, 10, mask))
{
    DeselectProvince();
}

10 是 maxDistance 值,需要提供才能使用带有“mask”参数的函数签名。根据您的用例调整此值。

© www.soinside.com 2019 - 2024. All rights reserved.