334 lines
11 KiB
TypeScript
334 lines
11 KiB
TypeScript
import { _decorator, Component, Vec3, Node } from 'cc';
|
|
import { UnitController } from './UnitController';
|
|
|
|
const { ccclass } = _decorator;
|
|
|
|
/**
|
|
* 矿工体力系统行为处理器 - 处理挖矿、休息、存储的完整循环
|
|
* 展示体力驱动的工作-休息循环系统
|
|
*/
|
|
@ccclass('RTSBehaviorHandler')
|
|
export class RTSBehaviorHandler extends Component {
|
|
|
|
private unitController: UnitController | null = null;
|
|
private minerDemo: any = null; // MinerDemo组件引用
|
|
private lastActionTime: number = 0;
|
|
private actionCooldown: number = 0.5; // 动作冷却时间,避免频繁切换
|
|
private minerIndex: number = -1; // 矿工索引,用于找到对应的家
|
|
|
|
start() {
|
|
this.unitController = this.getComponent(UnitController);
|
|
// 获取场景中的MinerDemo组件
|
|
this.minerDemo = this.node.parent?.getComponent('MinerDemo');
|
|
|
|
if (!this.unitController) {
|
|
console.error('RTSBehaviorHandler: 未找到UnitController组件');
|
|
}
|
|
if (!this.minerDemo) {
|
|
console.error('RTSBehaviorHandler: 未找到MinerDemo组件');
|
|
}
|
|
|
|
// 从节点名称中提取矿工索引
|
|
const match = this.node.name.match(/Miner_(\d+)/);
|
|
if (match) {
|
|
this.minerIndex = parseInt(match[1]) - 1; // 转换为0基索引
|
|
}
|
|
|
|
this.lastActionTime = Date.now();
|
|
}
|
|
|
|
/**
|
|
* 检查动作冷却
|
|
*/
|
|
private isActionOnCooldown(): boolean {
|
|
return (Date.now() - this.lastActionTime) < (this.actionCooldown * 1000);
|
|
}
|
|
|
|
/**
|
|
* 更新动作时间
|
|
*/
|
|
private updateActionTime() {
|
|
this.lastActionTime = Date.now();
|
|
}
|
|
|
|
/**
|
|
* 挖掘金矿(永不枯竭)
|
|
* @param params 事件参数,包含黑板变量值
|
|
*/
|
|
onMineGoldOre(params: any = {}): string {
|
|
if (!this.unitController || !this.minerDemo) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 检查体力是否充足
|
|
if (this.unitController.currentStamina < this.unitController.staminaCostPerMining) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 检查是否已经携带矿石
|
|
const hasOre = this.unitController.getBlackboardValue('hasOre');
|
|
if (hasOre) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 动作冷却检查
|
|
if (this.isActionOnCooldown()) {
|
|
return 'running';
|
|
}
|
|
|
|
// 获取所有金矿
|
|
const goldMines = this.minerDemo.getAllGoldMines();
|
|
if (goldMines.length === 0) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 寻找最近的金矿
|
|
const currentPos = this.node.worldPosition;
|
|
let nearestMine: Node | null = null;
|
|
let minDistance = Infinity;
|
|
|
|
for (const mine of goldMines) {
|
|
if (!mine || !mine.isValid) continue;
|
|
|
|
const distance = Vec3.distance(currentPos, mine.worldPosition);
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
nearestMine = mine;
|
|
}
|
|
}
|
|
|
|
if (!nearestMine) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 检查是否已经到达金矿位置
|
|
if (minDistance < 2.0) {
|
|
// 检查是否正在移动
|
|
const isMoving = this.unitController.getBlackboardValue('isMoving');
|
|
if (isMoving) {
|
|
return 'running';
|
|
}
|
|
|
|
// 消耗体力
|
|
this.unitController.currentStamina = Math.max(0, this.unitController.currentStamina - this.unitController.staminaCostPerMining);
|
|
|
|
// 设置携带矿石状态
|
|
this.unitController.setBlackboardValue('hasOre', true);
|
|
|
|
// 通知演示管理器
|
|
this.minerDemo.mineGoldOre(this.node);
|
|
|
|
// 清除移动目标
|
|
this.unitController.clearTarget();
|
|
this.unitController.setBlackboardValue('isMoving', false);
|
|
|
|
this.updateActionTime();
|
|
return 'success';
|
|
} else {
|
|
// 设置移动目标
|
|
this.unitController.setTarget(nearestMine.worldPosition);
|
|
return 'running';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前往仓库存储矿石
|
|
* @param params 事件参数,包含黑板变量值
|
|
*/
|
|
onStoreOre(params: any = {}): string {
|
|
if (!this.unitController || !this.minerDemo) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 检查是否携带矿石
|
|
const hasOre = this.unitController.getBlackboardValue('hasOre');
|
|
if (!hasOre) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 动作冷却检查
|
|
if (this.isActionOnCooldown()) {
|
|
return 'running';
|
|
}
|
|
|
|
const warehouse = this.minerDemo.getWarehouse();
|
|
if (!warehouse || !warehouse.isValid) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 计算到仓库的距离
|
|
const currentPos = this.node.worldPosition;
|
|
const warehousePos = warehouse.worldPosition;
|
|
const distance = Vec3.distance(currentPos, warehousePos);
|
|
|
|
// 检查是否已经到达仓库
|
|
if (distance < 2.5) {
|
|
// 检查是否正在移动
|
|
const isMoving = this.unitController.getBlackboardValue('isMoving');
|
|
if (isMoving) {
|
|
return 'running';
|
|
}
|
|
|
|
// 清除携带矿石状态
|
|
this.unitController.setBlackboardValue('hasOre', false);
|
|
|
|
// 清除移动目标
|
|
this.unitController.clearTarget();
|
|
this.unitController.setBlackboardValue('isMoving', false);
|
|
|
|
this.updateActionTime();
|
|
return 'success';
|
|
} else {
|
|
// 设置移动目标
|
|
this.unitController.setTarget(warehousePos);
|
|
return 'running';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 回家休息
|
|
* @param params 事件参数,包含黑板变量值
|
|
*/
|
|
onGoHomeRest(params: any = {}): string {
|
|
if (!this.unitController || !this.minerDemo) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 动作冷却检查
|
|
if (this.isActionOnCooldown()) {
|
|
return 'running';
|
|
}
|
|
|
|
// 获取矿工的家
|
|
const home = this.minerDemo.getMinerHome(this.minerIndex);
|
|
if (!home || !home.isValid) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 计算到家的距离
|
|
const currentPos = this.node.worldPosition;
|
|
const homePos = home.worldPosition;
|
|
const distance = Vec3.distance(currentPos, homePos);
|
|
|
|
// 检查是否已经到达家
|
|
if (distance < 2.0) {
|
|
// 检查是否正在移动
|
|
const isMoving = this.unitController.getBlackboardValue('isMoving');
|
|
if (isMoving) {
|
|
return 'running';
|
|
}
|
|
|
|
// 设置休息状态
|
|
this.unitController.setBlackboardValue('isResting', true);
|
|
|
|
// 清除移动目标
|
|
this.unitController.clearTarget();
|
|
this.unitController.setBlackboardValue('isMoving', false);
|
|
|
|
this.updateActionTime();
|
|
return 'success';
|
|
} else {
|
|
// 设置移动目标
|
|
this.unitController.setTarget(homePos);
|
|
return 'running';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 恢复体力
|
|
* @param params 事件参数,包含黑板变量值
|
|
*/
|
|
onRecoverStamina(params: any = {}): string {
|
|
if (!this.unitController) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 检查是否在家中
|
|
const isResting = this.unitController.getBlackboardValue('isResting');
|
|
if (!isResting) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 恢复体力
|
|
const oldStamina = this.unitController.currentStamina;
|
|
this.unitController.currentStamina = Math.min(this.unitController.maxStamina,
|
|
this.unitController.currentStamina + this.unitController.staminaRecoveryRate * 0.1); // 每次恢复2点体力
|
|
|
|
const isFullyRested = this.unitController.currentStamina >= this.unitController.maxStamina;
|
|
|
|
if (isFullyRested) {
|
|
// 清除休息状态
|
|
this.unitController.setBlackboardValue('isResting', false);
|
|
|
|
// 通知演示管理器
|
|
this.minerDemo.completeRestCycle();
|
|
|
|
this.updateActionTime();
|
|
return 'success';
|
|
} else {
|
|
// 体力还在恢复中
|
|
return 'running';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 待机行为
|
|
* @param params 事件参数,包含黑板变量值
|
|
*/
|
|
onIdleBehavior(params: any = {}): string {
|
|
if (!this.unitController) {
|
|
return 'failure';
|
|
}
|
|
|
|
// 清除移动目标,确保停止移动
|
|
this.unitController.clearTarget();
|
|
this.unitController.setBlackboardValue('isMoving', false);
|
|
|
|
|
|
|
|
return 'success';
|
|
}
|
|
|
|
/**
|
|
* 获取矿工状态摘要
|
|
*/
|
|
getMinerStatus(): string {
|
|
if (!this.unitController) return 'Unknown';
|
|
|
|
const hasOre = this.unitController.getBlackboardValue('hasOre');
|
|
const isMoving = this.unitController.getBlackboardValue('isMoving');
|
|
const isResting = this.unitController.getBlackboardValue('isResting');
|
|
const stamina = this.unitController.currentStamina;
|
|
const maxStamina = this.unitController.maxStamina;
|
|
|
|
let status = '';
|
|
if (isResting) {
|
|
status = '😴休息中';
|
|
} else if (hasOre) {
|
|
status = isMoving ? '🚚运输中' : '📦携带矿石';
|
|
} else {
|
|
status = isMoving ? '🚶移动中' : '⛏️挖矿';
|
|
}
|
|
|
|
return `${status} (体力:${stamina.toFixed(0)}/${maxStamina})`;
|
|
}
|
|
|
|
/**
|
|
* 调试信息
|
|
*/
|
|
getDebugInfo(): any {
|
|
if (!this.unitController) return {};
|
|
|
|
return {
|
|
name: this.node.name,
|
|
hasOre: this.unitController.getBlackboardValue('hasOre'),
|
|
isMoving: this.unitController.getBlackboardValue('isMoving'),
|
|
isResting: this.unitController.getBlackboardValue('isResting'),
|
|
stamina: this.unitController.currentStamina,
|
|
maxStamina: this.unitController.maxStamina,
|
|
staminaPercentage: this.unitController.currentStamina / this.unitController.maxStamina,
|
|
isLowStamina: this.unitController.currentStamina < this.unitController.maxStamina * 0.2,
|
|
status: this.getMinerStatus()
|
|
};
|
|
}
|
|
} |