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