Files
MedievalShopkeeper/Assets/Scripts/TopDownCamera.cs

108 lines
3.4 KiB
C#
Raw Permalink Normal View History

2026-09-03 16:35:05 +01:00
using UnityEngine;
using UnityEngine.InputSystem;
namespace MedievalShopkeeper
{
/// <summary>
/// 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.
/// </summary>
[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);
}
}
/// <summary>
/// Positions and angles the camera so it statically frames the shop floor from above.
/// </summary>
[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);
}
}
}