Files
VOIDRPG/Assets/92 - UserInterface/Generic/GameUI.cs
T
2026-07-09 21:33:33 +02:00

112 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
namespace VOID.UserInterface
{
[DefaultExecutionOrder(-1)]
public class GameUI : MonoBehaviour
{
public static GameUI current { get; private set; }
[Title("Generic Templates:")]
public VisualTreeAsset slotTemplate => _slotTemplate;
public VisualTreeAsset statusTemplate => _statusTemplate;
public VisualTreeAsset unitPortraitTemplate => _unitPortraitTemplate;
public VisualTreeAsset levelUpOptionTemplate => _levelUpOptionTemplate;
public VisualTreeAsset profileTemplate => _profileTemplate;
[SerializeField, Required] private VisualTreeAsset _slotTemplate;
[SerializeField, Required] private VisualTreeAsset _statusTemplate;
[SerializeField, Required] private VisualTreeAsset _unitPortraitTemplate;
[SerializeField, Required] private VisualTreeAsset _levelUpOptionTemplate;
[SerializeField, Required] private VisualTreeAsset _profileTemplate;
private VisualElement _rootVisualElement;
public IPanel runtimePanel { get; private set; }
public PanelSettings panelSettings { get; private set; }
public Vector2 cursorPositionOnUI { get; private set; }
public bool isCursorOverUI { get; private set; }
public float scale { get; private set; }
// Visual elements under cursor + event when Visual element under cursor changes
public readonly List<VisualElement> elementsUnderCursor = new();
public event Action ElementsUnderCursorChanged;
private void Awake()
{
current = this;
var uiDocument = gameObject.GetComponent<UIDocument>();
_rootVisualElement = uiDocument.rootVisualElement;
panelSettings = uiDocument.panelSettings;
runtimePanel = _rootVisualElement.panel;
CalculateScale();
}
public VisualElement PickTopElementUI(List<VisualElement> cachedElements = null)
{
return (cachedElements ?? elementsUnderCursor).FirstOrDefault();
}
public T PickComponentUI<T>(List<VisualElement> cachedElements = null)
{
return (cachedElements ?? elementsUnderCursor).Select(el => el.dataSource).FilterCast<T>().FirstOrDefault();
}
public T PickTopComponentUI<T>(List<VisualElement> cachedElements = null)
{
return PickTopComponentUI(cachedElements) is T dataSource ? dataSource : default;
}
public object PickTopComponentUI(List<VisualElement> cachedElements = null)
{
return PickTopElementUI(cachedElements)?.dataSource;
}
private void CalculateScale()
{
var screenSize = new Vector2(Screen.width, Screen.height);
var referenceScreenSize = panelSettings.referenceResolution;
var proportions = referenceScreenSize / screenSize;
scale = proportions.x * panelSettings.match + proportions.y * (1f - panelSettings.match);
}
private void Update()
{
FindCursorPositionOnUI();
FindElementsUnderCursor();
isCursorOverUI = !elementsUnderCursor.IsNullOrEmpty();
}
private void FindCursorPositionOnUI()
{
var mousePos = Mouse.current.position.ReadValue();
mousePos.y = Screen.height - mousePos.y;
cursorPositionOnUI = RuntimePanelUtils.ScreenToPanel(runtimePanel, mousePos);
}
private void FindElementsUnderCursor()
{
var previousTopElement = elementsUnderCursor.FirstOrDefault();
var currentTopElement = _rootVisualElement.panel.Pick(cursorPositionOnUI);
elementsUnderCursor.Clear();
// Find all "touchable" elements in UI under cursor - those with PickingMode.Position
// Move through parents (in case when position absolute is used)
var element = currentTopElement;
while (element != null)
{
if (element.pickingMode is PickingMode.Position) elementsUnderCursor.Add(element);
element = element.parent;
}
if (previousTopElement != currentTopElement) ElementsUnderCursorChanged?.Invoke();
}
}
}