Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / ui / UiBase.cs
  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. /// <summary>
  44. /// 是否是嵌套的子 Ui
  45. /// </summary>
  46. public bool IsNestedUi => ParentUi != null;
  47. //开启的协程
  48. private List<CoroutineData> _coroutineList;
  49. //嵌套打开的Ui列表
  50. private HashSet<UiBase> _nestedUiSet;
  51. //嵌套模式下是否打开Ui
  52. private bool _nestedOpen;
  53. //当前Ui包含的 IUiNodeScript 接口, 关闭Ui是需要调用 IUiNodeScript.OnDestroy()
  54. private HashSet<IUiNodeScript> _nodeScripts;
  55.  
  56. public UiBase(string uiName)
  57. {
  58. UiName = uiName;
  59. //记录ui打开
  60. UiManager.RecordUi(this, UiManager.RecordType.Open);
  61. }
  62.  
  63. /// <summary>
  64. /// 创建当前ui时调用
  65. /// </summary>
  66. public virtual void OnCreateUi()
  67. {
  68. }
  69. /// <summary>
  70. /// 用于初始化打开的子Ui, 在 OnCreateUi() 之后调用
  71. /// </summary>
  72. public virtual void OnInitNestedUi()
  73. {
  74. }
  75.  
  76. /// <summary>
  77. /// 当前ui显示时调用
  78. /// </summary>
  79. public virtual void OnShowUi()
  80. {
  81. }
  82.  
  83. /// <summary>
  84. /// 当前ui隐藏时调用
  85. /// </summary>
  86. public virtual void OnHideUi()
  87. {
  88. }
  89.  
  90. /// <summary>
  91. /// 销毁当前ui时调用
  92. /// </summary>
  93. public virtual void OnDestroyUi()
  94. {
  95. }
  96.  
  97. /// <summary>
  98. /// 如果 Ui 处于打开状态, 则每帧调用一次
  99. /// </summary>
  100. public virtual void Process(float delta)
  101. {
  102. }
  103.  
  104. /// <summary>
  105. /// 显示ui
  106. /// </summary>
  107. public void ShowUi()
  108. {
  109. if (IsDestroyed)
  110. {
  111. Debug.LogError($"当前Ui: {UiName}已经被销毁!");
  112. return;
  113. }
  114. if (IsOpen)
  115. {
  116. return;
  117. }
  118.  
  119. _nestedOpen = true;
  120. IsOpen = true;
  121. Visible = true;
  122. OnShowUi();
  123. //子Ui调用显示
  124. if (_nestedUiSet != null)
  125. {
  126. foreach (var uiBase in _nestedUiSet)
  127. {
  128. if (uiBase._nestedOpen || uiBase.Visible)
  129. {
  130. uiBase.ShowUi();
  131. }
  132. }
  133. }
  134. }
  135. /// <summary>
  136. /// 隐藏ui, 不会执行销毁
  137. /// </summary>
  138. public void HideUi()
  139. {
  140. if (IsDestroyed)
  141. {
  142. Debug.LogError($"当前Ui: {UiName}已经被销毁!");
  143. return;
  144. }
  145. if (!IsOpen)
  146. {
  147. return;
  148. }
  149.  
  150. _nestedOpen = false;
  151. IsOpen = false;
  152. Visible = false;
  153. OnHideUi();
  154. //子Ui调用隐藏
  155. if (_nestedUiSet != null)
  156. {
  157. foreach (var uiBase in _nestedUiSet)
  158. {
  159. if (uiBase._nestedOpen)
  160. {
  161. uiBase.HideUi();
  162. uiBase._nestedOpen = true;
  163. }
  164. }
  165. }
  166. }
  167.  
  168. /// <summary>
  169. /// 关闭并销毁ui
  170. /// </summary>
  171. public void Destroy()
  172. {
  173. if (IsDestroyed)
  174. {
  175. return;
  176. }
  177. //记录ui关闭
  178. UiManager.RecordUi(this, UiManager.RecordType.Close);
  179. HideUi();
  180. IsDestroyed = true;
  181. OnDestroyUi();
  182. //子Ui调用销毁
  183. if (_nestedUiSet != null)
  184. {
  185. foreach (var uiBase in _nestedUiSet)
  186. {
  187. uiBase.ParentUi = null;
  188. uiBase.Destroy();
  189. }
  190. _nestedUiSet.Clear();
  191. }
  192. //销毁 IUiNodeScript
  193. if (_nodeScripts != null)
  194. {
  195. foreach (var uiNodeScript in _nodeScripts)
  196. {
  197. uiNodeScript.OnDestroy();
  198. }
  199. }
  200.  
  201. //在父Ui中移除当前Ui
  202. if (ParentUi != null)
  203. {
  204. ParentUi.RecordNestedUi(this, null, UiManager.RecordType.Close);
  205. }
  206. QueueFree();
  207. }
  208.  
  209. public sealed override void _Process(double delta)
  210. {
  211. if (!IsOpen)
  212. {
  213. return;
  214. }
  215. var newDelta = (float)delta;
  216. Process(newDelta);
  217. //协程更新
  218. ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, newDelta);
  219. }
  220.  
  221. /// <summary>
  222. /// 嵌套打开子ui
  223. /// </summary>
  224. public UiBase OpenNestedUi(string uiName, UiBase prevUi = null)
  225. {
  226. var packedScene = ResourceManager.Load<PackedScene>("res://" + GameConfig.UiPrefabDir + uiName + ".tscn");
  227. var uiBase = packedScene.Instantiate<UiBase>();
  228. uiBase.Visible = false;
  229. uiBase.PrevUi = prevUi;
  230. AddChild(uiBase);
  231. RecordNestedUi(uiBase, null, UiManager.RecordType.Open);
  232. uiBase.OnCreateUi();
  233. uiBase.OnInitNestedUi();
  234. if (IsOpen)
  235. {
  236. uiBase.ShowUi();
  237. }
  238. return uiBase;
  239. }
  240.  
  241. /// <summary>
  242. /// 嵌套打开子ui
  243. /// </summary>
  244. public T OpenNestedUi<T>(string uiName, UiBase prevUi = null) where T : UiBase
  245. {
  246. return (T)OpenNestedUi(uiName, prevUi);
  247. }
  248.  
  249. /// <summary>
  250. /// 记录嵌套打开/关闭的UI
  251. /// </summary>
  252. public void RecordNestedUi(UiBase uiBase, IUiNode node, UiManager.RecordType type)
  253. {
  254. if (type == UiManager.RecordType.Open)
  255. {
  256. if (uiBase.ParentUi != null && uiBase.ParentUi != this)
  257. {
  258. Debug.LogError($"子Ui:'{uiBase.UiName}'已经被其他Ui:'{uiBase.ParentUi.UiName}'嵌套打开!");
  259. uiBase.ParentUi.RecordNestedUi(uiBase, node, UiManager.RecordType.Close);
  260. }
  261. if (_nestedUiSet == null)
  262. {
  263. _nestedUiSet = new HashSet<UiBase>();
  264. }
  265.  
  266. uiBase.ParentUi = this;
  267. uiBase.ParentNode = node;
  268. _nestedUiSet.Add(uiBase);
  269. }
  270. else
  271. {
  272. if (uiBase.ParentUi == this)
  273. {
  274. uiBase.ParentUi = null;
  275. uiBase.ParentNode = null;
  276. }
  277. else
  278. {
  279. Debug.LogError($"当前Ui:'{UiName}'没有嵌套打开子Ui:'{uiBase.UiName}'!");
  280. return;
  281. }
  282. if (_nestedUiSet == null)
  283. {
  284. return;
  285. }
  286. _nestedUiSet.Remove(uiBase);
  287. }
  288. }
  289.  
  290. /// <summary>
  291. /// 记录当前Ui包含的 IUiNodeScript 接口
  292. /// </summary>
  293. public void RecordUiNodeScript(IUiNodeScript nodeScript)
  294. {
  295. if (_nodeScripts == null)
  296. {
  297. _nodeScripts = new HashSet<IUiNodeScript>();
  298. }
  299. _nodeScripts.Add(nodeScript);
  300. }
  301.  
  302. /// <summary>
  303. /// 打开下一级Ui, 当前Ui会被隐藏
  304. /// </summary>
  305. /// <param name="uiName">下一级Ui的名称</param>
  306. public UiBase OpenNextUi(string uiName)
  307. {
  308. UiBase uiBase;
  309. if (ParentUi != null) //说明当前Ui是嵌套Ui
  310. {
  311. if (ParentNode != null) //子层级打开
  312. {
  313. uiBase = ParentNode.OpenNestedUi(uiName, this);
  314. }
  315. else
  316. {
  317. uiBase = ParentUi.OpenNestedUi(uiName, this);
  318. }
  319. }
  320. else //正常打开
  321. {
  322. uiBase = UiManager.OpenUi(uiName, this);
  323. }
  324. HideUi();
  325. return uiBase;
  326. }
  327. /// <summary>
  328. /// 打开下一级Ui, 当前Ui会被隐藏
  329. /// </summary>
  330. /// <param name="uiName">下一级Ui的名称</param>
  331. public T OpenNextUi<T>(string uiName) where T : UiBase
  332. {
  333. return (T)OpenNextUi(uiName);
  334. }
  335.  
  336. /// <summary>
  337. /// 返回上一级Ui, 当前Ui会被销毁
  338. /// </summary>
  339. public void OpenPrevUi()
  340. {
  341. Destroy();
  342. if (PrevUi == null)
  343. {
  344. Debug.LogError($"Ui: {UiName} 没有记录上一级Ui!");
  345. }
  346. else
  347. {
  348. PrevUi.ShowUi();
  349. }
  350. }
  351.  
  352. public long StartCoroutine(IEnumerator able)
  353. {
  354. return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
  355. }
  356. public void StopCoroutine(long coroutineId)
  357. {
  358. ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
  359. }
  360. public bool IsCoroutineOver(long coroutineId)
  361. {
  362. return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId);
  363. }
  364. public void StopAllCoroutine()
  365. {
  366. ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
  367. }
  368. }