using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
///
/// Orbit the tank with the mouse: drag to look around within a limited arc
/// (so paper cards never go edge-on), scroll to zoom. Works with either the
/// new Input System or the legacy Input manager.
/// Tab toggles room mode: fly freely around the room (WASD / arrows to move,
/// Q/E down/up, drag to look, scroll to move forward, Shift for speed).
/// Tab again glides back to the tank view.
///
public class TankOrbitCamera : MonoBehaviour
{
public Vector3 pivot = new Vector3(0f, 0f, 0f);
public float distance = 16f;
public Vector2 distanceRange = new Vector2(8f, 24f);
[Header("Limits (degrees)")]
public float yawLimit = 40f;
public Vector2 pitchRange = new Vector2(-8f, 25f);
[Header("Feel")]
public float dragSensitivity = 0.25f;
public float zoomSensitivity = 2f;
public float smoothing = 8f;
public bool dragWithLeftButton = true;
[Header("Room mode (Tab)")]
public float roomMoveSpeed = 40f;
public float roomLookSensitivity = 2.5f;
bool roomMode, returning;
float roomYaw, roomPitch;
float yaw, pitch, targetYaw, targetPitch, targetDistance;
void Start()
{
targetDistance = distance;
var cam = GetComponent();
if (cam != null) cam.farClipPlane = Mathf.Max(cam.farClipPlane, 3000f); // the room is scaled up; don't clip its far walls
Vector3 dir = (transform.position - pivot).normalized;
targetYaw = yaw = Mathf.Atan2(dir.x, -dir.z) * Mathf.Rad2Deg;
targetPitch = pitch = Mathf.Asin(dir.y) * Mathf.Rad2Deg;
Apply();
}
void ReadMouse(out bool dragging, out Vector2 delta, out float scroll)
{
#if ENABLE_INPUT_SYSTEM
var m = Mouse.current;
if (m == null) { dragging = false; delta = Vector2.zero; scroll = 0f; return; }
dragging = m.rightButton.isPressed || (dragWithLeftButton && m.leftButton.isPressed);
delta = m.delta.ReadValue() * 0.1f; // roughly match legacy axis scale
scroll = m.scroll.ReadValue().y / 120f; // wheel notches
#else
dragging = Input.GetMouseButton(1) || (dragWithLeftButton && Input.GetMouseButton(0));
delta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
scroll = Input.mouseScrollDelta.y;
#endif
}
bool TabPressed()
{
#if ENABLE_INPUT_SYSTEM
return Keyboard.current != null && Keyboard.current.tabKey.wasPressedThisFrame;
#else
return Input.GetKeyDown(KeyCode.Tab);
#endif
}
Vector3 ReadMove(out bool fast)
{
float x = 0, y = 0, z = 0;
#if ENABLE_INPUT_SYSTEM
var k = Keyboard.current;
fast = k != null && k.leftShiftKey.isPressed;
if (k != null)
{
if (k.wKey.isPressed || k.upArrowKey.isPressed) z += 1;
if (k.sKey.isPressed || k.downArrowKey.isPressed) z -= 1;
if (k.dKey.isPressed || k.rightArrowKey.isPressed) x += 1;
if (k.aKey.isPressed || k.leftArrowKey.isPressed) x -= 1;
if (k.eKey.isPressed) y += 1;
if (k.qKey.isPressed) y -= 1;
}
#else
fast = Input.GetKey(KeyCode.LeftShift);
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) z += 1;
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) z -= 1;
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) x += 1;
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) x -= 1;
if (Input.GetKey(KeyCode.E)) y += 1;
if (Input.GetKey(KeyCode.Q)) y -= 1;
#endif
return new Vector3(x, y, z);
}
void Update()
{
ReadMouse(out bool dragging, out Vector2 delta, out float scroll);
if (TabPressed())
{
roomMode = !roomMode;
if (roomMode)
{
var e = transform.rotation.eulerAngles;
roomYaw = e.y; roomPitch = e.x > 180f ? e.x - 360f : e.x;
returning = false;
}
else returning = true;
}
if (roomMode)
{
if (dragging)
{
roomYaw += delta.x * roomLookSensitivity;
roomPitch = Mathf.Clamp(roomPitch - delta.y * roomLookSensitivity, -85f, 85f);
}
var move = ReadMove(out bool fast);
var rot = Quaternion.Euler(roomPitch, roomYaw, 0f);
float speed = roomMoveSpeed * (fast ? 3f : 1f);
var step = rot * new Vector3(move.x, 0f, move.z) + Vector3.up * move.y;
transform.position += step * speed * Time.deltaTime + rot * Vector3.forward * scroll * speed * 0.15f;
transform.rotation = Quaternion.Slerp(transform.rotation, rot, 1f - Mathf.Exp(-20f * Time.deltaTime));
return;
}
if (dragging)
{
targetYaw -= delta.x * dragSensitivity * 10f;
targetPitch += delta.y * dragSensitivity * 10f;
}
targetDistance -= scroll * zoomSensitivity;
targetYaw = Mathf.Clamp(targetYaw, -yawLimit, yawLimit);
targetPitch = Mathf.Clamp(targetPitch, pitchRange.x, pitchRange.y);
targetDistance = Mathf.Clamp(targetDistance, distanceRange.x, distanceRange.y);
float k = 1f - Mathf.Exp(-smoothing * Time.deltaTime);
yaw = Mathf.Lerp(yaw, targetYaw, k);
pitch = Mathf.Lerp(pitch, targetPitch, k);
distance = Mathf.Lerp(distance, targetDistance, k);
Apply();
}
void Apply()
{
var rot = Quaternion.Euler(pitch, yaw, 0f);
var pos = pivot + rot * new Vector3(0f, 0f, -distance);
if (returning)
{
// Glide back from wherever room mode left the camera
float k = 1f - Mathf.Exp(-4f * Time.deltaTime);
transform.position = Vector3.Lerp(transform.position, pos, k);
transform.rotation = Quaternion.Slerp(transform.rotation, rot, k);
if ((transform.position - pos).sqrMagnitude < 0.01f) returning = false;
return;
}
transform.position = pos;
transform.rotation = rot;
}
void OnGUI()
{
var style = new GUIStyle(GUI.skin.label) { fontSize = 14 };
style.normal.textColor = new Color(1f, 1f, 1f, 0.75f);
GUI.Label(new Rect(12, 8, 700, 24), roomMode
? "Room view: WASD/arrows move, Q/E down/up, drag to look, Shift faster. Tab to return to the tank."
: "Tank view: drag to orbit, scroll to zoom. Tab to look around the room.", style);
}
}