我有一个脚本,它用于检测是否将鼠标悬停在或单击了一个省份,如果单击,则选择该省份,并在屏幕上显示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 放大并覆盖地图时,光线仍然穿过。
替换此代码:
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;
}
}
您是否尝试过排除光线投射上的“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”参数的函数签名。根据您的用例调整此值。