NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/SubSystems/GameSceneHelper.cs

275 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
/// <summary>
/// 游戏场景的通用业务逻辑
/// </summary>
public class GameSceneHelper : Singlenton<GameSceneHelper>
{
private Stack<(string, SceneHandle)> _uiViewSceneStack = new();
private RenderTexture _rTexture;
private Stack<(string, SceneHandle)> _rtSceneStack = new ();
/// <summary>
/// 打开UI预览场景当某个UI需要单独渲染场景时使用(如PVP布阵营地等)
/// 该函数会使得预览场景中的相机只渲染UI场景内的物件
/// 并处理了光照全局GIVolume单一主相机
/// </summary>
/// <param name="scenePath"></param>
/// <returns></returns>
public async UniTask<SceneHandle> 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;
}
/// <summary>
/// 卸载场景
/// </summary>
/// <returns></returns>
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);
}
}
/// <summary>
/// 设置激活场景
/// </summary>
/// <param name="sceneHandle"></param>
/// <param name="isActive"></param>
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;
Camera sceneMainCamera = sceneHandle.SceneMainCamera;
if (sceneMainCamera != null)
{
var additionalData = sceneMainCamera.GetUniversalAdditionalCameraData();
sceneMainCamera.cullingMask = maskToSet;
//volume处理
additionalData.volumeLayerMask = maskToSet;
}
//设置光源culling mask
var lights = Object.FindObjectsOfType<Light>();
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;
}
}
/// <summary>
/// 获取当前显示的场景
/// </summary>
/// <returns></returns>
public SceneHandle GetCurrentUIViewScene()
{
if (_uiViewSceneStack.Count == 0)
return null;
return _uiViewSceneStack.Peek().Item2;
}
/// <summary>
/// 切换当前显示的场景
/// </summary>
/// <param name="scenePath"></param>
/// <param name="loadSceneMode"></param>
/// <returns></returns>
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}");
_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<SceneHandle> 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 sceneCamera = sceneHandle.SceneMainCamera;
var rTexture = GetRenderTexture();
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();
}
}
}