#nullable enable using System; using Demo2.Domain; using UnityEngine; using UnityEngine.UIElements; namespace Demo2.Runtime { public sealed class Demo2GridInput : IDisposable { private readonly VisualElement _surface; private readonly Camera _worldCamera; private bool _middleDragging; public event Action? GridClicked; public Demo2GridInput(VisualElement surface, Camera worldCamera) { _surface = surface; _worldCamera = worldCamera; _surface.RegisterCallback(OnPointerDown); _surface.RegisterCallback(OnPointerUp); _surface.RegisterCallback(OnPointerMove); _surface.RegisterCallback(OnWheel); } public void Dispose() { _surface.UnregisterCallback(OnPointerDown); _surface.UnregisterCallback(OnPointerUp); _surface.UnregisterCallback(OnPointerMove); _surface.UnregisterCallback(OnWheel); } private void OnPointerDown(PointerDownEvent eventData) { if (eventData.button == 2) { _middleDragging = true; _surface.CapturePointer(eventData.pointerId); eventData.StopPropagation(); return; } if (eventData.button is not (0 or 1)) return; var world = _worldCamera.ScreenToWorldPoint(PanelToScreen(eventData.position)); var x = Mathf.FloorToInt(world.x); var y = Demo2Protocol.GridHeight - 1 - Mathf.FloorToInt(world.y); if (x >= 0 && x < Demo2Protocol.GridWidth && y >= 0 && y < Demo2Protocol.GridHeight) GridClicked?.Invoke(x, y, eventData.button); eventData.StopPropagation(); } private void OnPointerUp(PointerUpEvent eventData) { if (eventData.button != 2) return; _middleDragging = false; if (_surface.HasPointerCapture(eventData.pointerId)) _surface.ReleasePointer(eventData.pointerId); eventData.StopPropagation(); } private void OnPointerMove(PointerMoveEvent eventData) { if (!_middleDragging) return; var scale = _worldCamera.orthographicSize * 2f / Mathf.Max(1, _surface.resolvedStyle.height); var position = _worldCamera.transform.position; position -= new Vector3(eventData.deltaPosition.x, -eventData.deltaPosition.y) * scale; position.x = Mathf.Clamp(position.x, 4f, Demo2Protocol.GridWidth - 4f); position.y = Mathf.Clamp(position.y, 3f, Demo2Protocol.GridHeight - 3f); _worldCamera.transform.position = position; eventData.StopPropagation(); } private void OnWheel(WheelEvent eventData) { _worldCamera.orthographicSize = Mathf.Clamp(_worldCamera.orthographicSize + eventData.delta.y * 0.7f, 5f, 15f); eventData.StopPropagation(); } private Vector3 PanelToScreen(Vector3 panelPosition) { var root = _surface.panel?.visualTree; var width = Mathf.Max(1, root?.resolvedStyle.width ?? Screen.width); var height = Mathf.Max(1, root?.resolvedStyle.height ?? Screen.height); return new Vector3(panelPosition.x / width * Screen.width, Screen.height - panelPosition.y / height * Screen.height, 0); } } }