|
@@ -0,0 +1,188 @@
|
|
|
+import { _decorator, Component, Node, Label, Sprite, tween, Vec3 } from 'cc';
|
|
|
+const { ccclass, property } = _decorator;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 时间底座动画控制器,负责处理时间相关的动画效果
|
|
|
+ */
|
|
|
+@ccclass('TimeBaseController')
|
|
|
+export class TimeBaseController extends Component {
|
|
|
+ @property({
|
|
|
+ type: Sprite,
|
|
|
+ tooltip: '时间灯1'
|
|
|
+ })
|
|
|
+ timeLight1: Sprite = null;
|
|
|
+
|
|
|
+ @property({
|
|
|
+ type: Sprite,
|
|
|
+ tooltip: '时间灯2'
|
|
|
+ })
|
|
|
+ timeLight2: Sprite = null;
|
|
|
+
|
|
|
+ @property({
|
|
|
+ type: Label,
|
|
|
+ tooltip: '时间标签'
|
|
|
+ })
|
|
|
+ timeLabel: Label = null;
|
|
|
+
|
|
|
+ // 倒计时总时间(秒)
|
|
|
+ private totalTime: number = 150; // 2分30秒
|
|
|
+
|
|
|
+ // 当前剩余时间(秒)
|
|
|
+ private remainingTime: number = 150;
|
|
|
+
|
|
|
+ // 上一分钟时间,用于检测分钟变化
|
|
|
+ private lastMinute: number = -1;
|
|
|
+
|
|
|
+ // 灯光闪烁间隔(秒)
|
|
|
+ private urgentBlinkInterval: number = 0.5;
|
|
|
+
|
|
|
+ // 当前是否在紧急状态(少于1分钟)
|
|
|
+ private isUrgent: boolean = false;
|
|
|
+
|
|
|
+ // 灯光交替显示计时器
|
|
|
+ private blinkTimer: number = 0;
|
|
|
+
|
|
|
+ // 当前激活的灯
|
|
|
+ private activeLightIndex: number = 0;
|
|
|
+
|
|
|
+ start() {
|
|
|
+ // 初始化灯光状态
|
|
|
+ this.resetLights();
|
|
|
+
|
|
|
+ // 初始化时间显示
|
|
|
+ this.updateTimeDisplay();
|
|
|
+ }
|
|
|
+
|
|
|
+ update(dt: number) {
|
|
|
+ // 更新剩余时间
|
|
|
+ this.remainingTime = Math.max(0, this.remainingTime - dt);
|
|
|
+
|
|
|
+ // 更新时间显示
|
|
|
+ this.updateTimeDisplay();
|
|
|
+
|
|
|
+ // 计算分钟和秒
|
|
|
+ const minutes = Math.floor(this.remainingTime / 60);
|
|
|
+ const seconds = Math.floor(this.remainingTime % 60);
|
|
|
+
|
|
|
+ // 检查是否进入紧急状态(剩余时间少于1分钟)
|
|
|
+ const isCurrentlyUrgent = minutes < 1;
|
|
|
+
|
|
|
+ // 状态变化时重置
|
|
|
+ if (this.isUrgent !== isCurrentlyUrgent) {
|
|
|
+ this.isUrgent = isCurrentlyUrgent;
|
|
|
+ this.blinkTimer = 0;
|
|
|
+ this.resetLights();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 仅在紧急状态下处理灯光闪烁
|
|
|
+ if (this.isUrgent) {
|
|
|
+ this.handleLightBlink(dt);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查分钟变化,触发标签动画
|
|
|
+ if (minutes !== this.lastMinute) {
|
|
|
+ this.lastMinute = minutes;
|
|
|
+ this.playLabelPulseAnimation();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新时间显示
|
|
|
+ */
|
|
|
+ private updateTimeDisplay() {
|
|
|
+ if (!this.timeLabel) return;
|
|
|
+
|
|
|
+ // 计算分钟和秒
|
|
|
+ const minutes = Math.floor(this.remainingTime / 60);
|
|
|
+ const seconds = Math.floor(this.remainingTime % 60);
|
|
|
+
|
|
|
+ // 格式化时间字符串 (mm:ss)
|
|
|
+ const timeString = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
|
|
+
|
|
|
+ // 更新标签文本
|
|
|
+ this.timeLabel.string = timeString;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重置倒计时时间
|
|
|
+ * @param time 设置的时间(秒)
|
|
|
+ */
|
|
|
+ public resetTime(time: number = 150) {
|
|
|
+ this.totalTime = time;
|
|
|
+ this.remainingTime = time;
|
|
|
+ this.lastMinute = Math.floor(time / 60);
|
|
|
+ this.updateTimeDisplay();
|
|
|
+
|
|
|
+ // 重置状态
|
|
|
+ this.isUrgent = Math.floor(time / 60) < 1;
|
|
|
+ this.resetLights();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理灯光闪烁逻辑
|
|
|
+ */
|
|
|
+ private handleLightBlink(dt: number) {
|
|
|
+ // 更新计时器
|
|
|
+ this.blinkTimer += dt;
|
|
|
+
|
|
|
+ // 到达间隔时间则切换灯光
|
|
|
+ if (this.blinkTimer >= this.urgentBlinkInterval) {
|
|
|
+ this.blinkTimer = 0;
|
|
|
+ this.switchLights();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 切换灯光显示
|
|
|
+ */
|
|
|
+ private switchLights() {
|
|
|
+ // 紧急状态时交替闪烁两个灯
|
|
|
+ this.activeLightIndex = 1 - this.activeLightIndex;
|
|
|
+
|
|
|
+ if (this.timeLight1 && this.timeLight2) {
|
|
|
+ this.timeLight1.node.active = this.activeLightIndex === 0;
|
|
|
+ this.timeLight2.node.active = this.activeLightIndex === 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重置灯光状态
|
|
|
+ */
|
|
|
+ private resetLights() {
|
|
|
+ if (this.timeLight1 && this.timeLight2) {
|
|
|
+ if (this.isUrgent) {
|
|
|
+ // 紧急状态下初始只显示一个灯,准备交替闪烁
|
|
|
+ this.timeLight1.node.active = true;
|
|
|
+ this.timeLight2.node.active = false;
|
|
|
+ this.activeLightIndex = 0;
|
|
|
+ } else {
|
|
|
+ // 非紧急状态下只显示第一个灯,不闪烁
|
|
|
+ this.timeLight1.node.active = true;
|
|
|
+ this.timeLight2.node.active = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 播放标签脉冲动画(在整数分钟时触发)
|
|
|
+ */
|
|
|
+ private playLabelPulseAnimation() {
|
|
|
+ if (!this.timeLabel) return;
|
|
|
+
|
|
|
+ // 保存原始缩放
|
|
|
+ const originalScale = this.timeLabel.node.scale.clone();
|
|
|
+ const targetScale = new Vec3(originalScale.x * 1.3, originalScale.y * 1.3, originalScale.z);
|
|
|
+
|
|
|
+ // 创建放大然后恢复的动画序列
|
|
|
+ tween(this.timeLabel.node)
|
|
|
+ .to(0.1, { scale: targetScale })
|
|
|
+ .to(0.1, { scale: originalScale })
|
|
|
+ // 添加轻微抖动
|
|
|
+ .to(0.05, { position: new Vec3(5, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(-5, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(3, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(-3, 0, 0) })
|
|
|
+ .to(0.05, { position: new Vec3(0, 0, 0) })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+}
|