using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UIElements; namespace DanieleMarotta.RiversongCodeShowcase { [Service(typeof(IPointerService))] [GameSystemGroup(typeof(EarlyGameSystemGroup))] public class PointerSystem : GameSystem, IUpdatable, IPointerService { [InjectService] private IScene _scene; [InjectService] private GameConfig _config; [InjectService] private ITileSpace _tileSpace; [InjectService] private World _world; [InjectService] private UIService _uiService; private int _leftButtonClickCount; private Vector3? _positionOnTerrain; public PointerSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public bool IsPointerOverUI { get; private set; } public void Update() { _leftButtonClickCount = 0; UpdateIsPointerOverUIFlag(); UpdatePositionOnTerrain(); } private void UpdateIsPointerOverUIFlag() { var panel = _uiService.UIRoot.RootVisualElement.panel; var position = Mouse.current.position.ReadValue(); position.y = Screen.height - position.y; position = RuntimePanelUtils.ScreenToPanel(panel, position); IsPointerOverUI = panel.Pick(position) != null; } private void UpdatePositionOnTerrain() { _positionOnTerrain = null; var ray = _scene.MainCamera.ScreenPointToRay(Mouse.current.position.ReadValue()); if (Physics.Raycast(ray, out var hit, float.PositiveInfinity)) { if (!Mathf.Approximately(Vector3.Dot(hit.normal, Vector3.up), 1)) return; if (_tileSpace.GetElevation(hit.point.y) != _config.GeneralSettings.BaseElevation) return; _positionOnTerrain = hit.point; } } public bool TryGetPositionOnTerrain(out Vector3 position) { position = _positionOnTerrain ?? Vector3.zero; return _positionOnTerrain != null; } public bool TryConsumeLeftClick(int maxClickCount = 0) { return !IsPointerOverUI && Mouse.current.leftButton.wasPressedThisFrame && _leftButtonClickCount++ <= maxClickCount; } } }