Files
riversong-code-showcase/Source/Riversong/Game/UI/Panels/WorldUI/WorldUITrackingSystem.cs
2026-05-21 16:04:49 +02:00

71 lines
2.3 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.UIElements;
namespace DanieleMarotta.RiversongCodeShowcase
{
[Service(typeof(IWorldUIService))]
[GameSystemGroup(typeof(UISystemGroup))]
public class WorldUITrackingSystem : GameSystem, IUpdatable, IWorldUIService
{
[InjectService]
private IScene _scene;
private readonly Dictionary<VisualElement, TrackedElement> _trackedElements = new();
public WorldUITrackingSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public void Register(VisualElement element, Transform target)
{
_trackedElements[element] = new TrackedElement { Target = target };
}
public void Unregister(VisualElement element)
{
_trackedElements.Remove(element);
}
public void SetWorldOffset(VisualElement element, Vector3 offset)
{
var trackedElement = _trackedElements[element];
trackedElement.Offset = offset;
_trackedElements[element] = trackedElement;
}
public void Update()
{
if (_trackedElements.Count == 0) return;
using var invalidScope = ListPool<VisualElement>.Get(out var invalidElements);
var camera = _scene.MainCamera;
foreach (var (element, trackedElement) in _trackedElements)
{
var target = trackedElement.Target;
if (element.panel == null || target == null)
{
invalidElements.Add(element);
continue;
}
var screenPoint = camera.WorldToScreenPoint(target.position + trackedElement.Offset);
var isVisible = screenPoint.x >= 0 && screenPoint.x <= Screen.width && screenPoint.y >= 0 && screenPoint.y <= Screen.height && screenPoint.z > 0;
element.style.visibility = isVisible ? Visibility.Visible : Visibility.Hidden;
if (isVisible) element.SetAbsoluteScreenPosition(screenPoint);
}
foreach (var invalidElement in invalidElements) _trackedElements.Remove(invalidElement);
}
private struct TrackedElement
{
public Transform Target;
public Vector3 Offset;
}
}
}