摄像机区域的优化
This commit is contained in:
@@ -8,8 +8,17 @@ namespace BaseGames.Core.Assets
|
||||
public static class AddressKeys
|
||||
{
|
||||
// ── Scenes ──────────────────────────────────────────────────────
|
||||
public const string ScenePersistent = "Scene_Persistent";
|
||||
public const string SceneMainMenu = "Scene_MainMenu";
|
||||
/// <summary>Addressable key,用于 Addressables.LoadSceneAsync。</summary>
|
||||
public const string ScenePersistent = "Scene_Persistent";
|
||||
|
||||
/// <summary>
|
||||
/// Unity 场景名(与文件名一致),用于 SceneManager.LoadScene 和 GameBootstrap。
|
||||
/// 与 <see cref="ScenePersistent"/> 值相同,显式声明以区分两种使用场景。
|
||||
/// </summary>
|
||||
public const string ScenePersistentName = "Scene_Persistent";
|
||||
|
||||
/// <summary>Addressable key,用于 Addressables.LoadSceneAsync。</summary>
|
||||
public const string SceneMainMenu = "Scene_MainMenu";
|
||||
|
||||
// ── Player ──────────────────────────────────────────────────────
|
||||
public const string PrefabPlayer = "PLY_Player";
|
||||
|
||||
62
Assets/_Game/Scripts/Core/GameBootstrap.cs
Normal file
62
Assets/_Game/Scripts/Core/GameBootstrap.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using BaseGames.Core.Assets;
|
||||
|
||||
namespace BaseGames.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行时引导器:在任意场景进入 Play Mode 时,自动保证 Persistent 场景先于起始场景加载。
|
||||
///
|
||||
/// 解决的核心问题:
|
||||
/// 开发者从任意房间场景直接按 Play,GameManager / SceneService 等全局服务不存在。
|
||||
///
|
||||
/// 工作时机(BeforeSceneLoad):
|
||||
/// 此回调在 Unity 加载第一个场景的资产之前触发。
|
||||
/// 在这里调用 SceneManager.LoadScene(Additive) 会将 Persistent 场景加入加载队列,
|
||||
/// 使其 Awake(DefaultExecutionOrder -2000)早于起始场景的 Awake 执行,
|
||||
/// 所有服务在起始场景的第一个 Awake 之前已完成注册。
|
||||
///
|
||||
/// 前提:
|
||||
/// Scene_Persistent 必须已添加到 Build Settings(不需要是 Index 0)。
|
||||
/// Persistent 不应作为自动加载的 scene 0,避免与本脚本冲突导致双重加载。
|
||||
/// 推荐:将 Main Menu 场景作为 Build Index 0;Persistent 作为任意非 0 索引保留。
|
||||
///
|
||||
/// 编辑器 Edit Mode 的便利性由 PersistentSceneAutoLoader(Editor 程序集)负责,
|
||||
/// 本脚本只处理运行时(含发行版 Build)的加载保证。
|
||||
/// </summary>
|
||||
public static class GameBootstrap
|
||||
{
|
||||
// ── 防止同一 Domain 内重复引导 ────────────────────────────────────────
|
||||
// SubsystemRegistration 在每次 Domain Reload 时最早执行,用于重置静态状态。
|
||||
private static bool _bootstrapped;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ResetOnDomainReload() => _bootstrapped = false;
|
||||
|
||||
// ── 核心引导入口 ──────────────────────────────────────────────────────
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void EnsurePersistentLoaded()
|
||||
{
|
||||
if (_bootstrapped) return;
|
||||
_bootstrapped = true;
|
||||
|
||||
// 若 Persistent 已在 Hierarchy 中(例如从 Persistent 场景本身按 Play),跳过。
|
||||
// 注意:BeforeSceneLoad 时 sceneCount 通常为 0(尚未加载任何场景),
|
||||
// 此检查主要应对极少数场景管理器提前初始化的情况。
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
string name = SceneManager.GetSceneAt(i).name;
|
||||
if (name == AddressKeys.ScenePersistentName || name == "Persistent")
|
||||
return;
|
||||
}
|
||||
|
||||
// Additive 加载 Persistent(必须在 Build Settings 中注册)
|
||||
// 由于是 BeforeSceneLoad,此加载在起始场景资产加载前完成,
|
||||
// GameServiceRegistrar.Awake(-2000) 将早于起始场景所有 Awake 执行。
|
||||
#if UNITY_EDITOR
|
||||
Debug.Log("[GameBootstrap] 自动加载 Persistent 场景(BeforeSceneLoad)。");
|
||||
#endif
|
||||
SceneManager.LoadScene(AddressKeys.ScenePersistentName, LoadSceneMode.Additive);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Core/GameBootstrap.cs.meta
Normal file
11
Assets/_Game/Scripts/Core/GameBootstrap.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7713d082a2fb06b4096d6c5c41150606
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -8,10 +8,19 @@ namespace BaseGames.Core
|
||||
/// <summary>
|
||||
/// 在 Awake 时(最早执行)向 ServiceLocator 注册所有服务。
|
||||
/// 挂载在 Persistent 场景的根 GameObject 上。
|
||||
///
|
||||
/// 重复加载保护:GameBootstrap(BeforeSceneLoad)与 Persistent 同时存在于 Build Settings
|
||||
/// 时可能导致双重加载。_registered 静态标志确保注册逻辑只执行一次,
|
||||
/// 第二个实例的 GameObject 会被立即销毁。
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-2000)]
|
||||
public class GameServiceRegistrar : MonoBehaviour
|
||||
{
|
||||
// ── 重复加载保护(对应 GameBootstrap 的双重加载边界情况)────────────
|
||||
private static bool _registered;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ResetOnDomainReload() => _registered = false;
|
||||
[SerializeField] private DeathRespawnService _deathRespawnService;
|
||||
[SerializeField] private SceneService _sceneService;
|
||||
[SerializeField] private EventChannelRegistry _eventChannelRegistry;
|
||||
@@ -26,6 +35,10 @@ namespace BaseGames.Core
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 重复加载保护:若已有实例完成注册,销毁本对象(Persistent 双重加载的边界情况)
|
||||
if (_registered) { Destroy(gameObject); return; }
|
||||
_registered = true;
|
||||
|
||||
// 若 Inspector 已绑定主 AudioListener,直接使用,跳过全场景扫描
|
||||
if (_primaryListener != null)
|
||||
DisableDuplicateListenersInCurrentScenes();
|
||||
|
||||
Reference in New Issue
Block a user