using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; namespace Vanguard.Board3D { /// /// Ограниченная орбита камеры: ПКМ — поворот, СКМ — панорама, /// колесо — зум. Левая кнопка остаётся картам и UI. /// public sealed class BoardCameraRig : MonoBehaviour { private PlaymatLayoutConfig _config; private Vector3 _target; private float _distance = 15f; private float _yaw; private float _pitch = 35f; private bool _orbiting; private bool _panning; private Vector2 _lastPointer; public void Configure(PlaymatLayoutConfig config) { _config = config != null ? config : PlaymatLayoutConfig.Default; _target = _config.cameraTarget; var offset = _config.cameraPosition - _target; _distance = Mathf.Clamp( offset.magnitude, _config.zoomMin, _config.zoomMax); _pitch = Mathf.Clamp( Mathf.Asin(Mathf.Clamp(offset.y / Mathf.Max(0.001f, _distance), -1f, 1f)) * Mathf.Rad2Deg, _config.orbitPitchMin, _config.orbitPitchMax); _yaw = Mathf.Atan2(-offset.x, -offset.z) * Mathf.Rad2Deg; _yaw = Mathf.Clamp(_yaw, -_config.orbitYawLimit, _config.orbitYawLimit); Apply(); } private void Update() { if (_config == null) return; var mouse = Mouse.current; if (mouse == null) return; var pointer = mouse.position.ReadValue(); var overUi = IsPointerOverUi(); if (mouse.rightButton.wasPressedThisFrame && !overUi) { _orbiting = true; _lastPointer = pointer; } if (mouse.rightButton.wasReleasedThisFrame) _orbiting = false; if (_orbiting && mouse.rightButton.isPressed) { var delta = pointer - _lastPointer; _lastPointer = pointer; _yaw = Mathf.Clamp( _yaw + (delta.x * 0.18f), -_config.orbitYawLimit, _config.orbitYawLimit); _pitch = Mathf.Clamp( _pitch - (delta.y * 0.16f), _config.orbitPitchMin, _config.orbitPitchMax); Apply(); } if (mouse.middleButton.wasPressedThisFrame && !overUi) { _panning = true; _lastPointer = pointer; } if (mouse.middleButton.wasReleasedThisFrame) _panning = false; if (_panning && mouse.middleButton.isPressed) { var delta = pointer - _lastPointer; _lastPointer = pointer; var rotation = Quaternion.Euler(_pitch, _yaw, 0f); var right = rotation * Vector3.right; var forward = rotation * Vector3.forward; right.y = 0f; forward.y = 0f; right.Normalize(); forward.Normalize(); var scale = _config.panSpeed * _distance; _target -= (right * (delta.x * scale)) + (forward * (delta.y * scale)); _target.x = Mathf.Clamp(_target.x, -2.5f, 2.5f); _target.z = Mathf.Clamp(_target.z, -2f, 2f); Apply(); } var scroll = mouse.scroll.ReadValue().y; if (!overUi && Mathf.Abs(scroll) > 0.01f) { _distance = Mathf.Clamp( _distance - (scroll * _config.zoomSpeed), _config.zoomMin, _config.zoomMax); Apply(); } } private void Apply() { var rotation = Quaternion.Euler(_pitch, _yaw, 0f); transform.rotation = rotation; transform.position = _target - (rotation * Vector3.forward * _distance); var camera = GetComponent(); if (camera != null) camera.fieldOfView = _config.cameraFov; } private static bool IsPointerOverUi() { var eventSystem = EventSystem.current; return eventSystem != null && eventSystem.IsPointerOverGameObject(); } } }