using UnityEngine; using UnityEngine.InputSystem; namespace MedievalShopkeeper { /// /// Static Top-Down Camera for Medieval Shopkeeper. /// Positions the camera statically above the shop floor with a customizable height and pitch angle. /// Does not follow the player, giving a fixed overview of the shop. /// [ExecuteAlways] [RequireComponent(typeof(Camera))] public class TopDownCamera : MonoBehaviour { [Header("View Settings")] [Tooltip("World position the camera looks down at (e.g. center of the shop).")] [SerializeField] private Vector3 focusPoint = Vector3.zero; [Tooltip("Height of the camera above the shop floor.")] [Range(5f, 50f)] [SerializeField] private float cameraHeight = 16f; [Tooltip("Pitch angle (degrees): 90 = straight down (birds-eye), 55-65 = top-down angled/isometric.")] [Range(30f, 90f)] [SerializeField] private float pitchAngle = 60f; [Tooltip("Yaw angle (degrees) to rotate around the shop.")] [Range(-180f, 180f)] [SerializeField] private float yawAngle = 0f; [Header("Optional Zoom (PC Scroll Wheel / Pinch)")] [Tooltip("Allow zooming in/out while keeping the camera static over the shop.")] [SerializeField] private bool enableZoom = true; [SerializeField] private float zoomSpeed = 2f; [SerializeField] private float minHeight = 8f; [SerializeField] private float maxHeight = 30f; private void Start() { ApplyCameraTransform(); } private void LateUpdate() { #if UNITY_EDITOR if (!Application.isPlaying) { ApplyCameraTransform(); return; } #endif if (enableZoom) { HandleZoomInput(); } ApplyCameraTransform(); } private void HandleZoomInput() { float scroll = 0f; if (Mouse.current != null) { scroll = Mouse.current.scroll.ReadValue().y; } if (Mathf.Abs(scroll) > 0.01f) { cameraHeight -= Mathf.Sign(scroll) * zoomSpeed; cameraHeight = Mathf.Clamp(cameraHeight, minHeight, maxHeight); } } /// /// Positions and angles the camera so it statically frames the shop floor from above. /// [ContextMenu("Apply Camera Placement")] public void ApplyCameraTransform() { Quaternion rotation = Quaternion.Euler(pitchAngle, yawAngle, 0f); // Calculate distance backwards based on height and pitch float rad = Mathf.Clamp(pitchAngle, 10f, 90f) * Mathf.Deg2Rad; float distanceBack = pitchAngle >= 89.9f ? 0f : cameraHeight / Mathf.Tan(rad); Vector3 offset = Quaternion.Euler(0f, yawAngle, 0f) * new Vector3(0f, cameraHeight, -distanceBack); transform.position = focusPoint + offset; transform.rotation = rotation; } private void OnValidate() { ApplyCameraTransform(); } private void OnDrawGizmosSelected() { Gizmos.color = Color.green; Gizmos.DrawWireSphere(focusPoint, 0.5f); Gizmos.DrawLine(transform.position, focusPoint); } } }