using AppUI.Manager.View; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; namespace AppUI.Manager { /// /// AppUI UI 根节点:创建 Canvas、默认分组 "0",以及按需克隆出的上层分组(如 "1")。 /// 预制体与页面逻辑见 。 /// public class ViewMgr : MonoBehaviour { const string DefaultGroupName = "0"; static ViewMgr s_Instance; static bool s_SceneHookRegistered; public static ViewMgr Instance { get { if (s_Instance == null) { var go = new GameObject(nameof(ViewMgr)); s_Instance = go.AddComponent(); DontDestroyOnLoad(go); s_Instance.SetupRoot(); } return s_Instance; } } public static bool HasInstance() => s_Instance != null; /// /// 初始化 UI 根节点,并确保红外等上层分组 "1" 已创建(仅需在 Home 场景入口调用一次)。 /// public static void EnsureInitialized() { _ = Instance; EnsureGroup(1); } /// /// 获取或创建指定分组节点;groupIndex 为 0 时返回默认全屏分组。 /// public static Transform EnsureGroup(int groupIndex) { _ = Instance; string groupName = groupIndex.ToString(); Transform existing = Instance.transform.Find(groupName); if (existing) return existing; if (groupIndex == 0) { Instance.CreateDefaultGroup(); return Instance.transform.Find(DefaultGroupName); } Transform template = Instance.transform.Find(DefaultGroupName); if (!template) { Instance.CreateDefaultGroup(); template = Instance.transform.Find(DefaultGroupName); } return Instance.CreateGroupFromTemplate(template, groupIndex); } void OnDestroy() { if (s_SceneHookRegistered) { SceneManager.sceneUnloaded -= OnSceneUnloaded; s_SceneHookRegistered = false; } if (s_Instance == this) s_Instance = null; } static void EnsureSceneHook() { if (s_SceneHookRegistered) return; s_SceneHookRegistered = true; SceneManager.sceneUnloaded += OnSceneUnloaded; } static void OnSceneUnloaded(Scene scene) { ViewManager.HideAllView(); if (scene.name == "InfraredGameDouble" || scene.name == "WildAttackDouble") { InfraredDemo._ins?.SetSinglePoint(true); Debug.Log("OnSceneUnloaded 取消设置单点模式"); } } void SetupRoot() { gameObject.layer = LayerMask.NameToLayer("UI"); Canvas viewCanvas = gameObject.AddComponent(); viewCanvas.renderMode = RenderMode.ScreenSpaceOverlay; viewCanvas.sortingOrder = 1; CanvasScaler viewMgrCanvasScaler = gameObject.AddComponent(); viewMgrCanvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; viewMgrCanvasScaler.referenceResolution = new Vector2(2532, 1170); viewMgrCanvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; viewMgrCanvasScaler.matchWidthOrHeight = 0f; gameObject.AddComponent(); CreateDefaultGroup(); EnsureSceneHook(); } void CreateDefaultGroup() { if (transform.Find(DefaultGroupName)) return; var rectTransform = new GameObject(DefaultGroupName).AddComponent(); rectTransform.gameObject.layer = LayerMask.NameToLayer("UI"); rectTransform.SetParent(transform); rectTransform.localPosition = Vector3.zero; rectTransform.localScale = Vector3.one; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; } Transform CreateGroupFromTemplate(Transform template, int groupIndex) { string groupName = groupIndex.ToString(); var newObj = new GameObject(groupName); newObj.layer = LayerMask.NameToLayer("UI"); newObj.transform.SetParent(transform); newObj.transform.localPosition = template.localPosition; newObj.transform.localRotation = template.localRotation; newObj.transform.localScale = template.localScale; RectTransform rectTransform = newObj.AddComponent(); if (template is RectTransform templateRect) { rectTransform.anchorMin = templateRect.anchorMin; rectTransform.anchorMax = templateRect.anchorMax; rectTransform.offsetMin = templateRect.offsetMin; rectTransform.offsetMax = templateRect.offsetMax; } for (int i = 0; i < transform.childCount - 1; i++) { if (!int.TryParse(transform.GetChild(i).gameObject.name, out int siblingIndex)) continue; if (groupIndex < siblingIndex) { rectTransform.SetSiblingIndex(i); break; } } return rectTransform; } } }