hellbound/Assets/Scripts/Managers/Camera/CameraController.cs

199 lines
5.6 KiB
C#

using System;
using System.Collections;
using Cinemachine;
using UnityEngine;
public partial class CameraController : MonoBehaviour
{
public event Action OnCameraChanged;
public event Action OnCameraBlendEnded;
public Camera Main { get; private set; }
public CameraItem ActiveCamera { get; private set; }
[SerializeField] private CameraItem[] _cameras;
[SerializeField] private Camera _uiCamera;
private CinemachineBrain _brain;
private Camera[] _mainChildCameras;
private CinemachineTargetGroup _targetGroup;
public CameraTargetFollower TargetFollower { get; private set; }
private void Start()
{
CheckCameras();
Main = Camera.main;
if (Main != null)
{
_mainChildCameras = Main.gameObject.GetComponentsInChildren<Camera>();
_brain = Main.GetComponent<CinemachineBrain>();
}
else
throw new NullReferenceException("MainCamera is null");
InitSwitchCameras();
UI.Canvas.worldCamera = _uiCamera;
_brain.m_CameraActivatedEvent.AddListener(
(cam1, cam2) =>
{
OnCameraChanged?.Invoke();
StartCoroutine(InvokeCameraBlendEnded(_brain.ActiveBlend?.Duration ?? 0f));
});
TargetFollower = CameraTargetFollower.CreateTarget();
StartCoroutine(SetFollowTargetCycle(TargetFollower.transform));
StartCoroutine(SetLookAtTargetCycle(TargetFollower.transform));
if(_cameras.Length > 0)
SetActive(_cameras[0]);
}
private void Update()
{
if(_mainChildCameras.Length > 0)
foreach (Camera addCamera in _mainChildCameras)
{
addCamera.orthographic = Main.orthographic;
addCamera.orthographicSize = Main.orthographicSize;
addCamera.fieldOfView = Main.fieldOfView;
}
SwitchCamerasTick();
}
private IEnumerator InvokeCameraBlendEnded(float delay)
{
yield return new WaitForSecondsRealtime(delay);
OnCameraBlendEnded?.Invoke();
}
private void CheckCameras()
{
foreach (CameraItem cameraItem in _cameras)
{
if (cameraItem.camera == null)
throw new NullReferenceException();
}
}
private void DisableAllCameras()
{
foreach (CameraItem item in _cameras)
item.camera.gameObject.SetActive(false);
}
public void SetActive(CameraTypeEnum type)
{
DisableAllCameras();
CameraItem cameraItem = Array.Find(_cameras, item => item.type == type);
if (cameraItem == null)
throw new Exception($"Cant find camera with type {type}");
cameraItem.camera.gameObject.SetActive(true);
ActiveCamera = cameraItem;
}
public void SetActive(CameraItem cameraItem)
{
DisableAllCameras();
if (cameraItem == null)
throw new NullReferenceException();
cameraItem.camera.gameObject.SetActive(true);
ActiveCamera = cameraItem;
}
public void SetTarget(Transform target, bool instant = true)
{
TargetFollower.SetTarget(target, instant);
}
public void SetTarget(Transform[] targetsTransforms, CameraGroupTargetParameters[] parameters = null, bool instant = true)
{
_targetGroup = GetTargetGroup(targetsTransforms, parameters);
TargetFollower.SetTarget(_targetGroup.transform, instant);
}
private CinemachineTargetGroup GetTargetGroup(Transform[] targetsTransforms, CameraGroupTargetParameters[] parameters = null)
{
if (_targetGroup == null)
{
var go = new GameObject("TargetGroup");
_targetGroup = go.AddComponent<CinemachineTargetGroup>();
go.transform.SetParent(transform);
}
_targetGroup.m_Targets = new CinemachineTargetGroup.Target[targetsTransforms.Length];
if (parameters == null)
{
parameters = new CameraGroupTargetParameters[targetsTransforms.Length];
parameters.ForEach(() => new CameraGroupTargetParameters());
}
else if (parameters.Length < targetsTransforms.Length)
throw new Exception("Parameters array length less then elements count");
for (var i = 0; i < _targetGroup.m_Targets.Length; i++)
{
_targetGroup.m_Targets[i].target = targetsTransforms[i];
_targetGroup.m_Targets[i].weight = parameters[i].Weight;
_targetGroup.m_Targets[i].radius = parameters[i].Radius;
}
return _targetGroup;
}
private IEnumerator SetFollowTargetCycle(Transform target, bool reenable = true)
{
void SetFollow(CinemachineVirtualCamera cam)
{
cam.m_Follow = target;
if(reenable)
cam.enabled = true;
}
if(reenable)
{
foreach (CameraItem cam in _cameras)
cam.camera.enabled = false;
}
yield return null;
foreach (CameraItem cam in _cameras)
SetFollow(cam.camera);
}
private IEnumerator SetLookAtTargetCycle(Transform target, bool reenable = true)
{
void SetLookAt(CinemachineVirtualCamera cam)
{
cam.m_LookAt = target;
if(reenable)
cam.enabled = true;
}
if(reenable)
{
foreach (CameraItem cam in _cameras)
cam.camera.enabled = false;
}
yield return null;
foreach (CameraItem cam in _cameras)
SetLookAt(cam.camera);
}
}