Files
aibis-dream/Assets/Scripts/Framework/OtherKit/CameraKit.cs
T
2025-11-12 19:46:16 +08:00

426 lines
14 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using AibisDream.Kit;
using AibisDream.Utility;
using Cinemachine;
using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using Yarn.Unity;
namespace AibisDream.Framework
{
public class CameraKit : Singleton<CameraKit>
{
private const int LowPriority = 1;
private const int HighPriority = 10;
#region 相机组件
private static Camera _mainCam;
public static Camera UICamera => UIManager.Instance.UICamera;
private CinemachineBrain _orthoCameraBrain;
// private CinemachineBrain _perspectiveCameraBrain;
private readonly Dictionary<CameraEnum, ICinemachineCamera> _virtualCameraDict = new();
private readonly Dictionary<CameraEnum, CamState> _camInitStateDict = new();
private CameraEnum _curCameraEnum;
private CamState _curInitState;
private Camera _orthoMainCamera;
// private Camera _perspectiveMainCamera;
private struct CamState
{
public Vector3 pos;
public float initOrthoSize;
public bool isPerspective;
}
#endregion
private CameraKit()
{
}
public override void OnSingletonInit()
{
// 获取正交相机
_orthoMainCamera = Camera.main;
_orthoCameraBrain = _orthoMainCamera?.GetComponent<CinemachineBrain>();
// 获取透视相机
// _perspectiveMainCamera = GameObject.Find("PerspectiveMainCamera")?.GetComponent<Camera>();
// _perspectiveCameraBrain = _perspectiveMainCamera?.GetComponent<CinemachineBrain>();
_curCameraEnum = CameraEnum.Default;
// if (_orthoMainCamera && _perspectiveMainCamera)
// {
// // 默认激活正交相机,禁用透视相机
// _orthoMainCamera.gameObject.SetActive(true);
// _perspectiveMainCamera.gameObject.SetActive(false);
// }
}
#region 相机信息注册
public void UpdateCameraViewport(bool reset = false)
{
foreach (var overlayCam in _orthoMainCamera.GetUniversalAdditionalCameraData().cameraStack)
{
overlayCam.UpdateCameraViewport(reset);
}
_orthoMainCamera.UpdateCameraViewport(reset);
}
public void RegisterUICamera(Camera overlayCamera)
{
// 获取 Main Camera 的 UniversalAdditionalCameraData
var mainCameraData = _orthoMainCamera.GetUniversalAdditionalCameraData();
if (mainCameraData != null)
{
// 检查 Overlay Camera 是否已经在 Stack 中
if (!mainCameraData.cameraStack.Contains(overlayCamera))
{
overlayCamera.UpdateCameraViewport();
// 将 Overlay Camera 添加到 Stack
mainCameraData.cameraStack.Insert(0, overlayCamera);
Debug.Log("Overlay Camera added to Main Camera stack.");
}
}
else
{
Debug.LogError("Main Camera does not have UniversalAdditionalCameraData.");
}
}
public void UnRegisterUICamera(Camera overlayCamera)
{
// 获取 Main Camera 的 UniversalAdditionalCameraData
var mainCameraData = _orthoMainCamera.GetUniversalAdditionalCameraData();
if (mainCameraData != null)
{
// 检查 Overlay Camera 是否已经在 Stack 中
if (!mainCameraData.cameraStack.Contains(overlayCamera))
{
// 将 Overlay Camera 添加到 Stack
mainCameraData.cameraStack.Remove(overlayCamera);
Debug.Log("Overlay Camera added to Main Camera stack.");
}
}
else
{
Debug.LogError("Main Camera does not have UniversalAdditionalCameraData.");
}
}
public void RegisterCamera(CameraEnum camType, ICinemachineCamera virtualCamera, bool isPerspective = false)
{
_virtualCameraDict[camType] = virtualCamera;
var initState = new CamState
{
pos = virtualCamera.VirtualCameraGameObject.transform.localPosition,
initOrthoSize = virtualCamera.VirtualCameraGameObject.gameObject
.GetComponent<CinemachineVirtualCamera>().m_Lens.OrthographicSize,
isPerspective = isPerspective
};
_camInitStateDict[camType] = initState;
}
public void UnRegisterCamera(CameraEnum camType)
{
_virtualCameraDict.Remove(camType);
_camInitStateDict.Remove(camType);
}
public void RemoveAllCam()
{
_virtualCameraDict.Clear();
_camInitStateDict.Clear();
}
#endregion
/// <summary>
/// 检查当前是否需要切相机
/// </summary>
/// <param name="targetCameraState"></param>
/// <returns>是就不用切相机</returns>
public bool EqualToCameraState(CameraEnum targetCameraState)
{
return _curCameraEnum == targetCameraState;
}
/// <summary>
/// 切换相机
/// </summary>
/// <param name="camType"></param>
public IEnumerator SwitchCamera(CameraEnum camType)
{
var switchDuration = SwitchCameraSync(camType);
yield return new WaitForSeconds(switchDuration);
}
private float SwitchCameraSync(CameraEnum camType)
{
if (_curCameraEnum == camType)
{
return 0;
}
if (!_virtualCameraDict.ContainsKey(camType))
{
Debug.Log($"{camType.ToString()}相机未注册");
return 0;
}
// 切换主相机
bool isPerspective = _camInitStateDict[camType].isPerspective;
_orthoMainCamera.gameObject.SetActive(!isPerspective);
// _perspectiveMainCamera.gameObject.SetActive(isPerspective);
// var activeBrain = isPerspective ? _perspectiveCameraBrain : _orthoCameraBrain;
var activeBrain = _orthoCameraBrain;
// 设置虚拟相机优先级
foreach (var camPair in _virtualCameraDict)
{
if (camPair.Key == camType) camPair.Value.Priority = HighPriority;
if (camPair.Key != camType) camPair.Value.Priority = LowPriority;
}
_curInitState = _camInitStateDict[camType];
var lastCamEnum = _curCameraEnum;
_curCameraEnum = camType;
// 切完之后记得复原
ActionKit.Delay(activeBrain.m_DefaultBlend.BlendTime, () => ResetVirCam(lastCamEnum)).StartGlobal();
return activeBrain.m_DefaultBlend.BlendTime;
}
public void ResetCamera()
{
_curCameraEnum = CameraEnum.Default;
_camInitStateDict.Clear();
_camInitStateDict.Clear();
}
private void ResetVirCam(CameraEnum cameraEnum)
{
if (cameraEnum == CameraEnum.Default)
{
return;
}
if (!_virtualCameraDict.TryGetValue(cameraEnum, out var virCam))
{
return;
}
var camState = _camInitStateDict[cameraEnum];
virCam.VirtualCameraGameObject.transform.localPosition = camState.pos;
var camObj = virCam.VirtualCameraGameObject.GetComponent<CinemachineVirtualCamera>();
camObj.m_Lens.OrthographicSize = camState.initOrthoSize;
}
private Tween TransCamera(Vector3 targetPos, float targetOrthographicSize, float duration)
{
// 寻找现在正在激活的相机
var curCamera = _orthoCameraBrain.ActiveVirtualCamera;
var sq = DOTween.Sequence();
// 移动
sq.Join(curCamera.DOLocalMove(targetPos, duration));
// 缩放
sq.Join(curCamera.DOOrthoSize(targetOrthographicSize, duration));
return sq;
}
private Tween ReturnInitCamera(float duration)
{
return TransCamera(_curInitState.pos, _curInitState.initOrthoSize, duration);
}
public IEnumerator TransCameraAsync(Vector3 targetPos, float targetOrthographicSize, float duration)
{
yield return TransCamera(targetPos, targetOrthographicSize, duration).WaitForCompletion();
}
public IEnumerator ReturnInitCameraAsync(float duration)
{
yield return ReturnInitCamera(duration).WaitForCompletion();
}
// 方法已废弃,后面改成用Cinemachine的Shake
[Obsolete]
public IEnumerator ShakeCamera(float duration, float strength, int vibrate)
{
var curCamera = _orthoCameraBrain.ActiveVirtualCamera;
yield return curCamera.VirtualCameraGameObject.transform
.DOShakePosition(duration, strength, vibrate, 90, false, false)
.WaitForCompletion();
}
/// <summary>
/// 获取当前激活的相机
/// </summary>
public Camera GetCurrentCamera()
{
// return _camInitStateDict.TryGetValue(_curCameraEnum, out var state) && state.isPerspective
// ? _perspectiveMainCamera
// : _orthoMainCamera;
return _orthoMainCamera;
}
/// <summary>
/// 获取鼠标在世界中的位置
/// </summary>
/// <param name="mousePoint">鼠标界面位置</param>
/// <returns>世界位置</returns>
public static Vector3 GetMouseWorldPos(Vector3 mousePoint)
{
if (!_mainCam) _mainCam = Camera.main;
var pos = _mainCam.ScreenToWorldPoint(mousePoint);
return new Vector3(pos.x, pos.y, 0);
}
public static Vector3 GetScreenPos(Vector3 worldPos)
{
if (!_mainCam) _mainCam = Camera.main;
worldPos.z = 0;
return _mainCam.WorldToScreenPoint(worldPos);
}
}
public static class CinemachineExtension
{
public static TweenerCore<Vector3, Vector3, VectorOptions> DOLocalMove(this ICinemachineCamera camera,
Vector3 targetPos, float duration)
{
var transform = camera.VirtualCameraGameObject.gameObject.transform;
return transform.DOLocalMove(targetPos, duration);
}
public static TweenerCore<float, float, FloatOptions> DOOrthoSize(this ICinemachineCamera camera,
float endValue, float duration)
{
var virtualCamera = camera.VirtualCameraGameObject.GetComponent<CinemachineVirtualCamera>();
var currentOrthoSize = virtualCamera.m_Lens.OrthographicSize;
return DOTween.To(() => currentOrthoSize, x => currentOrthoSize = x, endValue, duration)
.OnUpdate(() => virtualCamera.m_Lens.OrthographicSize = currentOrthoSize);
}
public static void UpdateCameraViewport(this Camera camera, bool reset = false)
{
if (reset)
{
camera.rect = new Rect(0, 0, 1, 1);
return;
}
// 当前屏幕宽高比
float windowAspect = (float)Screen.width / (float)Screen.height;
// 计算缩放比例
float scaleHeight = windowAspect / ConstRef.TargetAspect;
Rect rect = camera.rect;
if (scaleHeight < 1.0f)
{
// 添加黑边
rect.width = 1.0f;
rect.height = scaleHeight;
rect.x = 0;
rect.y = (1.0f - scaleHeight) / 2.0f;
}
else
{
// 如果宽高比大于目标,则无需添加黑边
rect.width = 1.0f / scaleHeight;
rect.height = 1.0f;
rect.x = (1.0f - 1.0f / scaleHeight) / 2.0f;
rect.y = 0;
}
camera.rect = rect;
}
}
public static class CameraCommand
{
[YarnCommand("return_init_camera")]
public static IEnumerator ReturnInitCamera(float duration = 1f)
{
return CameraKit.Instance.ReturnInitCameraAsync(duration);
}
[YarnCommand("trans_camera")]
public static IEnumerator TransCameraAsync(float x, float y, float targetOrthographicSize, float duration)
{
Vector3 targetPos = new Vector3(x, y, -10);
return CameraKit.Instance.TransCameraAsync(targetPos, targetOrthographicSize, duration);
}
[YarnCommand("shake_camera")]
public static IEnumerator ShakeCamera(float duration, float strength, int vibrate = 10)
{
return CameraKit.Instance.ShakeCamera(duration, strength, vibrate);
}
[YarnCommand("switch_camera")]
public static IEnumerator SwitchCamera(string targetStateStr)
{
// 字符串转枚举
if (!Enum.TryParse<CameraEnum>(targetStateStr, out var targetState))
{
Debug.Log($"{targetStateStr}不在FixState枚举中");
yield break;
}
yield return CameraKit.Instance.SwitchCamera(targetState);
}
}
public enum CameraEnum
{
Default,
Clinic,
CoolingMachine,
BodyModule,
BodyModuleCenter,
Memory,
Logic,
Eye,
UF,
Expression,
Engine,
Gear,
EyeDeep,
ExpressionDeep,
Emo,
EmoDeep,
Op,
CutEmo,
CutMemory,
CutLogic,
CutEmoDeep,
CutMemoryDeep,
CutLogicDeep,
BreakCamera,
DreamCamera,
Subway,
SubwayTV,
Language,
LanguageDeep
}
}