采矿行为树示例

This commit is contained in:
YHH
2025-06-25 17:50:40 +08:00
parent 01084a8897
commit 0b4a6b77e2
28 changed files with 3119 additions and 2054 deletions

View File

@@ -0,0 +1,139 @@
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';
}
}
}