Fix raycast to not hit through ui

This commit is contained in:
HungDK
2026-04-15 11:26:47 +07:00
parent c70b752c19
commit 9ddb91a087
3 changed files with 89 additions and 0 deletions
@@ -99,6 +99,18 @@ namespace BrewMonster
/// <param name="idTargetOverride">Optional target ID to use instead of raycast (for second-click behavior) / 可选的目标ID,用于替代射线检测(用于第二次点击行为)</param>
public void OnMsgLBtnClick(int idTargetOverride = 0)
{
// Interactive UI (buttons, fields, scrolls) consumes the click. Full-screen raycast panels alone do not.
// When a non-HUD dialog is open, block world interaction entirely (terrain/NPC/matter) until it is closed.
if (idTargetOverride == 0)
{
if (CECUIManager.IsPointerOverInteractiveUI())
return;
var uiMan = EC_Game.GetGameRun()?.GetUIManager();
if (uiMan != null && uiMan.IsWorldInteractionBlockedByUI())
return;
}
// 停止自动策略 / Stop auto policy
// Note: Auto policy check would go here if implemented
@@ -84,6 +84,13 @@ public class pickupItem : MonoBehaviour
// Check for mouse clicks on cubes
if (Input.GetMouseButtonDown(0))
{
if (CECUIManager.IsPointerOverInteractiveUI())
return;
var uiMan = EC_Game.GetGameRun()?.GetUIManager();
if (uiMan != null && uiMan.IsWorldInteractionBlockedByUI())
return;
HandleCubeClick();
}
}
+70
View File
@@ -9,6 +9,8 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Task.UI;
using BrewMonster.Scripts.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using TMPro;
public class CECUIManager : MonoSingleton<CECUIManager>
@@ -366,6 +368,74 @@ public class CECUIManager : MonoSingleton<CECUIManager>
return null;
}
/// <summary>
/// Dialog names on <see cref="_uiStack"/> that are normal gameplay HUD and must NOT block world raycasts
/// (the stack always has at least <c>Win_Hpmpxp</c> after <see cref="Awake"/>).
/// </summary>
private static readonly HashSet<string> HudStackDialogNames = new HashSet<string>(StringComparer.Ordinal)
{
"Win_Hpmpxp",
};
/// <summary>
/// Returns true when a modal / non-HUD dialog is open and world clicks should be ignored.
/// </summary>
public bool IsWorldInteractionBlockedByUI()
{
if (_uiStack == null || _uiStack.Count == 0)
return false;
foreach (var name in _uiStack)
{
if (string.IsNullOrEmpty(name))
continue;
if (!HudStackDialogNames.Contains(name))
return true;
}
return false;
}
/// <summary>
/// True when the pointer hits UI that should consume the click (buttons, fields, scroll views).
/// Unlike <see cref="EventSystem.IsPointerOverGameObject"/>, full-screen Images/Text with raycast
/// but no interactive control do not block — so clicks can reach the world for NPC selection.
/// </summary>
public static bool IsPointerOverInteractiveUI()
{
var es = EventSystem.current;
if (es == null)
return false;
Vector2 pos = Input.mousePosition;
if (Input.touchCount > 0)
pos = Input.GetTouch(0).position;
var ped = new PointerEventData(es) { position = pos };
var results = new List<RaycastResult>();
es.RaycastAll(ped, results);
if (results.Count == 0)
return false;
foreach (var r in results)
{
var go = r.gameObject;
if (go == null)
continue;
if (go.GetComponentInParent<Selectable>() != null)
return true;
if (go.GetComponentInParent<TMP_InputField>() != null)
return true;
if (go.GetComponentInParent<InputField>() != null)
return true;
if (go.GetComponentInParent<ScrollRect>() != null)
return true;
}
return false;
}
// public CDlgMessageBox ShowMessageBox(MessageBoxData messageBoxData)
// {
// var msgBox = GetInGameUIMan().GetDialog("DlgMessageBox") as CDlgMessageBox;