EscapeShooter/My project/Assets/Project Files/Modules/Camera Controller/Scripts/CameraController.cs

253 lines
7.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using UnityEngine;
namespace Watermelon
{
[DefaultExecutionOrder(100)]
public sealed class CameraController : MonoBehaviour, ISceneSavingReceiver
{
private static CameraController cameraController;
[SerializeField] CameraType firstCamera;
[Space]
[ReadOnly]
[SerializeField] VirtualCamera[] virtualCameras;
[Header("Blends")]
[SerializeField] List<CameraBlendSettings> blendSettings;
[UnpackNested]
[SerializeField] CameraBlendData defaultBlendData;
private static Transform cameraTransform;
private static Dictionary<CameraType, int> virtualCamerasLink;
private static Camera mainCamera;
public static Camera MainCamera => mainCamera;
private static VirtualCamera activeCamera;
public static VirtualCamera ActiveVirtualCamera => activeCamera;
private static bool isBlending;
public static bool IsBlending => isBlending;
private static CameraBlendCase currentBlendCase;
public void Init()
{
cameraController = this;
// Get camera component
mainCamera = GetComponent<Camera>();
cameraTransform = transform;
// Initialise cameras link
virtualCamerasLink = new Dictionary<CameraType, int>();
for (int i = 0; i < virtualCameras.Length; i++)
{
virtualCameras[i].Init();
virtualCamerasLink.Add(virtualCameras[i].CameraType, i);
}
VirtualCamera firstVirtualCamera = GetCamera(firstCamera);
firstVirtualCamera.Activate();
activeCamera = firstVirtualCamera;
UpdateCamera();
}
private static void UpdateCamera()
{
UpdateCamera(activeCamera.CameraData);
}
private static void UpdateCamera(CameraLocalData cameraData)
{
if (activeCamera.Target == null)
return;
mainCamera.fieldOfView = cameraData.FieldOfView;
mainCamera.nearClipPlane = cameraData.NearClipPlane;
mainCamera.farClipPlane = cameraData.FarClipPlane;
cameraTransform.SetPositionAndRotation(cameraData.Position, cameraData.Rotation);
}
private void LateUpdate()
{
if (activeCamera == null)
return;
// Update camera position
if (isBlending)
{
UpdateCamera(currentBlendCase.CameraData);
return;
}
UpdateCamera();
}
public static VirtualCamera GetCamera(CameraType cameraType)
{
return cameraController.virtualCameras[virtualCamerasLink[cameraType]];
}
private static CameraBlendData GetBlendData(CameraType firstCameraType, CameraType secondCameraType)
{
for (int i = 0; i < cameraController.blendSettings.Count; i++)
{
if (cameraController.blendSettings[i].FirstCameraType == firstCameraType && cameraController.blendSettings[i].SecondCameraType == secondCameraType)
{
return cameraController.blendSettings[i].BlendData;
}
}
return cameraController.defaultBlendData;
}
public static void EnableCamera(CameraType cameraTypeToEnable)
{
// if required camera is already active
if (activeCamera != null && activeCamera.CameraType == cameraTypeToEnable)
return;
// if required camera doesn't exist
VirtualCamera newCamera = GetCamera(cameraTypeToEnable);
if (newCamera == null)
{
Debug.LogError($"Camera of type {cameraTypeToEnable} not found.");
return;
}
// if there was no camera - instantly activate required
if (activeCamera == null)
{
activeCamera = newCamera;
activeCamera.Activate();
UpdateCamera();
return;
}
CameraType currentCameraType = activeCamera.CameraType;
// Get blend data
CameraBlendData blendData = GetBlendData(currentCameraType, cameraTypeToEnable);
// if blend time is zero - disable current camera and activate required
if (blendData.BlendTime <= 0)
{
activeCamera.Disable();
activeCamera = newCamera;
activeCamera.Activate();
UpdateCamera();
return;
}
isBlending = true;
newCamera.Activate();
// running blend
currentBlendCase = new CameraBlendCase(activeCamera, newCamera, blendData, () =>
{
activeCamera.Disable();
activeCamera = newCamera;
activeCamera.Activate();
isBlending = false;
});
}
public static void OverrideBlend(CameraType firstCameraType, CameraType secondCameraType, float newTime, Ease.Type easing)
{
if (cameraController.blendSettings.FindIndex(s => s.FirstCameraType == firstCameraType && s.SecondCameraType == secondCameraType) != -1)
{
CameraBlendData blendData = GetBlendData(firstCameraType, secondCameraType);
blendData.OverrideBlendTime(newTime);
}
else
{
CameraBlendSettings newBlend = new CameraBlendSettings(firstCameraType, secondCameraType, new CameraBlendData(newTime, easing));
cameraController.blendSettings.Add(newBlend);
}
}
public void OnSceneSaving()
{
#if UNITY_6000_0_OR_NEWER
#pragma warning disable CS0618
VirtualCamera[] cachedVirtualCameras = FindObjectsByType<VirtualCamera>(FindObjectsInactive.Include, FindObjectsSortMode.None);
#pragma warning restore CS0618
#else
VirtualCamera[] cachedVirtualCameras = FindObjectsOfType<VirtualCamera>(true);
#endif
if (!cachedVirtualCameras.SafeSequenceEqual(virtualCameras))
{
virtualCameras = cachedVirtualCameras;
RuntimeEditorUtils.SetDirty(this);
}
}
}
public class CameraBlendCase
{
public readonly VirtualCamera FirstCamera;
public readonly VirtualCamera SecondCamera;
private CameraBlendData cameraBlendData;
private Ease.IEasingFunction easingFunction;
private TweenCase tweenCase;
private CameraLocalData cameraData;
public CameraLocalData CameraData => cameraData;
public CameraBlendCase(VirtualCamera firstCamera, VirtualCamera secondCamera, CameraBlendData cameraBlendData, SimpleCallback completeCallback)
{
this.cameraBlendData = cameraBlendData;
FirstCamera = firstCamera;
SecondCamera = secondCamera;
firstCamera.StartTransition();
secondCamera.StartTransition();
cameraData = new CameraLocalData(firstCamera.CameraData);
easingFunction = Ease.GetFunction(cameraBlendData.BlendEaseType);
tweenCase = Tween.DoFloat(0f, 1.0f, cameraBlendData.BlendTime, (value) =>
{
cameraData.Lerp(firstCamera.CameraData, secondCamera.CameraData, value);
}).SetCustomEasing(easingFunction).OnComplete(() =>
{
FirstCamera.StopTransition();
SecondCamera.StopTransition();
completeCallback?.Invoke();
});
}
public void Clear()
{
tweenCase.KillActive();
}
}
}