67 lines
3.7 KiB
C#
67 lines
3.7 KiB
C#
using System.Collections.Generic;
|
|||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.EventSystems;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
// Палец над HUD в 3D-поселении (05.11): «над интерфейсом» -- только если под пальцем то, что нажимают или крутят
|
||
|
|
// (кнопка, поле, ползунок, прокручиваемое окно) или небольшая панель. Невидимый слой во весь экран
|
||
|
|
// (затемнение, контейнер безопасной зоны, фон) карту не блокирует -- иначе не работают ни тап, ни зум, ни стройка.
|
||
|
|
// Такой слой пишется в Console один раз, чтобы его можно было найти и убрать.
|
||
|
|
public static class City3DInput
|
||
|
|
{
|
||
|
|
static readonly List<RaycastResult> hits = new List<RaycastResult>();
|
||
|
|
static readonly HashSet<string> reported = new HashSet<string>();
|
||
|
|
|
||
|
|
public static bool OverHud(Vector2 screen)
|
||
|
|
{
|
||
|
|
var es = EventSystem.current;
|
||
|
|
if (es == null) return false;
|
||
|
|
// Открыто окно HUD (панель) -- весь ввод его, карта не трогается
|
||
|
|
if (UIPanelManager.Instance != null && UIPanelManager.Instance.CurrentId != "")
|
||
|
|
{
|
||
|
|
if (reported.Add("panel:" + UIPanelManager.Instance.CurrentId))
|
||
|
|
Debug.Log($"[3D] Открыта панель HUD «{UIPanelManager.Instance.CurrentId}» -- 3D-карта не принимает нажатия, пока её не закрыть");
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
hits.Clear();
|
||
|
|
es.RaycastAll(new PointerEventData(es) { position = screen }, hits);
|
||
|
|
foreach (var h in hits)
|
||
|
|
{
|
||
|
|
if (h.gameObject == null) continue;
|
||
|
|
if (IsInteractive(h.gameObject) || !CoversScreen(h.gameObject)) return true;
|
||
|
|
if (reported.Add(h.gameObject.name))
|
||
|
|
Debug.Log($"[3D] Слой интерфейса во весь экран ловит нажатия, 3D-карта его пропускает: «{Path(h.gameObject.transform)}». " +
|
||
|
|
"Если он не нужен -- выключить у него Raycast Target");
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool IsInteractive(GameObject go)
|
||
|
|
{
|
||
|
|
// кнопки, прокрутка, поля, а также всё, что само ловит нажатие (затемнение модального окна закрывает его тапом)
|
||
|
|
return go.GetComponentInParent<Selectable>() != null || go.GetComponentInParent<ScrollRect>() != null
|
||
|
|
|| go.GetComponentInParent<IPointerClickHandler>() != null || go.GetComponentInParent<IPointerDownHandler>() != null
|
||
|
|
|| go.name == "Modal" || go.GetComponentInParent<TMPro.TMP_InputField>() != null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Занимает почти весь экран (больше 80% по ширине и высоте)
|
||
|
|
static bool CoversScreen(GameObject go)
|
||
|
|
{
|
||
|
|
if (!(go.transform is RectTransform rt)) return false;
|
||
|
|
var corners = new Vector3[4];
|
||
|
|
rt.GetWorldCorners(corners);
|
||
|
|
var canvas = go.GetComponentInParent<Canvas>();
|
||
|
|
Camera cam = canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay ? canvas.worldCamera : null;
|
||
|
|
Vector2 a = RectTransformUtility.WorldToScreenPoint(cam, corners[0]);
|
||
|
|
Vector2 b = RectTransformUtility.WorldToScreenPoint(cam, corners[2]);
|
||
|
|
return Mathf.Abs(b.x - a.x) > Screen.width * 0.8f && Mathf.Abs(b.y - a.y) > Screen.height * 0.8f;
|
||
|
|
}
|
||
|
|
|
||
|
|
static string Path(Transform t)
|
||
|
|
{
|
||
|
|
string p = t.name;
|
||
|
|
for (var x = t.parent; x != null; x = x.parent) p = x.name + "/" + p;
|
||
|
|
return p;
|
||
|
|
}
|
||
|
|
}
|