using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; namespace TyphoonUI { internal class UIManagerImpl : MonoBehaviour { private static readonly object _lock = new object(); private static UIManagerImpl _instance = null; public static UIManagerImpl Instance { get { if (_instance == null) { lock (_lock) { if (_instance == null) { var clone = new GameObject("UIManager"); _instance = clone.AddComponent(); _instance.Init(); } } } return _instance; } } //行为队列 public IOperationQueue OperationQueue; //UI相机 public UICamera UICamera; //EventSystem public EventSystem EventSystem; //画布字典 public Dictionary Canvases = new Dictionary(); //层级面板 public Dictionary> LayerPanels = new Dictionary>(); //UI面板 public Dictionary Panels = new Dictionary(); public AbstractBinding Binding; //UI资源包 public Dictionary UIPackages = new Dictionary(); //是否存在实例 public static bool HasInstance() => _instance != null; private void Init() { DontDestroyOnLoad(gameObject); //构建队列 var operationQueue = gameObject.AddComponent(); operationQueue.Initialize(); OperationQueue = operationQueue; //绑定UIBinding InitializeBinding(); //初始化画布 InitializeCanvas(); #if UNITY_EDITOR //添加监控类 gameObject.AddComponent(); #endif } /// /// 初始化绑定UI资源 /// private void InitializeBinding() { var type = GetType("TyphoonUI.UIBinding"); if (type == null) { throw new Exception("未找到TyphoonUI.UIBinding,请先执行TyphoonUI/安装,生成资源绑定类UIBinding.cs"); } Binding = Activator.CreateInstance(type) as AbstractBinding; Binding.Initialize(); } /// /// 初始化画布 /// private void InitializeCanvas() { var coreSource = CoreSource.Default; if (coreSource == null) { throw new Exception($"不存在画布资源,请从选项中导入预设..."); } if (coreSource.UICamera == null) { throw new Exception($"{coreSource} 未配置UICamera"); } if (coreSource.EventSystem == null) { throw new Exception($"{coreSource} 未配置EventSystem"); } UICamera = Instantiate(coreSource.UICamera).GetComponent(); if (UICamera == null) { throw new Exception($"{coreSource.UICamera}缺少UICamera组件"); } DontDestroyOnLoad(UICamera.gameObject); EventSystem = Instantiate(coreSource.EventSystem).GetComponent(); if (EventSystem == null) { throw new Exception($"{coreSource.EventSystem}缺少EventSystem组件"); } DontDestroyOnLoad(EventSystem.gameObject); //创建画布 foreach (var element in coreSource.Canvases) { var clone = Instantiate(element); clone.name = element.name; var canvas = clone.GetComponent(); canvas.Canvas.worldCamera = UICamera.Camera; if (canvas == null) { throw new Exception($"{element}缺少组件:UICanvas"); } DontDestroyOnLoad(clone); Canvases.Add(canvas.Layer, canvas); LayerPanels.Add(canvas.Layer, new HashSet()); } } /// /// 初始化 /// public void Initialize() { } /// /// 获取画布 /// public UICanvas GetCanvas(CanvasLayer layer) { return Canvases[layer]; } /// /// 获取资源 /// public GameObject GetSourcePrefab(string package, string sourceName) { if (!UIPackages.TryGetValue(package, out var match)) { throw new Exception($"未注入UIPackage:{package}"); } if (match.TryGet(sourceName, out var source)) { return source; } throw new Exception($"UIPackage不存在资源:{sourceName}"); } /// /// 注册面板到画布 /// public T CreatePanel() where T : UIPanel { var script = typeof(T).FullName; if (Panels.TryGetValue(script, out var match)) { //已经生成,直接返回 return match as T; } var (binding, layer) = Binding.GetPanelBinding(); var source = GetSourcePrefab(binding.Package, binding.SourceName); var canvas = GetCanvas(layer); var clone = Instantiate(source, canvas.Canvas.transform); clone.transform.localPosition = Vector3.zero; clone.transform.localEulerAngles = Vector3.zero; clone.transform.localScale = Vector3.one; var result = clone.AddComponent(); var view = clone.GetComponent(); if (view == null) { throw new Exception($"view为null,{binding.SourceName}资源根节点不存在UIObject"); } result.Attach(view); result.PanelScript = script; result.RootView.alpha = 0; result.RootView.blocksRaycasts = false; LayerPanels[layer].Add(script); Panels.Add(script, result); return result; } /// /// 实例化组件 /// public T CreateComponent() where T : UIComponent { var binding = Binding.GetComponentBinding(); var source = GetSourcePrefab(binding.Package, binding.SourceName); var clone = Instantiate(source); var result = clone.AddComponent(); var view = clone.GetComponent(); if (view == null) { throw new Exception($"view为null,{binding.SourceName}资源根节点不存在UIObject"); } result.Attach(view); return result; } /// /// 实例化组件 /// public static T CreateComponent(GameObject viewObjectRoot) where T : UIComponent { var view = viewObjectRoot.GetComponent(); var result = viewObjectRoot.AddComponent(); if (view == null) { throw new Exception($"{viewObjectRoot} 不存在 UIObject"); } result.Attach(view); return result; } /// /// 实例化组件 /// /// /// /// /// public T CreateComponent(Transform parent) where T : UIComponent { var binding = Binding.GetComponentBinding(); var source = GetSourcePrefab(binding.Package, binding.SourceName); var clone = Instantiate(source, parent); var result = clone.AddComponent(); var view = clone.GetComponent(); if (view == null) { throw new Exception($"view为null,{binding.SourceName}资源根节点不存在UIObject"); } result.Attach(view); return result; } /// /// 打开面板 /// public void OpenPanel(object data = null) where T : UIPanel { var panelName = typeof(T).FullName; //获取面板层级 var (binding, layer) = Binding.GetPanelBinding(); var canvas = GetCanvas(layer); switch (canvas.Mode) { case UICanvas.PanelMode.Single: //单页面模式 { //关闭该层画布的其它面板 var hash = LayerPanels[layer]; foreach (var element in hash) { if (element != panelName) { Panels[element].Close(); } } } break; } if (Panels.TryGetValue(panelName, out var match)) { match.Open(data); } else { CreatePanel().Open(data); } } /// /// 关闭面板 /// public void ClosePanel(object data = null) where T : UIPanel { var panelName = typeof(T).FullName; if (Panels.TryGetValue(panelName, out var match)) { match.Close(data); } } /// /// 关闭所有 /// public void CloseAll(CanvasLayer[] ignoreLayers = null, string[] panels = null) { var ignore = new HashSet(); if (ignoreLayers != null) { foreach (var layer in ignoreLayers) { var arr = LayerPanels[layer]; foreach (var element in arr) { ignore.Add(element); } } } if (panels != null) { foreach (var element in panels) { ignore.Add(element); } } foreach (var kv in Panels) { var key = kv.Key; var panel = kv.Value; if (!ignore.Contains(key)) { panel.Close(); } } } /// /// 获取面板 /// public T GetPanel() where T : UIPanel { var fullname = typeof(T).FullName; if (Panels.TryGetValue(fullname, out var match)) { return match as T; } return null; } /// /// 获取面板 /// public UIPanel GetPanel(string panelScript) { if (Panels.TryGetValue(panelScript, out var match)) { return match; } return null; } /// /// 是否存在面板 /// public bool HasPanel() where T : UIPanel { var fullname = typeof(T).FullName; return HasPanel(fullname); } /// /// 是否存在面板 /// public bool HasPanel(string panelScript) { return Panels.ContainsKey(panelScript); } /// /// 获取层级画布面板 /// public List GetCanvasPanels(CanvasLayer layer) { var result = new List(); if (LayerPanels.TryGetValue(layer, out var match)) { foreach (var fullname in match) { var panel = GetPanel(fullname); if (panel != null) { result.Add(panel); } } } return result; } /// /// 层级画布面板排序(按binding item优先级) /// public void SortCanvasPanelsInHierarchy(CanvasLayer canvasLayer) { var bindingItems = new List(); //获取顺序 var panels = GetCanvasPanels(canvasLayer); var panelOrders = new List(); foreach (var panel in panels) { var item = Binding.GetPanelBinding(panel.PanelScript); if (item != null) { panelOrders.Add(panel); bindingItems.Add(item); } } panelOrders.Sort((a, b) => { return a.transform.GetSiblingIndex().CompareTo(b.transform.GetSiblingIndex()); }); bindingItems.Sort((a, b) => { return a.Priority.CompareTo(b.Priority); }); var rebuild = false; for (int i = 0; i < panelOrders.Count && i < bindingItems.Count; i++) { if (panelOrders[i].PanelScript != bindingItems[i].Script) { rebuild = true; break; } } if (rebuild) { //更新层级排序 foreach (var element in panelOrders) { element.transform.SetAsLastSibling(); } } } /// /// 注入资源包 /// public void LoadPackage(UIPackage package) { var packageName = package.name; UIPackages[packageName] = package; } /// /// 卸载资源包 /// public void UnloadPackage(string packageName) { if (UIPackages.TryGetValue(packageName, out var match)) { UIPackages.Remove(packageName); Resources.UnloadAsset(match); } } /// /// 获取UIPackage /// public UIPackage GetPackage(string packageName) { if (UIPackages.TryGetValue(packageName, out var match)) { return match; } throw new Exception("未注入UIPackage:{packageName"); } /// /// 销毁面板 /// public bool DestroyPanel() where T : UIPanel { var panelScript = typeof(T).FullName; return DestroyPanel(panelScript); } /// /// 销毁面板 /// public bool DestroyPanel(string panelScript) { if (panelScript == null) { return false; } if (Panels.TryGetValue(panelScript, out var match)) { Destroy(match.gameObject); Panels.Remove(panelScript); foreach (var layer in LayerPanels) { layer.Value.Remove(panelScript); } return true; } return false; } /// /// 通知语言发生变化 /// public void NoticeLanguageChanged() { foreach (var kv in Panels) { var panel = kv.Value; panel.OnLanguageChanged(); } } /// /// 反射获取类型 /// private static Type GetType(string typeName) { Type type = null; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { type = assembly.GetType(typeName); if (type != null) break; } return type; } } }