import { Component, _decorator, Label, ProgressBar, Node, UITransform, Canvas, find, Camera, Vec3, director, Color, Layers, Graphics } from 'cc'; const { ccclass, property } = _decorator; /** * 矿工状态UI组件 */ @ccclass('MinerStatusUI') export class MinerStatusUI extends Component { nameLabel: Label | null = null; statusLabel: Label | null = null; staminaBar: ProgressBar | null = null; actionProgressBar: ProgressBar | null = null; actionLabel: Label | null = null; oreCountLabel: Label | null = null; warehouseCountLabel: Label | null = null; @property followTarget: Node | null = null; @property yOffset: number = 100; private camera: Camera | null = null; private canvas: Canvas | null = null; start() { this.node.layer = Layers.Enum.UI_2D; this.camera = find('Main Camera')?.getComponent(Camera) || director.getScene()?.getComponentInChildren(Camera); this.canvas = find('Canvas')?.getComponent(Canvas) || director.getScene()?.getComponentInChildren(Canvas); if (!this.camera) { console.warn('[MinerStatusUI] 未找到主摄像机'); } if (!this.canvas) { console.warn('[MinerStatusUI] 未找到Canvas'); } if (this.nameLabel && this.followTarget) { this.nameLabel.string = this.followTarget.name; } this.updateStamina(100, 100); this.updateStatus('待机中'); this.updateActionProgress('', 0); } update() { if (this.followTarget && this.camera && this.canvas) { this.updateUIPosition(); } } private updateUIPosition() { if (!this.followTarget || !this.camera || !this.canvas) return; const targetWorldPos = this.followTarget.worldPosition.clone(); targetWorldPos.y += this.yOffset / 100; const screenPos = this.camera.worldToScreen(targetWorldPos); const canvasTransform = this.canvas.node.getComponent(UITransform); if (canvasTransform) { const canvasPos = new Vec3( screenPos.x - canvasTransform.width / 2, screenPos.y - canvasTransform.height / 2, 0 ); this.node.setPosition(canvasPos); } } setFollowTarget(target: Node) { this.followTarget = target; if (this.nameLabel) { this.nameLabel.string = target.name; } } updateStamina(current: number, max: number) { if (this.staminaBar) { this.staminaBar.progress = current / max; } if (this.staminaBar) { const percentage = current / max; const fillNode = this.staminaBar.node.getChildByName('Bar'); if (fillNode) { const graphics = fillNode.getComponent(Graphics); if (graphics) { let color: Color; if (percentage > 0.6) { color = new Color(0, 255, 0, 255); } else if (percentage > 0.3) { color = new Color(255, 255, 0, 255); } else { color = new Color(255, 0, 0, 255); } graphics.clear(); graphics.fillColor = color; graphics.rect(-75, -4, 150 * percentage, 8); graphics.fill(); } } } } updateStatus(status: string) { if (this.statusLabel) { this.statusLabel.string = status; } } updateActionProgress(actionName: string, progress: number) { if (this.actionLabel) { this.actionLabel.string = actionName; } if (this.actionProgressBar) { this.actionProgressBar.progress = Math.max(0, Math.min(1, progress)); this.actionProgressBar.node.active = actionName !== '' && progress > 0; } } setVisible(visible: boolean) { this.node.active = visible; } updateOreCount(hasOre: boolean, warehouseTotal: number) { if (this.oreCountLabel) { this.oreCountLabel.string = hasOre ? '💎1' : '💎0'; } } }