TimeBaseController.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { _decorator, Component, Node, Label, Sprite, tween, Vec3 } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * 时间底座动画控制器,负责处理时间相关的动画效果
  5. */
  6. @ccclass('TimeBaseController')
  7. export class TimeBaseController extends Component {
  8. @property({
  9. type: Sprite,
  10. tooltip: '时间灯1'
  11. })
  12. timeLight1: Sprite = null;
  13. @property({
  14. type: Sprite,
  15. tooltip: '时间灯2'
  16. })
  17. timeLight2: Sprite = null;
  18. @property({
  19. type: Label,
  20. tooltip: '时间标签'
  21. })
  22. timeLabel: Label = null;
  23. // 倒计时总时间(秒)
  24. private totalTime: number = 150; // 2分30秒
  25. // 当前剩余时间(秒)
  26. private remainingTime: number = 150;
  27. // 上一分钟时间,用于检测分钟变化
  28. private lastMinute: number = -1;
  29. // 灯光闪烁间隔(秒)
  30. private urgentBlinkInterval: number = 0.5;
  31. // 当前是否在紧急状态(少于1分钟)
  32. private isUrgent: boolean = false;
  33. // 灯光交替显示计时器
  34. private blinkTimer: number = 0;
  35. // 当前激活的灯
  36. private activeLightIndex: number = 0;
  37. start() {
  38. // 初始化灯光状态
  39. this.resetLights();
  40. // 初始化时间显示
  41. this.updateTimeDisplay();
  42. }
  43. update(dt: number) {
  44. // 更新剩余时间
  45. this.remainingTime = Math.max(0, this.remainingTime - dt);
  46. // 更新时间显示
  47. this.updateTimeDisplay();
  48. // 计算分钟和秒
  49. const minutes = Math.floor(this.remainingTime / 60);
  50. const seconds = Math.floor(this.remainingTime % 60);
  51. // 检查是否进入紧急状态(剩余时间少于1分钟)
  52. const isCurrentlyUrgent = minutes < 1;
  53. // 状态变化时重置
  54. if (this.isUrgent !== isCurrentlyUrgent) {
  55. this.isUrgent = isCurrentlyUrgent;
  56. this.blinkTimer = 0;
  57. this.resetLights();
  58. }
  59. // 仅在紧急状态下处理灯光闪烁
  60. if (this.isUrgent) {
  61. this.handleLightBlink(dt);
  62. }
  63. // 检查分钟变化,触发标签动画
  64. if (minutes !== this.lastMinute) {
  65. this.lastMinute = minutes;
  66. this.playLabelPulseAnimation();
  67. }
  68. }
  69. /**
  70. * 更新时间显示
  71. */
  72. private updateTimeDisplay() {
  73. if (!this.timeLabel) return;
  74. // 计算分钟和秒
  75. const minutes = Math.floor(this.remainingTime / 60);
  76. const seconds = Math.floor(this.remainingTime % 60);
  77. // 格式化时间字符串 (mm:ss)
  78. const timeString = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
  79. // 更新标签文本
  80. this.timeLabel.string = timeString;
  81. }
  82. /**
  83. * 重置倒计时时间
  84. * @param time 设置的时间(秒)
  85. */
  86. public resetTime(time: number = 150) {
  87. this.totalTime = time;
  88. this.remainingTime = time;
  89. this.lastMinute = Math.floor(time / 60);
  90. this.updateTimeDisplay();
  91. // 重置状态
  92. this.isUrgent = Math.floor(time / 60) < 1;
  93. this.resetLights();
  94. }
  95. /**
  96. * 处理灯光闪烁逻辑
  97. */
  98. private handleLightBlink(dt: number) {
  99. // 更新计时器
  100. this.blinkTimer += dt;
  101. // 到达间隔时间则切换灯光
  102. if (this.blinkTimer >= this.urgentBlinkInterval) {
  103. this.blinkTimer = 0;
  104. this.switchLights();
  105. }
  106. }
  107. /**
  108. * 切换灯光显示
  109. */
  110. private switchLights() {
  111. // 紧急状态时交替闪烁两个灯
  112. this.activeLightIndex = 1 - this.activeLightIndex;
  113. if (this.timeLight1 && this.timeLight2) {
  114. this.timeLight1.node.active = this.activeLightIndex === 0;
  115. this.timeLight2.node.active = this.activeLightIndex === 1;
  116. }
  117. }
  118. /**
  119. * 重置灯光状态
  120. */
  121. private resetLights() {
  122. if (this.timeLight1 && this.timeLight2) {
  123. if (this.isUrgent) {
  124. // 紧急状态下初始只显示一个灯,准备交替闪烁
  125. this.timeLight1.node.active = true;
  126. this.timeLight2.node.active = false;
  127. this.activeLightIndex = 0;
  128. } else {
  129. // 非紧急状态下只显示第一个灯,不闪烁
  130. this.timeLight1.node.active = true;
  131. this.timeLight2.node.active = false;
  132. }
  133. }
  134. }
  135. /**
  136. * 播放标签脉冲动画(在整数分钟时触发)
  137. */
  138. private playLabelPulseAnimation() {
  139. if (!this.timeLabel) return;
  140. // 保存原始缩放
  141. const originalScale = this.timeLabel.node.scale.clone();
  142. const targetScale = new Vec3(originalScale.x * 1.3, originalScale.y * 1.3, originalScale.z);
  143. // 创建放大然后恢复的动画序列
  144. tween(this.timeLabel.node)
  145. .to(0.1, { scale: targetScale })
  146. .to(0.1, { scale: originalScale })
  147. // 添加轻微抖动
  148. .to(0.05, { position: new Vec3(5, 0, 0) })
  149. .to(0.05, { position: new Vec3(-5, 0, 0) })
  150. .to(0.05, { position: new Vec3(3, 0, 0) })
  151. .to(0.05, { position: new Vec3(-3, 0, 0) })
  152. .to(0.05, { position: new Vec3(0, 0, 0) })
  153. .start();
  154. }
  155. }