LoadingUI.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import { _decorator, Component, Label, Tween, tween, v3 } from "cc";
  2. import { Logger } from "./Logger";
  3. const { ccclass, property } = _decorator;
  4. /*初始化加载界面*/
  5. interface LoadingTask {
  6. progress: number;
  7. tips?: string;
  8. callback?: () => void | Promise<void>;
  9. }
  10. @ccclass("LoadingUI")
  11. export class LoadingUI extends Component {
  12. @property(Label)
  13. public progressLabel: Label = null!;
  14. @property(Label)
  15. public tipLabel: Label = null!;
  16. private _currentProgress = 0;
  17. private _isLoading = false;
  18. private _progressTween: Tween<any> | null = null;
  19. private _taskQueue: LoadingTask[] = [];
  20. private _currentTaskIndex = 0;
  21. /**
  22. * 开始加载流程
  23. * @param initialProgress 初始进度 (0-100)
  24. * @example 调用事例:
  25. * this.loadingUI.startLoading();
  26. //添加所有加载任务
  27. this.loadingUI.addTask(10, '资源加载中...', () => {
  28. PlayerData.ins().initialize();
  29. PlatformSystem.initialize();
  30. SettingData.ins().initialize();
  31. });
  32. this.loadingUI.addTask(30, '加载音乐资源...', async () => {
  33. await AudioManager.initialize();
  34. });
  35. this.loadingUI.addTask(40, '加载关卡数据...', async () => {
  36. await LevelsResData.ins().initialize();
  37. await LevelsResData.instance.preLoadAllMap();
  38. });
  39. this.loadingUI.addTask(20, '预加载场景...', async () => {
  40. await SceneManager.initialize();
  41. });
  42. //执行所有任务完成后会自动调用finishLoading()
  43. await this.loadingUI.executeTasks();
  44. */
  45. public startLoading(initialProgress: number = 0) {
  46. if (this._isLoading) {
  47. Logger.warn("Loading is already in progress");
  48. return;
  49. }
  50. this.node.active = true;
  51. this._isLoading = true;
  52. this._currentProgress = initialProgress;
  53. this._updateProgressDisplay(this._currentProgress);
  54. }
  55. /**
  56. * 添加一个加载任务
  57. * @param progress 该任务增加的进度值 (0-100)
  58. * @param tips 提示文本
  59. * @param callback 任务回调函数,可以是异步的
  60. */
  61. public addTask(progress: number, tips?: string, callback?: () => void | Promise<void>) {
  62. this._taskQueue.push({ progress, tips, callback });
  63. }
  64. /**
  65. * 执行所有加载任务
  66. */
  67. public async executeTasks() {
  68. if (!this._isLoading) {
  69. Logger.warn("Loading has not started yet");
  70. return;
  71. }
  72. for (this._currentTaskIndex = 0; this._currentTaskIndex < this._taskQueue.length; this._currentTaskIndex++) {
  73. const task = this._taskQueue[this._currentTaskIndex];
  74. //更新提示文本
  75. if (task.tips) {
  76. this.tipLabel.string = task.tips;
  77. }
  78. //执行任务回调
  79. if (task.callback) {
  80. try {
  81. const result = task.callback();
  82. if (result instanceof Promise) {
  83. await result;
  84. }
  85. } catch (error) {
  86. Logger.error("Loading task failed:", error);
  87. }
  88. }
  89. //更新进度
  90. await this._updateProgress(this._currentProgress + task.progress);
  91. }
  92. //所有任务完成后自动完成加载
  93. await this.finishLoading();
  94. }
  95. /**
  96. * 直接设置进度(带动画)
  97. * @param targetProgress 目标进度 (0-100)
  98. * @param duration 动画持续时间 (秒)
  99. */
  100. public async setProgress(targetProgress: number, duration: number = 0.3) {
  101. if(!this._isLoading) {
  102. Logger.warn("Loading has not started yet");
  103. return;
  104. }
  105. await this._updateProgress(targetProgress, duration);
  106. }
  107. /**
  108. * 完成加载(自动跳转到100%)
  109. */
  110. public async finishLoading(isHide: boolean = false) {
  111. if(!this._isLoading) {
  112. Logger.warn("Loading has not started yet");
  113. return;
  114. }
  115. await this._updateProgress(100, 0.5);
  116. this._isLoading = false;
  117. //延迟隐藏
  118. await new Promise(resolve => setTimeout(resolve, 500));
  119. if(isHide){this.node.active = false;}
  120. //重置状态
  121. this._reset();
  122. }
  123. private _reset() {
  124. this._currentProgress = 0;
  125. this._taskQueue = [];
  126. this._currentTaskIndex = 0;
  127. if (this._progressTween) {
  128. this._progressTween.stop();
  129. this._progressTween = null;
  130. }
  131. }
  132. private async _updateProgress(targetProgress: number, duration: number = 0.3) {
  133. //确保进度在0-100范围内
  134. targetProgress = Math.min(100, Math.max(0, targetProgress));
  135. // 如果不需要动画,直接设置
  136. if (duration <= 0) {
  137. this._currentProgress = targetProgress;
  138. this._updateProgressDisplay(this._currentProgress);
  139. return;
  140. }
  141. //使用Tween实现平滑过渡
  142. return new Promise<void>((resolve) => {
  143. if (this._progressTween) {
  144. this._progressTween.stop();
  145. }
  146. const startProgress = this._currentProgress;
  147. this._progressTween = tween({ progress: startProgress })
  148. .to(duration, { progress: targetProgress }, {
  149. onUpdate: (target) => {
  150. this._currentProgress = Math.floor(target.progress);
  151. this._updateProgressDisplay(this._currentProgress);
  152. },
  153. onComplete: () => {
  154. this._currentProgress = targetProgress;
  155. this._updateProgressDisplay(this._currentProgress);
  156. this._progressTween = null;
  157. resolve();
  158. }
  159. })
  160. .start();
  161. });
  162. }
  163. private _updateProgressDisplay(progress: number) {
  164. this.progressLabel.string = `${progress}%`;
  165. }
  166. }