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();
}
}
}