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 { 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 _virtualCameraDict = new(); private readonly Dictionary _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(); // 获取透视相机 // _perspectiveMainCamera = GameObject.Find("PerspectiveMainCamera")?.GetComponent(); // _perspectiveCameraBrain = _perspectiveMainCamera?.GetComponent(); _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().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 /// /// 检查当前是否需要切相机 /// /// /// 是就不用切相机 public bool EqualToCameraState(CameraEnum targetCameraState) { return _curCameraEnum == targetCameraState; } /// /// 切换相机 /// /// 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(); 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(); } /// /// 获取当前激活的相机 /// public Camera GetCurrentCamera() { // return _camInitStateDict.TryGetValue(_curCameraEnum, out var state) && state.isPerspective // ? _perspectiveMainCamera // : _orthoMainCamera; return _orthoMainCamera; } /// /// 获取鼠标在世界中的位置 /// /// 鼠标界面位置 /// 世界位置 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 DOLocalMove(this ICinemachineCamera camera, Vector3 targetPos, float duration) { var transform = camera.VirtualCameraGameObject.gameObject.transform; return transform.DOLocalMove(targetPos, duration); } public static TweenerCore DOOrthoSize(this ICinemachineCamera camera, float endValue, float duration) { var virtualCamera = camera.VirtualCameraGameObject.GetComponent(); 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(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, AnalysisMode, AnalysisModeDeep, BlockPuzzle, } }