using System; using System.Collections; using System.Collections.Generic; using AibisDream.Kit; 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 : SingletonBase { private const int LowPriority = 1; private const int HighPriority = 10; #region 相机组件 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 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, ICinemachineCamera virtualCamera) { if (!_virtualCameraDict.TryGetValue(camType, out var curCam)) return; if (virtualCamera == curCam) { _virtualCameraDict.Remove(camType); _camInitStateDict.Remove(camType); } } 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); } public float SwitchCameraSync(CameraEnum camType) { Debug.Log("Camera Type is:" + 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; // 设置虚拟相机优先级 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; } private void ResetVirCam(CameraEnum cameraEnum) { var virCam = _virtualCameraDict[cameraEnum]; var camState = _camInitStateDict[cameraEnum]; virCam.VirtualCameraGameObject.transform.localPosition = camState.pos; var camObj = virCam.VirtualCameraGameObject.GetComponent(); camObj.m_Lens.OrthographicSize = camState.initOrthoSize; } public 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; } /// /// /// /// 相机 /// /// public Tween TransCamera(float targetOrthographicSize, float duration) { // 寻找现在正在激活的相机 var curCamera = _orthoCameraBrain.ActiveVirtualCamera; return curCamera.DOOrthoSize(targetOrthographicSize, duration); } public Tween TransCamera(Vector3 targetPos, float duration) { // 寻找现在正在激活的相机 var curCamera = _orthoCameraBrain.ActiveVirtualCamera; return curCamera.DOLocalMove(targetPos, duration); } 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; } } 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 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 } }