using UnityEngine; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif /// /// Fixed lobby camera. The view doesn't move on its own or with the mouse: left clicking a /// ViewTarget (the tank, the computer monitor) glides the camera face on and close to it, and /// right clicking glides back to the lobby view the scene was built with. /// [RequireComponent(typeof(Camera))] public class LobbyCamera : MonoBehaviour { [Tooltip("Seconds for the glide between views.")] public float moveTime = 0.8f; [Tooltip("The lobby view, set by the scene builder. Used on start and for Back, whatever pose the camera was saved in.")] public bool hasHomePose; public Vector3 homePosition; public Quaternion homeRotation = Quaternion.identity; Camera cam; Vector3 homePos, fromPos, toPos; Quaternion homeRot, fromRot, toRot; float t = 1f; ViewTarget current, hover; /// Label of the close-up the camera is in, or null in the lobby view. public static string CurrentLabel { get; private set; } /// When true (a browser has the keyboard), only F1 leaves the close-up; Esc/Backspace/scroll are passed through. public static bool CaptureKeys; static LobbyCamera instance; public static void RequestView(ViewTarget t) { if (instance != null) instance.GoTo(t); } ILobbyClickable hoverClick; void Start() { cam = GetComponent(); instance = this; if (hasHomePose) transform.SetPositionAndRotation(homePosition, homeRotation); homePos = toPos = transform.position; homeRot = toRot = transform.rotation; } void ReadMouse(out Vector2 pos, out bool left, out bool right) { // "Back" is a right click, Esc, Backspace, or scrolling the wheel toward you #if ENABLE_INPUT_SYSTEM var m = Mouse.current; var k = Keyboard.current; pos = m != null ? m.position.ReadValue() : Vector2.zero; left = m != null && m.leftButton.wasPressedThisFrame; right = (m != null && (m.rightButton.wasPressedThisFrame || m.scroll.ReadValue().y < -0.1f)) || (k != null && (k.escapeKey.wasPressedThisFrame || k.backspaceKey.wasPressedThisFrame)); #else pos = Input.mousePosition; left = Input.GetMouseButtonDown(0); right = Input.GetMouseButtonDown(1) || Input.mouseScrollDelta.y < -0.1f || Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Backspace); #endif } void Update() { ReadMouse(out var mouse, out bool left, out bool right); hover = null; hoverClick = null; if (current == null && cam != null) { var ray = cam.ScreenPointToRay(mouse); var hits = Physics.RaycastAll(ray, cam.farClipPlane); System.Array.Sort(hits, (a, b) => a.distance.CompareTo(b.distance)); foreach (var h in hits) { var click = h.collider.GetComponent(); if (click != null) { hoverClick = click; break; } var vt = h.collider.GetComponentInParent(); if (vt != null) { hover = vt; break; } } } if (left && hoverClick != null) hoverClick.Click(); else if (left && hover != null) GoTo(hover); else if (right && current != null && !CaptureKeys) GoHome(); if (t < 1f) { t = Mathf.Min(1f, t + Time.deltaTime / Mathf.Max(0.01f, moveTime)); float e = t * t * (3f - 2f * t); // ease in and out transform.SetPositionAndRotation(Vector3.Lerp(fromPos, toPos, e), Quaternion.Slerp(fromRot, toRot, e)); } } void GoTo(ViewTarget target) { var b = target.Bounds; var rot = Quaternion.Euler(target.pitch, 0f, 0f); float halfV = cam.fieldOfView * 0.5f * Mathf.Deg2Rad; float halfH = Mathf.Atan(Mathf.Tan(halfV) * cam.aspect); float dist = Mathf.Max(b.extents.y / Mathf.Tan(halfV), b.extents.x / Mathf.Tan(halfH)) * target.padding + b.extents.z; Begin(b.center - rot * Vector3.forward * dist, rot); current = target; CurrentLabel = target.label; } void GoHome() { Begin(homePos, homeRot); current = null; CurrentLabel = null; } void Begin(Vector3 pos, Quaternion rot) { fromPos = transform.position; fromRot = transform.rotation; toPos = pos; toRot = rot; t = 0f; } void OnGUI() { var style = new GUIStyle(GUI.skin.label) { fontSize = 15 }; style.normal.textColor = new Color(1f, 1f, 1f, 0.85f); if (current != null && !CaptureKeys && GUI.Button(new Rect(14, 40, 90, 30), "Back")) GoHome(); string msg = current != null ? "Right click, Esc or scroll out to go back" : hoverClick != null ? hoverClick.Hint : hover != null ? hover.label : "Click the tank or the computer to take a closer look"; GUI.Label(new Rect(14, 10, 800, 26), msg, style); } }