Files
DougDiggem/Assets/Scripts/Management/CameraController.cs
T

242 lines
6.7 KiB
C#

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;
[Header("Occlusion Settings")]
[SerializeField] private LayerMask obstructionMask;
[SerializeField] private float fadedAlpha = 0.25f;
[SerializeField] private float fadeSpeed = 5f;
private Dictionary<Renderer, float> currentAlpha =
new Dictionary<Renderer, float>();
private Dictionary<Renderer, float> targetAlpha =
new Dictionary<Renderer, float>();
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;
}
UpdateOcclusion();
UpdateFade();
HandleRotation();
HandleZoom();
UpdateCameraPosition();
}
private void HandleRotation()
{
if (!Input.GetMouseButton(1))
{
UnityEngine.Cursor.visible = true;
UnityEngine.Cursor.lockState = CursorLockMode.None;
return;
}
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()
{
if (!Input.GetMouseButton(1))
{
return;
}
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);
}
void UpdateOcclusion()
{
// Reset all renderers to visible
foreach (Renderer r in new List<Renderer>(targetAlpha.Keys))
{
targetAlpha[r] = 1f;
}
Vector3 dir =
MainCamera.transform.position - target.position;
float dist = dir.magnitude;
RaycastHit[] hits = Physics.RaycastAll(
target.position,
dir.normalized,
dist,
obstructionMask,
QueryTriggerInteraction.Ignore);
foreach (RaycastHit hit in hits)
{
Renderer r = hit.collider.GetComponent<Renderer>();
if (r == null)
continue;
if (!currentAlpha.ContainsKey(r))
{
currentAlpha[r] = 1f;
targetAlpha[r] = 1f;
}
targetAlpha[r] = fadedAlpha;
}
}
void UpdateFade()
{
List<Renderer> renderers =
new List<Renderer>(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
}