289 lines
12 KiB
TypeScript
289 lines
12 KiB
TypeScript
import { Component, _decorator, Node, Label, ProgressBar, UITransform, Widget, Canvas, find, director, Color, Sprite, Layers, Graphics } from 'cc';
|
|
import { MinerStatusUI } from './MinerStatusUI';
|
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
/**
|
|
* 状态UI管理器
|
|
* 负责创建和管理游戏对象的状态显示界面
|
|
*/
|
|
@ccclass('StatusUIManager')
|
|
export class StatusUIManager extends Component {
|
|
|
|
/**
|
|
* 为矿工创建状态显示UI
|
|
*/
|
|
static createStatusUIForMiner(miner: Node): MinerStatusUI | null {
|
|
const canvas = find('Canvas') || director.getScene()?.getChildByName('Canvas');
|
|
if (!canvas) {
|
|
console.error('[StatusUIManager] 未找到Canvas');
|
|
return null;
|
|
}
|
|
|
|
const minerIndex = this.extractMinerIndex(miner.name);
|
|
const yOffset = minerIndex * 20;
|
|
|
|
const uiRoot = new Node(`${miner.name}_StatusUI`);
|
|
canvas.addChild(uiRoot);
|
|
|
|
const uiTransform = uiRoot.addComponent(UITransform);
|
|
uiTransform.setContentSize(200, 100);
|
|
|
|
const borderNode = new Node('Border');
|
|
uiRoot.addChild(borderNode);
|
|
const borderTransform = borderNode.addComponent(UITransform);
|
|
borderTransform.setContentSize(202, 102);
|
|
const borderGraphics = borderNode.addComponent(Graphics);
|
|
borderGraphics.fillColor = new Color(100, 100, 100, 120);
|
|
borderGraphics.rect(-101, -51, 202, 102);
|
|
borderGraphics.fill();
|
|
|
|
const borderWidget = borderNode.addComponent(Widget);
|
|
borderWidget.isAlignTop = true;
|
|
borderWidget.isAlignBottom = true;
|
|
borderWidget.isAlignLeft = true;
|
|
borderWidget.isAlignRight = true;
|
|
borderWidget.top = -1;
|
|
borderWidget.bottom = -1;
|
|
borderWidget.left = -1;
|
|
borderWidget.right = -1;
|
|
borderWidget.updateAlignment();
|
|
|
|
const backgroundNode = new Node('Background');
|
|
uiRoot.addChild(backgroundNode);
|
|
const backgroundTransform = backgroundNode.addComponent(UITransform);
|
|
backgroundTransform.setContentSize(200, 100);
|
|
const backgroundGraphics = backgroundNode.addComponent(Graphics);
|
|
backgroundGraphics.fillColor = new Color(0, 0, 0, 100);
|
|
backgroundGraphics.rect(-100, -50, 200, 100);
|
|
backgroundGraphics.fill();
|
|
|
|
const statusUI = uiRoot.addComponent(MinerStatusUI);
|
|
statusUI.setFollowTarget(miner);
|
|
statusUI.yOffset = 100 + yOffset;
|
|
|
|
const nameNode = new Node('NameLabel');
|
|
uiRoot.addChild(nameNode);
|
|
const nameTransform = nameNode.addComponent(UITransform);
|
|
nameTransform.setContentSize(200, 25);
|
|
const nameLabel = nameNode.addComponent(Label);
|
|
nameLabel.string = miner.name;
|
|
nameLabel.fontSize = 16;
|
|
nameLabel.color = new Color(255, 255, 255, 255);
|
|
|
|
const nameWidget = nameNode.addComponent(Widget);
|
|
nameWidget.isAlignTop = true;
|
|
nameWidget.top = 0;
|
|
nameWidget.isAlignHorizontalCenter = true;
|
|
nameWidget.updateAlignment();
|
|
|
|
// 创建状态标签
|
|
const statusNode = new Node('StatusLabel');
|
|
uiRoot.addChild(statusNode);
|
|
const statusTransform = statusNode.addComponent(UITransform);
|
|
statusTransform.setContentSize(200, 20);
|
|
const statusLabel = statusNode.addComponent(Label);
|
|
statusLabel.string = '待机中';
|
|
statusLabel.fontSize = 14;
|
|
statusLabel.color = new Color(200, 200, 200, 255);
|
|
|
|
// 设置状态标签位置
|
|
const statusWidget = statusNode.addComponent(Widget);
|
|
statusWidget.isAlignTop = true;
|
|
statusWidget.top = 25;
|
|
statusWidget.isAlignHorizontalCenter = true;
|
|
statusWidget.updateAlignment();
|
|
|
|
// 创建体力进度条
|
|
const staminaBarNode = new Node('StaminaBar');
|
|
uiRoot.addChild(staminaBarNode);
|
|
const staminaBarTransform = staminaBarNode.addComponent(UITransform);
|
|
staminaBarTransform.setContentSize(150, 8);
|
|
const staminaBar = staminaBarNode.addComponent(ProgressBar);
|
|
staminaBar.progress = 1.0;
|
|
|
|
// 创建体力进度条背景
|
|
const staminaBgNode = new Node('Background');
|
|
staminaBarNode.addChild(staminaBgNode);
|
|
const staminaBgTransform = staminaBgNode.addComponent(UITransform);
|
|
staminaBgTransform.setContentSize(150, 8);
|
|
const staminaBgGraphics = staminaBgNode.addComponent(Graphics);
|
|
staminaBgGraphics.fillColor = new Color(50, 50, 50, 255);
|
|
staminaBgGraphics.rect(-75, -4, 150, 8);
|
|
staminaBgGraphics.fill();
|
|
|
|
// 创建体力进度条填充
|
|
const staminaFillNode = new Node('Bar');
|
|
staminaBarNode.addChild(staminaFillNode);
|
|
const staminaFillTransform = staminaFillNode.addComponent(UITransform);
|
|
staminaFillTransform.setContentSize(150, 8);
|
|
const staminaFillGraphics = staminaFillNode.addComponent(Graphics);
|
|
staminaFillGraphics.fillColor = new Color(0, 255, 0, 255);
|
|
staminaFillGraphics.rect(-75, -4, 150, 8);
|
|
staminaFillGraphics.fill();
|
|
|
|
// 设置体力进度条位置
|
|
const staminaWidget = staminaBarNode.addComponent(Widget);
|
|
staminaWidget.isAlignTop = true;
|
|
staminaWidget.top = 45;
|
|
staminaWidget.isAlignHorizontalCenter = true;
|
|
staminaWidget.updateAlignment();
|
|
|
|
// 创建动作进度条
|
|
const actionBarNode = new Node('ActionProgressBar');
|
|
uiRoot.addChild(actionBarNode);
|
|
const actionBarTransform = actionBarNode.addComponent(UITransform);
|
|
actionBarTransform.setContentSize(150, 6);
|
|
const actionBar = actionBarNode.addComponent(ProgressBar);
|
|
actionBar.progress = 0;
|
|
actionBarNode.active = false; // 初始隐藏
|
|
|
|
// 创建动作进度条背景
|
|
const actionBgNode = new Node('Background');
|
|
actionBarNode.addChild(actionBgNode);
|
|
const actionBgTransform = actionBgNode.addComponent(UITransform);
|
|
actionBgTransform.setContentSize(150, 6);
|
|
const actionBgGraphics = actionBgNode.addComponent(Graphics);
|
|
actionBgGraphics.fillColor = new Color(50, 50, 50, 255);
|
|
actionBgGraphics.rect(-75, -3, 150, 6);
|
|
actionBgGraphics.fill();
|
|
|
|
// 创建动作进度条填充
|
|
const actionFillNode = new Node('Bar');
|
|
actionBarNode.addChild(actionFillNode);
|
|
const actionFillTransform = actionFillNode.addComponent(UITransform);
|
|
actionFillTransform.setContentSize(150, 6);
|
|
const actionFillGraphics = actionFillNode.addComponent(Graphics);
|
|
actionFillGraphics.fillColor = new Color(255, 255, 0, 255);
|
|
actionFillGraphics.rect(-75, -3, 150, 6);
|
|
actionFillGraphics.fill();
|
|
|
|
// 设置动作进度条位置
|
|
const actionWidget = actionBarNode.addComponent(Widget);
|
|
actionWidget.isAlignTop = true;
|
|
actionWidget.top = 55;
|
|
actionWidget.isAlignHorizontalCenter = true;
|
|
actionWidget.updateAlignment();
|
|
|
|
// 创建动作标签
|
|
const actionLabelNode = new Node('ActionLabel');
|
|
uiRoot.addChild(actionLabelNode);
|
|
const actionLabelTransform = actionLabelNode.addComponent(UITransform);
|
|
actionLabelTransform.setContentSize(200, 15);
|
|
const actionLabel = actionLabelNode.addComponent(Label);
|
|
actionLabel.string = '';
|
|
actionLabel.fontSize = 12;
|
|
actionLabel.color = new Color(255, 255, 0, 255);
|
|
|
|
// 设置动作标签位置
|
|
const actionLabelWidget = actionLabelNode.addComponent(Widget);
|
|
actionLabelWidget.isAlignTop = true;
|
|
actionLabelWidget.top = 65;
|
|
actionLabelWidget.isAlignHorizontalCenter = true;
|
|
actionLabelWidget.updateAlignment();
|
|
|
|
// 创建矿石数量标签
|
|
const oreCountNode = new Node('OreCountLabel');
|
|
uiRoot.addChild(oreCountNode);
|
|
const oreCountTransform = oreCountNode.addComponent(UITransform);
|
|
oreCountTransform.setContentSize(100, 15);
|
|
const oreCountLabel = oreCountNode.addComponent(Label);
|
|
oreCountLabel.string = '💎0';
|
|
oreCountLabel.fontSize = 12;
|
|
oreCountLabel.color = new Color(255, 215, 0, 255); // 金色
|
|
|
|
// 设置矿石数量标签位置(居中显示)
|
|
const oreCountWidget = oreCountNode.addComponent(Widget);
|
|
oreCountWidget.isAlignTop = true;
|
|
oreCountWidget.top = 80;
|
|
oreCountWidget.isAlignHorizontalCenter = true;
|
|
oreCountWidget.updateAlignment();
|
|
|
|
statusUI.nameLabel = nameLabel;
|
|
statusUI.statusLabel = statusLabel;
|
|
statusUI.staminaBar = staminaBar;
|
|
statusUI.actionProgressBar = actionBar;
|
|
statusUI.actionLabel = actionLabel;
|
|
statusUI.oreCountLabel = oreCountLabel;
|
|
statusUI.warehouseCountLabel = null;
|
|
|
|
StatusUIManager.setNodeLayerRecursively(uiRoot, Layers.Enum.UI_2D);
|
|
return statusUI;
|
|
}
|
|
|
|
/**
|
|
* 递归设置节点及其子节点的层级
|
|
*/
|
|
private static setNodeLayerRecursively(node: Node, layer: number) {
|
|
node.layer = layer;
|
|
for (const child of node.children) {
|
|
StatusUIManager.setNodeLayerRecursively(child, layer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 从矿工名字中提取索引号
|
|
*/
|
|
private static extractMinerIndex(minerName: string): number {
|
|
const match = minerName.match(/Miner_(\d+)/);
|
|
if (match) {
|
|
return parseInt(match[1]) - 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 为仓库创建存储量显示UI
|
|
*/
|
|
static createWarehouseUI(warehouse: Node): MinerStatusUI | null {
|
|
const canvas = find('Canvas') || director.getScene()?.getChildByName('Canvas');
|
|
if (!canvas) {
|
|
console.error('[StatusUIManager] 未找到Canvas');
|
|
return null;
|
|
}
|
|
|
|
const uiRoot = new Node(`${warehouse.name}_StorageUI`);
|
|
canvas.addChild(uiRoot);
|
|
|
|
const uiTransform = uiRoot.addComponent(UITransform);
|
|
uiTransform.setContentSize(120, 40);
|
|
|
|
const backgroundNode = new Node('Background');
|
|
uiRoot.addChild(backgroundNode);
|
|
const backgroundTransform = backgroundNode.addComponent(UITransform);
|
|
backgroundTransform.setContentSize(120, 40);
|
|
const backgroundGraphics = backgroundNode.addComponent(Graphics);
|
|
backgroundGraphics.fillColor = new Color(0, 0, 0, 120);
|
|
backgroundGraphics.rect(-60, -20, 120, 40);
|
|
backgroundGraphics.fill();
|
|
|
|
const storageNode = new Node('StorageLabel');
|
|
uiRoot.addChild(storageNode);
|
|
const storageTransform = storageNode.addComponent(UITransform);
|
|
storageTransform.setContentSize(120, 30);
|
|
const storageLabel = storageNode.addComponent(Label);
|
|
storageLabel.string = '🏭 总存储: 0';
|
|
storageLabel.fontSize = 14;
|
|
storageLabel.color = new Color(255, 255, 255, 255);
|
|
|
|
const storageWidget = storageNode.addComponent(Widget);
|
|
storageWidget.isAlignHorizontalCenter = true;
|
|
storageWidget.isAlignVerticalCenter = true;
|
|
storageWidget.updateAlignment();
|
|
|
|
const statusUI = uiRoot.addComponent(MinerStatusUI);
|
|
statusUI.setFollowTarget(warehouse);
|
|
statusUI.yOffset = 150;
|
|
|
|
statusUI.nameLabel = null;
|
|
statusUI.statusLabel = null;
|
|
statusUI.staminaBar = null;
|
|
statusUI.actionProgressBar = null;
|
|
statusUI.actionLabel = null;
|
|
statusUI.oreCountLabel = null;
|
|
statusUI.warehouseCountLabel = storageLabel;
|
|
|
|
StatusUIManager.setNodeLayerRecursively(uiRoot, Layers.Enum.UI_2D);
|
|
return statusUI;
|
|
}
|
|
}
|