Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / ui / UiBase.cs
@小李xl 小李xl on 9 Aug 2023 7 KB 抽出IUiNode接口
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using Godot;
  4.  
  5. /// <summary>
  6. /// Ui 基类
  7. /// </summary>
  8. public abstract partial class UiBase : Control, IDestroy, ICoroutine
  9. {
  10. /// <summary>
  11. /// 当前 UI 所属层级
  12. /// </summary>
  13. [Export]
  14. public UiLayer Layer = UiLayer.Middle;
  15.  
  16. /// <summary>
  17. /// ui名称
  18. /// </summary>
  19. public string UiName { get; }
  20. /// <summary>
  21. /// 是否已经打开ui
  22. /// </summary>
  23. public bool IsOpen { get; private set; } = false;
  24.  
  25. public bool IsDestroyed { get; private set; }
  26.  
  27. /// <summary>
  28. /// 负责记录上一个Ui
  29. /// </summary>
  30. public UiBase PrevUi { get; set; }
  31.  
  32. /// <summary>
  33. /// 所属父级Ui, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
  34. /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
  35. /// </summary>
  36. public UiBase ParentUi { get; private set; }
  37. /// <summary>
  38. /// 所属父级节点, 仅当通过 UiNode.OpenNestedUi() 打开时才会赋值<br/>
  39. /// 注意: 如果是在预制体中放置的子 Ui, 那么子 Ui 的该属性会在 父 Ui 的 OnCreateUi() 之后赋值
  40. /// </summary>
  41. public IUiNode ParentNode { get; private set; }
  42.  
  43. //开启的协程
  44. private List<CoroutineData> _coroutineList;
  45. //嵌套打开的Ui列表
  46. private HashSet<UiBase> _nestedUiSet;
  47.  
  48. public UiBase(string uiName)
  49. {
  50. UiName = uiName;
  51. //记录ui打开
  52. UiManager.RecordUi(this, UiManager.RecordType.Open);
  53. }
  54.  
  55. /// <summary>
  56. /// 创建当前ui时调用
  57. /// </summary>
  58. public virtual void OnCreateUi()
  59. {
  60. }
  61. /// <summary>
  62. /// 用于初始化打开的子Ui, 在 OnCreateUi() 之后调用
  63. /// </summary>
  64. public virtual void OnInitNestedUi()
  65. {
  66. }
  67.  
  68. /// <summary>
  69. /// 当前ui显示时调用
  70. /// </summary>
  71. public virtual void OnShowUi()
  72. {
  73. }
  74.  
  75. /// <summary>
  76. /// 当前ui隐藏时调用
  77. /// </summary>
  78. public virtual void OnHideUi()
  79. {
  80. }
  81.  
  82. /// <summary>
  83. /// 销毁当前ui时调用
  84. /// </summary>
  85. public virtual void OnDestroyUi()
  86. {
  87. }
  88.  
  89. /// <summary>
  90. /// 每帧调用一次
  91. /// </summary>
  92. public virtual void Process(float delta)
  93. {
  94. }
  95.  
  96. /// <summary>
  97. /// 显示ui
  98. /// </summary>
  99. public void ShowUi()
  100. {
  101. if (IsOpen)
  102. {
  103. return;
  104. }
  105.  
  106. IsOpen = true;
  107. Visible = true;
  108. OnShowUi();
  109. //子Ui调用显示
  110. if (_nestedUiSet != null)
  111. {
  112. foreach (var uiBase in _nestedUiSet)
  113. {
  114. uiBase.ShowUi();
  115. }
  116. }
  117. }
  118. /// <summary>
  119. /// 隐藏ui, 不会执行销毁
  120. /// </summary>
  121. public void HideUi()
  122. {
  123. if (!IsOpen)
  124. {
  125. return;
  126. }
  127.  
  128. IsOpen = false;
  129. Visible = false;
  130. OnHideUi();
  131. //子Ui调用隐藏
  132. if (_nestedUiSet != null)
  133. {
  134. foreach (var uiBase in _nestedUiSet)
  135. {
  136. uiBase.HideUi();
  137. }
  138. }
  139. }
  140.  
  141. /// <summary>
  142. /// 关闭并销毁ui
  143. /// </summary>
  144. public void Destroy()
  145. {
  146. if (IsDestroyed)
  147. {
  148. return;
  149. }
  150. //记录ui关闭
  151. UiManager.RecordUi(this, UiManager.RecordType.Close);
  152. HideUi();
  153. IsDestroyed = true;
  154. OnDestroyUi();
  155. //子Ui调用销毁
  156. if (_nestedUiSet != null)
  157. {
  158. foreach (var uiBase in _nestedUiSet)
  159. {
  160. uiBase.ParentUi = null;
  161. uiBase.Destroy();
  162. }
  163. _nestedUiSet.Clear();
  164. }
  165.  
  166. //在父Ui中移除当前Ui
  167. if (ParentUi != null)
  168. {
  169. ParentUi.RecordNestedUi(this, null, UiManager.RecordType.Close);
  170. }
  171. QueueFree();
  172. }
  173.  
  174. public sealed override void _Process(double delta)
  175. {
  176. if (!IsOpen)
  177. {
  178. return;
  179. }
  180. var newDelta = (float)delta;
  181. Process(newDelta);
  182. //协程更新
  183. if (_coroutineList != null)
  184. {
  185. ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, newDelta);
  186. }
  187. }
  188.  
  189. /// <summary>
  190. /// 嵌套打开子ui
  191. /// </summary>
  192. public UiBase OpenNestedUi(string uiName, UiBase prevUi = null)
  193. {
  194. var packedScene = ResourceManager.Load<PackedScene>("res://" + GameConfig.UiPrefabDir + uiName + ".tscn");
  195. var uiBase = packedScene.Instantiate<UiBase>();
  196. uiBase.PrevUi = prevUi;
  197. AddChild(uiBase);
  198. RecordNestedUi(uiBase, null, UiManager.RecordType.Open);
  199. uiBase.OnCreateUi();
  200. uiBase.OnInitNestedUi();
  201. if (IsOpen)
  202. {
  203. uiBase.ShowUi();
  204. }
  205. return uiBase;
  206. }
  207.  
  208. /// <summary>
  209. /// 嵌套打开子ui
  210. /// </summary>
  211. public T OpenNestedUi<T>(string uiName, UiBase prevUi = null) where T : UiBase
  212. {
  213. return (T)OpenNestedUi(uiName, prevUi);
  214. }
  215.  
  216. /// <summary>
  217. /// 记录嵌套打开/关闭的UI
  218. /// </summary>
  219. public void RecordNestedUi(UiBase uiBase, IUiNode node, UiManager.RecordType type)
  220. {
  221. if (type == UiManager.RecordType.Open)
  222. {
  223. if (uiBase.ParentUi != null && uiBase.ParentUi != this)
  224. {
  225. GD.PrintErr($"子Ui:'{uiBase.UiName}'已经被其他Ui:'{uiBase.ParentUi.UiName}'嵌套打开!");
  226. uiBase.ParentUi.RecordNestedUi(uiBase, node, UiManager.RecordType.Close);
  227. }
  228. if (_nestedUiSet == null)
  229. {
  230. _nestedUiSet = new HashSet<UiBase>();
  231. }
  232.  
  233. uiBase.ParentUi = this;
  234. uiBase.ParentNode = node;
  235. _nestedUiSet.Add(uiBase);
  236. }
  237. else
  238. {
  239. if (uiBase.ParentUi == this)
  240. {
  241. uiBase.ParentUi = null;
  242. uiBase.ParentNode = null;
  243. }
  244. else
  245. {
  246. GD.PrintErr($"当前Ui:'{UiName}'没有嵌套打开子Ui:'{uiBase.UiName}'!");
  247. return;
  248. }
  249. if (_nestedUiSet == null)
  250. {
  251. return;
  252. }
  253. _nestedUiSet.Remove(uiBase);
  254. }
  255. }
  256.  
  257. /// <summary>
  258. /// 打开下一级Ui, 当前Ui会被隐藏
  259. /// </summary>
  260. /// <param name="uiName">下一级Ui的名称</param>
  261. public UiBase OpenNextUi(string uiName)
  262. {
  263. UiBase uiBase;
  264. if (ParentUi != null) //说明当前Ui是嵌套Ui
  265. {
  266. if (ParentNode != null) //子层级打开
  267. {
  268. uiBase = ParentNode.OpenNestedUi(uiName, this);
  269. }
  270. else
  271. {
  272. uiBase = ParentUi.OpenNestedUi(uiName, this);
  273. }
  274. }
  275. else //正常打开
  276. {
  277. uiBase = UiManager.OpenUi(uiName, this);
  278. }
  279. HideUi();
  280. return uiBase;
  281. }
  282. /// <summary>
  283. /// 打开下一级Ui, 当前Ui会被隐藏
  284. /// </summary>
  285. /// <param name="uiName">下一级Ui的名称</param>
  286. public T OpenNextUi<T>(string uiName) where T : UiBase
  287. {
  288. return (T)OpenNextUi(uiName);
  289. }
  290.  
  291. /// <summary>
  292. /// 返回上一级Ui, 当前Ui会被销毁
  293. /// </summary>
  294. public void OpenPrevUi()
  295. {
  296. Destroy();
  297. if (PrevUi == null)
  298. {
  299. GD.PrintErr($"Ui: {UiName} 没有记录上一级Ui!");
  300. }
  301. else
  302. {
  303. PrevUi.ShowUi();
  304. }
  305. }
  306.  
  307. public long StartCoroutine(IEnumerator able)
  308. {
  309. return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
  310. }
  311. public void StopCoroutine(long coroutineId)
  312. {
  313. ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
  314. }
  315. public void StopAllCoroutine()
  316. {
  317. ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
  318. }
  319. }