using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEditor.Rendering; using UnityEngine; using UnityEngine.UIElements; using static Unity.Cinemachine.CinemachineTargetGroup; using static UnityEngine.GraphicsBuffer; public class CameraController : MonoBehaviour { [Header("Target")] [SerializeField] private Transform target; [SerializeField] private Vector3 targetOffset = new Vector3(0f, 1.5f, 0f); public Camera MainCamera; public Transform playerCamHome; [Header("Orbit")] [SerializeField] private float distance = 5f; [SerializeField] private float minDistance = 1f; [SerializeField] private float maxDistance = 8f; [SerializeField] private float rotationSpeed = 180f; [SerializeField] private float rotationOffset = 270f; [SerializeField] private float minPitch = -30f; [SerializeField] private float maxPitch = 75f; [Header("Zoom")] [SerializeField] private float zoomSpeed = 2f; [SerializeField] private float zoomSmoothness = 10f; [Header("Camera Collision")] [SerializeField] private LayerMask collisionLayers; [SerializeField] private float collisionRadius = 0.25f; [SerializeField] private float collisionOffset = 0.1f; [SerializeField] private float positionSmoothness = 15f; private float yaw; private float pitch = 20f; private float targetDistance; private Vector3 currentVelocity; public Vector3 Forward { get { Vector3 forward = MainCamera.transform.forward; forward.y = 0f; return forward.normalized; } } public Vector3 Right { get { Vector3 right = MainCamera.transform.right; right.y = 0f; return right.normalized; } } private void Start() { targetDistance = distance; Vector3 startingAngles = MainCamera.transform.eulerAngles; yaw = startingAngles.y + rotationOffset; pitch = startingAngles.x; if (pitch > 180f) { pitch -= 360f; } } private void LateUpdate() { if (target == null) { if (GameManager.Instance.PlayerController.DougBody != null) target = GameManager.Instance.PlayerController.DougBody.transform; else return; } HandleRotation(); HandleZoom(); UpdateCameraPosition(); } private void HandleRotation() { if (!Input.GetMouseButton(1)) { UnityEngine.Cursor.visible = true; UnityEngine.Cursor.lockState = CursorLockMode.None; return; } else { UnityEngine.Cursor.visible = false; UnityEngine.Cursor.lockState = CursorLockMode.Locked; } yaw += Input.GetAxis("Mouse X") * rotationSpeed * Time.deltaTime; pitch -= Input.GetAxis("Mouse Y") * rotationSpeed * Time.deltaTime; pitch = Mathf.Clamp(pitch, minPitch, maxPitch); } private void HandleZoom() { float scrollInput = Input.GetAxis("Mouse ScrollWheel"); targetDistance -= scrollInput * zoomSpeed; targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance); distance = Mathf.Lerp(distance, targetDistance, zoomSmoothness * Time.deltaTime); } private void UpdateCameraPosition() { Vector3 targetPosition = target.position + targetOffset; Quaternion orbitRotation = Quaternion.Euler(pitch, yaw, 0f); Vector3 desiredDirection = orbitRotation * Vector3.back; Vector3 desiredPosition = targetPosition + desiredDirection * distance; float correctedDistance = distance; if (Physics.SphereCast(targetPosition, collisionRadius, desiredDirection, out RaycastHit hit, distance, collisionLayers, QueryTriggerInteraction.Ignore)) { correctedDistance = Mathf.Max(minDistance, hit.distance - collisionOffset); } Vector3 finalPosition = targetPosition + desiredDirection * correctedDistance; MainCamera.transform.position = Vector3.SmoothDamp(MainCamera.transform.position, finalPosition, ref currentVelocity, 1f / positionSmoothness); MainCamera.transform.rotation = Quaternion.LookRotation(targetPosition - MainCamera.transform.position, Vector3.up); } /*public float camTargetRotation { get; private set; } = 0; public CameraControlMode CamControlMode { get; private set; } = CameraControlMode.SnapRotate; public Camera MainCamera; private bool isCamRotating = false; [Header("Rotation")] public float mouseSensitivity = 200f; public float minPitch = -30f; public float maxPitch = 60f; public float distance = 5f; private float yaw; private float pitch; [Header("Zoom")] public float followSpeed = 10f; public float maxDistance = 6f; public float minDistance = 1f; public float zoomSpeed = 5f; public float heightOffset = -0.5f; private float currentDistance; private float distanceVelocity; [Header("Collision")] public float collisionRadius = 0.3f; public float collisionOffset = 0.2f; public LayerMask collisionMask; [Header("Occlusion Settings")] public LayerMask obstructionMask; public float fadedAlpha = 0.25f; public float fadeSpeed = 5f; private Dictionary currentAlpha = new Dictionary(); private Dictionary targetAlpha = new Dictionary(); public Transform playerCamHome; Transform dougBody; private void Update() { UpdateOcclusion(); UpdateFade(); if (Input.GetMouseButton(1)) { HandleFreeCamRotation(); } else { CamAvoidCollisions(); } } void Start() { Vector3 angles = playerCamHome.transform.eulerAngles; yaw = angles.y; pitch = angles.x; currentDistance = distance; } /// /// Trigger cam rotation /// public void RotateCam() { if (!isCamRotating) { float currentY = playerCamHome.transform.rotation.eulerAngles.y; camTargetRotation = currentY + 90f; isCamRotating = true; } } /// /// Set cam rotation immediately /// void SnapToRotation(float rotation) { if (CamControlMode == CameraControlMode.SnapRotate) { playerCamHome.RotateAround( transform.position, Vector3.up, rotation ); camTargetRotation = rotation; } } /// /// Move cam to desired rotation (every frame) /// void HandleSnapCamRotation() { float currentY = playerCamHome.transform.rotation.eulerAngles.y; float step = 200 * Time.deltaTime; float newY = Mathf.MoveTowardsAngle(currentY, camTargetRotation, step); playerCamHome.RotateAround( transform.position, Vector3.up, newY - currentY ); if (Mathf.Abs(Mathf.DeltaAngle(newY, camTargetRotation)) < 0.01f) { isCamRotating = false; } } /// /// Move cam to desired free rotation (every frame) /// void HandleFreeCamRotation() { if (dougBody == null) { if (GameManager.Instance.PlayerController.DougBody != null) dougBody = GameManager.Instance.PlayerController.DougBody.transform; else return; } Vector3 target = new Vector3(dougBody.position.x, dougBody.position.y + heightOffset, dougBody.position.z); // Mouse Input float mouseX = Input.GetAxis("Mouse X"); float mouseY = Input.GetAxis("Mouse Y"); yaw += mouseX * mouseSensitivity * Time.deltaTime; pitch -= mouseY * mouseSensitivity * Time.deltaTime; pitch = Mathf.Clamp(pitch, minPitch, maxPitch); // Rotation Quaternion rotation = Quaternion.Euler(pitch, yaw, 0); // Zoom float scroll = Input.GetAxis("Mouse ScrollWheel"); if (Mathf.Abs(scroll) > 0.0001f) { distance -= scroll * zoomSpeed; distance = Mathf.Clamp(distance, minDistance, maxDistance); } currentDistance = Mathf.SmoothDamp( currentDistance, distance, ref distanceVelocity, 0.05f); float adjustedDistance = currentDistance; Vector3 desiredDirection = rotation * Vector3.back; // Camera obstruction handling if (Physics.SphereCast( target, collisionRadius, desiredDirection, out RaycastHit hit, currentDistance, collisionMask, QueryTriggerInteraction.Ignore)) { adjustedDistance = Mathf.Max( hit.distance - collisionOffset, minDistance); } // Desired Position Vector3 offset = rotation * Vector3.forward * -adjustedDistance; Vector3 desiredPosition = target + offset; if (desiredPosition.y < dougBody.position.y) { desiredPosition.y = dougBody.position.y; } // Smooth Follow playerCamHome.transform.position = Vector3.Lerp( playerCamHome.transform.position, desiredPosition, followSpeed * Time.deltaTime ); // Look at player playerCamHome.transform.LookAt(target + Vector3.up); } void CamAvoidCollisions() { if (dougBody == null) { if (GameManager.Instance.PlayerController.DougBody != null) dougBody = GameManager.Instance.PlayerController.DougBody.transform; else return; } Vector3 target = new Vector3(dougBody.position.x, dougBody.position.y + heightOffset, dougBody.position.z); Quaternion rotation = Quaternion.Euler(pitch, yaw, 0); Vector3 desiredDirection = rotation * Vector3.back; float adjustedDistance = currentDistance; if (Physics.SphereCast( target, collisionRadius, desiredDirection, out RaycastHit hit, currentDistance, collisionMask, QueryTriggerInteraction.Ignore)) { adjustedDistance = Mathf.Max( hit.distance - collisionOffset, minDistance); } // Desired Position Vector3 offset = rotation * Vector3.forward * -adjustedDistance; Vector3 desiredPosition = target + offset; if (desiredPosition.y < dougBody.position.y) { desiredPosition.y = dougBody.position.y; } // Smooth Follow playerCamHome.transform.position = Vector3.Lerp( playerCamHome.transform.position, desiredPosition, followSpeed * Time.deltaTime ); // Look at player playerCamHome.transform.LookAt(target + Vector3.up); } void UpdateOcclusion() { if (dougBody == null) { if (GameManager.Instance.PlayerController.DougBody != null) dougBody = GameManager.Instance.PlayerController.DougBody.transform; else return; } // Reset all renderers to visible foreach (Renderer r in new List(targetAlpha.Keys)) { targetAlpha[r] = 1f; } Vector3 dir = MainCamera.transform.position - dougBody.position; float dist = dir.magnitude; RaycastHit[] hits = Physics.RaycastAll( dougBody.position, dir.normalized, dist, obstructionMask, QueryTriggerInteraction.Ignore); foreach (RaycastHit hit in hits) { Renderer r = hit.collider.GetComponent(); if (r == null) continue; if (!currentAlpha.ContainsKey(r)) { currentAlpha[r] = 1f; targetAlpha[r] = 1f; } targetAlpha[r] = fadedAlpha; } } void UpdateFade() { List renderers = new List(currentAlpha.Keys); foreach (Renderer r in renderers) { float current = currentAlpha[r]; float target = targetAlpha[r]; current = Mathf.Lerp( current, target, Time.deltaTime * fadeSpeed); currentAlpha[r] = current; foreach (Material mat in r.materials) { Color c = mat.color; c.a = current; if (Mathf.Abs(current - targetAlpha[r]) < 0.05f) { c.a = targetAlpha[r]; } mat.color = c; } // Cleanup once fully restored if (Mathf.Abs(current - 1f) < 0.01f && Mathf.Abs(target - 1f) < 0.01f) { currentAlpha.Remove(r); targetAlpha.Remove(r); } } }*/ } public enum CameraControlMode { SnapRotate, FreeRotate }