using System.Collections.Generic; using System.Linq; using Unity.VisualScripting; using UnityEngine; using static Unity.Cinemachine.CinemachineTargetGroup; using static UnityEngine.GraphicsBuffer; public class CameraController : MonoBehaviour { public float camTargetRotation { get; private set; } = 0; public CameraControlMode CamControlMode { get; private set; } = CameraControlMode.SnapRotate; public Camera MainCamera; private bool isCamRotating = false; [Header("Free Cam Settings")] public float mouseSensitivity = 200f; public float minPitch = -30f; public float maxPitch = 60f; public float distance = 5f; public float heightOffset = -0.5f; public float followSpeed = 10f; public float maxDistance = 6f; public float minDistance = 1f; public float zoomSpeed = 5f; private float yaw; private float pitch; private float currentDistance; private float distanceVelocity; [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(); } } void Start() { Vector3 angles = 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) return; dougBody = GameManager.Instance.PlayerController.DougBody.transform; } 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); // 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); // Rotation Quaternion rotation = Quaternion.Euler(pitch, yaw, 0); // Desired Position Vector3 offset = rotation * Vector3.forward * -currentDistance; Vector3 desiredPosition = target + offset; // 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) return; dougBody = GameManager.Instance.PlayerController.DougBody.transform; } if (dougBody == null) 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 }