242 lines
6.7 KiB
C#
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
|
|
}
|