| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using Unity.Cinemachine;
- using Unity.VisualScripting;
- using UnityEngine;
- using UnityEngine.EventSystems;
- public class CinemachineCameraController : MonoBehaviour
- {
- public static CinemachineCameraController Instance { get; private set; }
- public CinemachineCamera actionCam;
- public GameObject groundPlane;
- [Header("Camera Controls")]
- public float minZoom = 15f;
- public float maxZoom = 200f;
- public float zoomSpeed = 10f;
- public float panSpeed = 30f;
- public float cameraAngle = 60f; // degrees
- private Vector3 framingPosition;
- private float framingHeight;
- private float framingDistance;
- private float zoomLevel;
- private Coroutine cameraMoveCoroutine;
- private Vector3 panOffset = Vector3.zero;
- private float yaw = 0f; // Add this field at the top with your other private fields
- private void Awake()
- {
- Instance = this;
- }
- private void Start()
- {
- FrameGroundPlane();
- }
- private void Update()
- {
- HandleCameraInput();
- }
- private void HandleCameraInput()
- {
- Rect gameArea = new Rect(0, 0, Screen.width, Screen.height);
- // Zoom
- if (Application.isFocused && !EventSystem.current.IsPointerOverGameObject() && gameArea.Contains(Input.mousePosition))
- {
- float scroll = Input.GetAxisRaw("Mouse ScrollWheel");
- if (Mathf.Abs(scroll) > 0.01f)
- {
- zoomLevel -= scroll * zoomSpeed;
- zoomLevel = Mathf.Clamp(zoomLevel, minZoom, maxZoom);
- FrameGroundPlane();
- }
- }
- // Pan (WASD or Arrow keys) - works even when paused
- Vector3 move = Vector3.zero;
- if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
- move.x -= 1f;
- if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
- move.x += 1f;
- if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
- move.z += 1f;
- if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
- move.z -= 1f;
- if (move != Vector3.zero)
- {
- panOffset += move.normalized * panSpeed * Time.unscaledDeltaTime;
- FrameGroundPlane();
- }
- // Rotate with middle mouse button
- if (Input.GetMouseButton(2))
- {
- float mouseX = Input.GetAxisRaw("Mouse X");
- yaw += mouseX * 3f;
- FrameGroundPlane();
- }
- }
- private void FrameGroundPlane()
- {
- if (groundPlane == null)
- {
- Debug.LogError("Ground plane is not assigned in CinemachineCameraController.");
- return;
- }
- // Use collider bounds to frame the ground plane
- Collider col = groundPlane.GetComponent<Collider>();
- if (col == null)
- {
- Debug.LogError("Ground plane does not have a collider to frame.");
- return;
- }
- Bounds bounds = col.bounds;
- Vector3 center = bounds.center + panOffset;
- float size = Mathf.Max(bounds.size.x, bounds.size.z);
- if (zoomLevel < 0.01f)
- {
- zoomLevel = size + 5f; // Ensure zoom level is not negative
- }
- float angleRadians = cameraAngle * Mathf.Deg2Rad;
- float y = Mathf.Sin(angleRadians) * zoomLevel;
- float z = -Mathf.Cos(angleRadians) * zoomLevel;
- Quaternion rotation = Quaternion.Euler(0, yaw, 0); // Apply yaw rotation
- Vector3 offset = rotation * new Vector3(0, y, z);
- framingPosition = center + offset;
- actionCam.transform.position = framingPosition;
- actionCam.transform.LookAt(center);
- actionCam.Follow = null;
- actionCam.LookAt = null;
- framingHeight = y;
- framingDistance = Mathf.Abs(z);
- }
- public void FocusOnCharacter(Transform character)
- {
- actionCam.Follow = character;
- actionCam.LookAt = character;
- }
- public void FollowTargetingLine(Vector3 mouseWorldPosition)
- {
- Vector3 target = new Vector3(mouseWorldPosition.x, 0, mouseWorldPosition.z) + panOffset;
- float angleRadians = cameraAngle * Mathf.Deg2Rad;
- float y = Mathf.Sin(angleRadians) * zoomLevel;
- float z = -Mathf.Cos(angleRadians) * zoomLevel;
- Vector3 camPos = target + new Vector3(0, y, z);
- actionCam.transform.position = camPos;
- actionCam.transform.LookAt(target);
- actionCam.Follow = null;
- actionCam.LookAt = null;
- }
- public void FrameAllCharacters(List<GameObject> characters)
- {
- if (characters == null || characters.Count == 0) return;
- Bounds bounds = new Bounds(characters[0].transform.position, Vector3.zero);
- foreach (var go in characters)
- bounds.Encapsulate(go.transform.position);
- Vector3 center = bounds.center + panOffset;
- float size = Mathf.Max(bounds.size.x, bounds.size.z);
- // Keep current zoomLevel, but allow zoom out if needed to fit all
- float requiredZoom = size + 5f;
- if (zoomLevel < requiredZoom)
- {
- zoomLevel = requiredZoom;
- }
- float angleRadians = cameraAngle * Mathf.Deg2Rad;
- float y = Mathf.Sin(angleRadians) * zoomLevel;
- float z = -Mathf.Cos(angleRadians) * zoomLevel;
- Vector3 camPos = center + new Vector3(0, y, z);
- // Start smooth movement
- if (cameraMoveCoroutine != null)
- StopCoroutine(cameraMoveCoroutine);
- cameraMoveCoroutine = StartCoroutine(SmoothMoveCamera(camPos, center, 0.7f));
- }
- private IEnumerator SmoothMoveCamera(Vector3 targetPosition, Vector3 lookAtTarget, float duration)
- {
- Vector3 startPos = actionCam.transform.position;
- Quaternion startRot = actionCam.transform.rotation;
- Quaternion endRot = Quaternion.LookRotation(lookAtTarget - targetPosition, Vector3.up);
- float elapsed = 0f;
- while (elapsed < duration)
- {
- float t = elapsed / duration;
- actionCam.transform.position = Vector3.Lerp(startPos, targetPosition, t);
- actionCam.transform.rotation = Quaternion.Slerp(startRot, endRot, t);
- elapsed += Time.deltaTime;
- yield return null;
- }
- actionCam.transform.position = targetPosition;
- actionCam.transform.rotation = endRot;
- actionCam.Follow = null;
- actionCam.LookAt = null;
- }
- }
|