using System.Collections; using System.Collections.Generic; using Cysharp.Threading.Tasks; using Framework; using Gameplay; using Gameplay.Performance; using Gameplay.SubSystems; using PhxhSDK; using PhxhSDK.Res; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.SceneManagement; using Constants = Framework.Constants; /// /// 游戏场景的通用业务逻辑 /// public class GameSceneHelper : Singlenton { private Stack<(string, SceneHandle)> _uiViewSceneStack = new(); private RenderTexture _rTexture; private Stack<(string, SceneHandle)> _rtSceneStack = new (); /// /// 打开UI预览场景,当某个UI需要单独渲染场景时使用(如PVP布阵,营地等) /// 该函数会使得预览场景中的相机只渲染UI场景内的物件 /// 并处理了光照,全局GI,Volume,单一主相机 /// /// /// public async UniTask LoadSceneForUIView(string scenePath, LoadSceneMode loadSceneMode = LoadSceneMode.Additive) { // DebugUtil.Log($"加载UIView场景:{scenePath}"); SceneHandle sceneHandle = await GameSceneManager.Instance.LoadSceneAsync(scenePath, loadSceneMode); if (sceneHandle == null) return null; if (loadSceneMode == LoadSceneMode.Additive) { if (_uiViewSceneStack.Count > 0) { //如果之前加载过UIView场景,则使得上一个场景不影响当前场景 (string, SceneHandle) lastUIViewSceneData = _uiViewSceneStack.Peek(); SetSceneActiveForUIView(lastUIViewSceneData.Item2, false); } } else _uiViewSceneStack.Clear(); SetSceneActiveForUIView(sceneHandle, true); _uiViewSceneStack.Push((scenePath, sceneHandle)); return sceneHandle; } /// /// 卸载场景 /// /// public async UniTask UnloadSceneForUIView() { if (_uiViewSceneStack.Count == 0) { DebugUtil.LogError($"没有加载过UIView场景"); return; } (string, SceneHandle) sceneData = _uiViewSceneStack.Pop(); CameraManager.Instance.RevertMainCamera(); await GameSceneManager.Instance.UnLoadSceneAsync(sceneData.Item1); if (_uiViewSceneStack.Count > 0) { (string, SceneHandle) lastUIViewSceneData = _uiViewSceneStack.Peek(); SetSceneActiveForUIView(lastUIViewSceneData.Item2, true); } } /// /// 设置激活场景 /// /// /// public void SetSceneActiveForUIView(SceneHandle sceneHandle, bool isActive) { Scene scene = sceneHandle.Scene; if (!scene.IsValid()) return; int groundLayer = Constants.Layer.GROUND; int layerToSet = isActive ? Constants.Layer.UIVIEW : Constants.Layer.DEFAULT; int maskToSet = isActive ? LayerMask.GetMask(Constants.Layer.UIVIEW_NAME, Constants.Layer.GROUND_NAME) : LayerMask.GetMask(Constants.Layer.DEFAULT_NAME, Constants.Layer.GROUND_NAME); //调整所有物品的层级 GameObject[] roots = scene.GetRootGameObjects(); foreach (GameObject root in roots) { //将所有gameObject设置为UIView层 root.SetLayerEx(layerToSet, groundLayer); root.SetActive(isActive); } Volume volume = sceneHandle.GetSceneVolume(); if (volume != null) volume.enabled = isActive; if(CameraManager.Instance.TryGetSceneCamera(sceneHandle, out Camera sceneMainCamera)) { var additionalData = sceneMainCamera.GetUniversalAdditionalCameraData(); sceneMainCamera.cullingMask = maskToSet; //volume处理 additionalData.volumeLayerMask = maskToSet; } //设置光源culling mask var lights = Object.FindObjectsOfType(); foreach (var light in lights) { if (light.gameObject.scene != scene) continue; light.cullingMask = maskToSet; } if (isActive) { //切换全局GI SceneManager.SetActiveScene(scene); //切换主相机 CameraManager.Instance.SwitchMainCamera(sceneMainCamera); } } public RenderTexture GetRenderTexture() { if (!_rTexture) { _CreateRt(); } return _rTexture; } private void _CreateRt() { var rtFormat = PerformanceManager.instance.data.enableHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.ARGB32; _rTexture = RenderTexturePool.Instance.Create("GameSceneHelper_rt", PerformanceManager.instance.fullScreenWidth, PerformanceManager.instance.fullScreenHeight, RenderTexturePool.DEFAULT_DEPTH, rtFormat); } private void _ReleaseRt() { if (_rTexture) { RenderTexturePool.Instance.Destroy(_rTexture); _rTexture = null; } } /// /// 获取当前显示的场景 /// /// public SceneHandle GetCurrentUIViewScene() { if (_uiViewSceneStack.Count == 0) return null; return _uiViewSceneStack.Peek().Item2; } /// /// 切换当前显示的场景 /// /// /// /// public void ChangeSceneForUIView(string scenePath) { if (_uiViewSceneStack.Count <= 0) { DebugUtil.LogError("当前没有场景"); return; } Stack<(string, SceneHandle)> stackTemp = new(); SceneHandle curSceneHandle = null; // 要激活的场景 #region 校验当前场景是否是要切换的场景 (string, SceneHandle) lastUIViewScene = _uiViewSceneStack.Pop(); // 当前激活场景 if (lastUIViewScene.Item1.Equals(scenePath)) { DebugUtil.LogWarning($"已经激活该场景{scenePath}"); SetSceneActiveForUIView(lastUIViewScene.Item2, true); _uiViewSceneStack.Push(lastUIViewScene); return; } #endregion #region 遍历剩下的所有场景,获取要切换的场景,其余场景临时存起来 while (_uiViewSceneStack.Count > 0) { (string, SceneHandle) uiViewScene = _uiViewSceneStack.Pop(); if (uiViewScene.Item1.Equals(scenePath)) { curSceneHandle = uiViewScene.Item2; break; } else stackTemp.Push(uiViewScene); } #endregion #region 先把临时存的场景放回栈中 while (stackTemp.Count > 0) { _uiViewSceneStack.Push(stackTemp.Pop()); } #endregion _uiViewSceneStack.Push(lastUIViewScene); // 放入上次激活的场景 if (curSceneHandle != null) { _uiViewSceneStack.Push((scenePath, curSceneHandle)); SetSceneActiveForUIView(lastUIViewScene.Item2, false); SetSceneActiveForUIView(curSceneHandle, true); } else DebugUtil.LogError($"没有加载场景{scenePath}"); } public async UniTask LoadSceneForRt(string scenePath) { //var targetRt = CameraManager.Instance.MainCamera.targetTexture; SetSceneActiveByIndex(0, false); var sceneHandle = await GameSceneManager.Instance.LoadSceneAsync(scenePath, LoadSceneMode.Additive); if (sceneHandle == null) { return null; } var rTexture = GetRenderTexture(); if (CameraManager.Instance.TryGetSceneCamera(sceneHandle, out Camera sceneCamera)) sceneCamera.targetTexture = rTexture; _rtSceneStack.Push((scenePath, sceneHandle)); return sceneHandle; } public void SetSceneActiveByIndex(int index, bool isActive) { var scene = SceneManager.GetSceneAt(index); GameObject[] roots = scene.GetRootGameObjects(); foreach (GameObject root in roots) { //将所有gameObject设置为UIView层 //root.SetLayerEx(layerToSet, groundLayer); root.SetActive(isActive); } } public async UniTask UnLoadSceneForRt() { if (_rtSceneStack.Count > 0) { var item = _rtSceneStack.Pop(); await GameSceneManager.Instance.UnLoadSceneAsync(item.Item1); _ReleaseRt(); } } }