- using System;
- using System.Collections;
- using System.Collections.Generic;
- using Godot;
-
- /// <summary>
- /// Ui 基类
- /// </summary>
- public abstract partial class UiBase : Control, IDestroy, ICoroutine
- {
- /// <summary>
- /// Ui显示事件
- /// </summary>
- public event Action OnShowUiEvent;
- /// <summary>
- /// Ui隐藏事件
- /// </summary>
- public event Action OnHideUiEvent;
- /// <summary>
- /// Ui销毁事件
- /// </summary>
- public event Action OnDestroyUiEvent;
-
- /// <summary>
- /// 当前 UI 所属层级
- /// </summary>
- [Export]
- public UiLayer Layer = UiLayer.Middle;
-
- /// <summary>
- /// ui名称
- /// </summary>
- public string UiName { get; }
-
- /// <summary>
- /// 是否已经打开ui
- /// </summary>
- public bool IsOpen { get; private set; } = false;
-
- public bool IsDestroyed { get; private set; }
-
- /// <summary>
- /// 负责记录上一个Ui
- /// </summary>
- public UiBase PrevUi { get; set; }
-
- /// <summary>
- /// 所属父级Ui, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
- /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
- /// </summary>
- public UiBase ParentUi { get; private set; }
-
- /// <summary>
- /// 所属父级节点, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
- /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
- /// </summary>
- public IUiNode ParentNode { get; private set; }
-
- /// <summary>
- /// 是否是嵌套的子 Ui
- /// </summary>
- public bool IsNestedUi => ParentUi != null;
-
- //开启的协程
- private List<CoroutineData> _coroutineList;
- //嵌套打开的Ui列表
- private HashSet<UiBase> _nestedUiSet;
- //嵌套模式下是否打开Ui
- private bool _nestedOpen;
- //当前Ui包含的 IUiNodeScript 接口, 关闭Ui是需要调用 IUiNodeScript.OnDestroy()
- private HashSet<IUiNodeScript> _nodeScripts;
- //存放事件集合的对象
- private EventFactory _eventFactory;
- //存放的IUiGrid对象
- private List<IUiGrid> _uiGrids;
-
- public UiBase(string uiName)
- {
- UiName = uiName;
- //记录ui打开
- UiManager.RecordUi(this, UiManager.RecordType.Open);
- }
-
- /// <summary>
- /// 创建当前ui时调用
- /// </summary>
- public virtual void OnCreateUi()
- {
- }
-
- /// <summary>
- /// 用于初始化打开的子Ui, 在 OnCreateUi() 之后调用
- /// </summary>
- public virtual void OnInitNestedUi()
- {
- }
-
- /// <summary>
- /// 当前ui显示时调用
- /// </summary>
- public virtual void OnShowUi()
- {
- }
-
- /// <summary>
- /// 当前ui隐藏时调用
- /// </summary>
- public virtual void OnHideUi()
- {
- }
-
- /// <summary>
- /// 销毁当前ui时调用
- /// </summary>
- public virtual void OnDestroyUi()
- {
- }
-
- /// <summary>
- /// 如果 Ui 处于打开状态, 则每帧调用一次
- /// </summary>
- public virtual void Process(float delta)
- {
- }
-
- /// <summary>
- /// 显示ui
- /// </summary>
- public void ShowUi()
- {
- if (IsDestroyed)
- {
- Debug.LogError($"当前Ui: {UiName}已经被销毁!");
- return;
- }
-
- Visible = true;
- if (IsOpen)
- {
- return;
- }
-
- _nestedOpen = true;
- IsOpen = true;
- OnShowUi();
- if (OnShowUiEvent != null)
- {
- OnShowUiEvent();
- }
-
- //子Ui调用显示
- if (_nestedUiSet != null)
- {
- foreach (var uiBase in _nestedUiSet)
- {
- if (uiBase._nestedOpen || uiBase.Visible)
- {
- uiBase.ShowUi();
- }
- }
- }
- }
-
- /// <summary>
- /// 隐藏ui, 不会执行销毁
- /// </summary>
- public void HideUi()
- {
- if (IsDestroyed)
- {
- Debug.LogError($"当前Ui: {UiName}已经被销毁!");
- return;
- }
-
- Visible = false;
- if (!IsOpen)
- {
- return;
- }
-
- _nestedOpen = false;
- IsOpen = false;
- OnHideUi();
- if (OnHideUiEvent != null)
- {
- OnHideUiEvent();
- }
-
- //子Ui调用隐藏
- if (_nestedUiSet != null)
- {
- foreach (var uiBase in _nestedUiSet)
- {
- if (uiBase._nestedOpen)
- {
- uiBase.HideUi();
- uiBase._nestedOpen = true;
- }
- }
- }
- }
-
- /// <summary>
- /// 关闭并销毁ui
- /// </summary>
- public void Destroy()
- {
- if (IsDestroyed)
- {
- return;
- }
- //记录ui关闭
- UiManager.RecordUi(this, UiManager.RecordType.Close);
- HideUi();
- IsDestroyed = true;
- OnDestroyUi();
- if (OnDestroyUiEvent != null)
- {
- OnDestroyUiEvent();
- }
-
- if (_uiGrids != null)
- {
- foreach (var uiGrid in _uiGrids)
- {
- uiGrid.Destroy();
- }
- _uiGrids.Clear();
- }
-
- //子Ui调用销毁
- if (_nestedUiSet != null)
- {
- foreach (var uiBase in _nestedUiSet)
- {
- uiBase.ParentUi = null;
- uiBase.Destroy();
- }
- _nestedUiSet.Clear();
- }
-
- //销毁 IUiNodeScript
- if (_nodeScripts != null)
- {
- foreach (var uiNodeScript in _nodeScripts)
- {
- uiNodeScript.OnDestroy();
- }
- }
-
- //在父Ui中移除当前Ui
- if (ParentUi != null)
- {
- ParentUi.RecordNestedUi(this, null, UiManager.RecordType.Close);
- }
-
- RemoveAllEventListener();
- QueueFree();
- }
-
- /// <summary>
- /// 添加监听事件, 所有事件会在当前 ui 销毁时自动销毁
- /// </summary>
- /// <param name="eventType">事件类型</param>
- /// <param name="callback">回调函数</param>
- public void AddEventListener(EventEnum eventType, Action<object> callback)
- {
- if (_eventFactory == null)
- {
- _eventFactory = new EventFactory();
- }
- _eventFactory.AddEventListener(eventType, callback);
- }
-
- /// <summary>
- /// 移除所有的监听事件
- /// </summary>
- public void RemoveAllEventListener()
- {
- if (_eventFactory != null)
- {
- _eventFactory.RemoveAllEventListener();
- }
- }
-
- /// <summary>
- /// 创建一个UiGrid对象, 该Ui对象会在Ui销毁时自动销毁
- /// </summary>
- /// <param name="template">模板对象</param>
- /// <typeparam name="TNode">模板对象类型</typeparam>
- /// <typeparam name="TData">存放的数据类型</typeparam>
- /// <typeparam name="TCell">Cell处理类</typeparam>
- public UiGrid<TNode, TData> CreateUiGrid<TNode, TData, TCell>(TNode template) where TNode : IUiCellNode where TCell : UiCell<TNode, TData>
- {
- var uiGrid = new UiGrid<TNode, TData>(template, typeof(TCell));
- if (_uiGrids == null)
- {
- _uiGrids = new List<IUiGrid>();
- }
- _uiGrids.Add(uiGrid);
- return uiGrid;
- }
-
- /// <summary>
- /// 创建一个UiGrid对象, 该Ui对象会在Ui销毁时自动销毁
- /// </summary>
- /// <param name="template">模板对象</param>
- /// <param name="parent">父节点</param>
- /// <typeparam name="TNode">模板对象类型</typeparam>
- /// <typeparam name="TData">存放的数据类型</typeparam>
- /// <typeparam name="TCell">Cell处理类</typeparam>
- public UiGrid<TNode, TData> CreateUiGrid<TNode, TData, TCell>(TNode template, Node parent) where TNode : IUiCellNode where TCell : UiCell<TNode, TData>
- {
- var uiGrid = new UiGrid<TNode, TData>(template, parent, typeof(TCell));
- if (_uiGrids == null)
- {
- _uiGrids = new List<IUiGrid>();
- }
- _uiGrids.Add(uiGrid);
- return uiGrid;
- }
-
- public sealed override void _Process(double delta)
- {
- if (!IsOpen)
- {
- return;
- }
- var newDelta = (float)delta;
- Process(newDelta);
-
- //协程更新
- ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, newDelta);
- }
-
- /// <summary>
- /// 嵌套打开子ui
- /// </summary>
- public UiBase OpenNestedUi(string uiName, UiBase prevUi = null)
- {
- var packedScene = ResourceManager.Load<PackedScene>("res://" + GameConfig.UiPrefabDir + uiName + ".tscn");
- var uiBase = packedScene.Instantiate<UiBase>();
- uiBase.Visible = false;
- uiBase.PrevUi = prevUi;
- AddChild(uiBase);
- RecordNestedUi(uiBase, null, UiManager.RecordType.Open);
-
- uiBase.OnCreateUi();
- uiBase.OnInitNestedUi();
- if (IsOpen)
- {
- uiBase.ShowUi();
- }
-
- return uiBase;
- }
-
- /// <summary>
- /// 嵌套打开子ui
- /// </summary>
- public T OpenNestedUi<T>(string uiName, UiBase prevUi = null) where T : UiBase
- {
- return (T)OpenNestedUi(uiName, prevUi);
- }
-
- /// <summary>
- /// 记录嵌套打开/关闭的UI
- /// </summary>
- public void RecordNestedUi(UiBase uiBase, IUiNode node, UiManager.RecordType type)
- {
- if (type == UiManager.RecordType.Open)
- {
- if (uiBase.ParentUi != null && uiBase.ParentUi != this)
- {
- Debug.LogError($"子Ui:'{uiBase.UiName}'已经被其他Ui:'{uiBase.ParentUi.UiName}'嵌套打开!");
- uiBase.ParentUi.RecordNestedUi(uiBase, node, UiManager.RecordType.Close);
- }
- if (_nestedUiSet == null)
- {
- _nestedUiSet = new HashSet<UiBase>();
- }
-
- uiBase.ParentUi = this;
- uiBase.ParentNode = node;
- _nestedUiSet.Add(uiBase);
- }
- else
- {
- if (uiBase.ParentUi == this)
- {
- uiBase.ParentUi = null;
- uiBase.ParentNode = null;
- }
- else
- {
- Debug.LogError($"当前Ui:'{UiName}'没有嵌套打开子Ui:'{uiBase.UiName}'!");
- return;
- }
-
- if (_nestedUiSet == null)
- {
- return;
- }
- _nestedUiSet.Remove(uiBase);
- }
- }
-
- /// <summary>
- /// 记录当前Ui包含的 IUiNodeScript 接口
- /// </summary>
- public void RecordUiNodeScript(IUiNodeScript nodeScript)
- {
- if (_nodeScripts == null)
- {
- _nodeScripts = new HashSet<IUiNodeScript>();
- }
- _nodeScripts.Add(nodeScript);
- }
-
- /// <summary>
- /// 打开下一级Ui, 当前Ui会被隐藏
- /// </summary>
- /// <param name="uiName">下一级Ui的名称</param>
- public UiBase OpenNextUi(string uiName)
- {
- UiBase uiBase;
- if (ParentUi != null) //说明当前Ui是嵌套Ui
- {
- if (ParentNode != null) //子层级打开
- {
- uiBase = ParentNode.OpenNestedUi(uiName, this);
- }
- else
- {
- uiBase = ParentUi.OpenNestedUi(uiName, this);
- }
- }
- else //正常打开
- {
- uiBase = UiManager.OpenUi(uiName, this);
- }
- HideUi();
- return uiBase;
- }
-
-
- /// <summary>
- /// 打开下一级Ui, 当前Ui会被隐藏
- /// </summary>
- /// <param name="uiName">下一级Ui的名称</param>
- public T OpenNextUi<T>(string uiName) where T : UiBase
- {
- return (T)OpenNextUi(uiName);
- }
-
- /// <summary>
- /// 返回上一级Ui, 当前Ui会被销毁
- /// </summary>
- public void OpenPrevUi()
- {
- Destroy();
- if (PrevUi == null)
- {
- Debug.LogError($"Ui: {UiName} 没有记录上一级Ui!");
- }
- else
- {
- PrevUi.ShowUi();
- }
- }
-
- public long StartCoroutine(IEnumerator able)
- {
- return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
- }
-
- public void StopCoroutine(long coroutineId)
- {
- ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
- }
-
- public bool IsCoroutineOver(long coroutineId)
- {
- return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
- }
-
- public void StopAllCoroutine()
- {
- ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
- }
- }