import { _decorator, Component, resources, JsonAsset } from 'cc'; import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig } from '@esengine/ai'; import { UnitController } from './UnitController'; const { ccclass, property } = _decorator; /** * 执行上下文接口 */ interface GameExecutionContext { blackboard?: Blackboard; unitController: UnitController; gameObject: any; [key: string]: any; } /** * 行为树管理器 - 使用@esengine/ai包管理行为树 */ @ccclass('BehaviorTreeManager') export class BehaviorTreeManager extends Component { @property debugMode: boolean = true; @property tickInterval: number = 0.1; // 行为树更新间隔(秒) private behaviorTree: BehaviorTree | null = null; private blackboard: Blackboard | null = null; private context: GameExecutionContext | null = null; private isLoaded: boolean = false; private isRunning: boolean = false; private lastTickTime: number = 0; private unitController: UnitController | null = null; private currentBehaviorTreeName: string = ''; /** * 初始化行为树 */ async initializeBehaviorTree(behaviorTreeName: string, unitController: UnitController) { this.currentBehaviorTreeName = behaviorTreeName; this.unitController = unitController; try { await this.loadBehaviorTree(behaviorTreeName); this.setupBlackboard(); this.isLoaded = true; this.isRunning = true; console.log(`行为树初始化成功: ${behaviorTreeName}`); } catch (error) { console.error(`行为树初始化失败: ${behaviorTreeName}`, error); } } /** * 加载行为树文件 */ private async loadBehaviorTree(behaviorTreeName: string): Promise { return new Promise((resolve, reject) => { const jsonPath = `${behaviorTreeName}.bt`; resources.load(jsonPath, JsonAsset, (err, asset) => { if (err) { console.error(`加载行为树文件失败: ${jsonPath}`, err); reject(err); return; } try { const behaviorTreeData = asset.json as BehaviorTreeJSONConfig; // 创建执行上下文 this.blackboard = new Blackboard(); this.context = { blackboard: this.blackboard, unitController: this.unitController!, gameObject: this.node }; // 从JSON数据创建行为树 const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig(behaviorTreeData, this.context); this.behaviorTree = buildResult.tree as BehaviorTree; this.blackboard = buildResult.blackboard; resolve(); } catch (parseError) { console.error(`创建行为树失败: ${jsonPath}`, parseError); reject(parseError); } }); }); } /** * 设置黑板基础信息 */ private setupBlackboard() { if (!this.unitController || !this.blackboard) return; // 设置单位基础信息 this.blackboard.setValue('entityName', this.node.name); this.blackboard.setValue('unitType', this.unitController.unitType); this.blackboard.setValue('maxHealth', this.unitController.maxHealth); this.blackboard.setValue('currentHealth', this.unitController.currentHealth); this.blackboard.setValue('moveSpeed', this.unitController.moveSpeed); this.blackboard.setValue('attackRange', this.unitController.attackRange); this.blackboard.setValue('attackDamage', this.unitController.attackDamage); this.blackboard.setValue('attackCooldown', this.unitController.attackCooldown); // 设置时间信息 this.blackboard.setValue('currentTime', Date.now() / 1000); this.blackboard.setValue('deltaTime', 0.016); this.blackboard.setValue('worldPosition', this.node.worldPosition); // 设置初始状态 this.blackboard.setValue('currentCommand', 'idle'); this.blackboard.setValue('hasTarget', false); this.blackboard.setValue('isSelected', false); // 设置单位控制器引用,供行为树节点使用 this.blackboard.setValue('unitController', this.unitController); this.blackboard.setValue('gameObject', this.node); } /** * 更新黑板值 */ updateBlackboardValue(key: string, value: any) { if (this.blackboard) { this.blackboard.setValue(key, value); } } /** * 获取黑板值 */ getBlackboardValue(key: string): any { return this.blackboard?.getValue(key); } /** * 获取黑板 */ getBlackboard(): Blackboard | null { return this.blackboard; } /** * 获取行为树 */ getBehaviorTree(): BehaviorTree | null { return this.behaviorTree; } /** * 更新行为树 */ update(deltaTime: number) { if (!this.isLoaded || !this.isRunning || !this.behaviorTree || !this.blackboard) return; // 控制更新频率 this.lastTickTime += deltaTime; if (this.lastTickTime < this.tickInterval) return; this.lastTickTime = 0; // 更新黑板中的时间信息 this.blackboard.setValue('deltaTime', deltaTime); this.blackboard.setValue('currentTime', Date.now() / 1000); this.blackboard.setValue('worldPosition', this.node.worldPosition); // 更新单位状态信息 if (this.unitController) { this.blackboard.setValue('currentHealth', this.unitController.currentHealth); this.blackboard.setValue('healthPercentage', this.unitController.currentHealth / this.unitController.maxHealth); this.blackboard.setValue('isLowHealth', this.unitController.currentHealth < this.unitController.maxHealth * 0.3); this.blackboard.setValue('currentCommand', this.unitController.currentCommand); this.blackboard.setValue('isSelected', this.unitController.isSelected); this.blackboard.setValue('targetPosition', this.unitController.targetPosition); this.blackboard.setValue('targetNode', this.unitController.targetNode); // 更新距离信息 if (this.unitController.targetPosition) { const distance = this.node.worldPosition.subtract(this.unitController.targetPosition).length(); this.blackboard.setValue('distanceToTarget', distance); this.blackboard.setValue('isInAttackRange', distance <= this.unitController.attackRange); this.blackboard.setValue('isCloseToTarget', distance <= 1.0); } // 更新状态标志 this.blackboard.setValue('isIdle', this.unitController.currentCommand === 'idle'); this.blackboard.setValue('isMoving', this.unitController.currentCommand === 'move'); this.blackboard.setValue('isAttacking', this.unitController.currentCommand === 'attack'); this.blackboard.setValue('isGathering', this.unitController.currentCommand === 'gather'); this.blackboard.setValue('isPatrolling', this.unitController.currentCommand === 'patrol'); } // 执行行为树 try { this.behaviorTree.tick(deltaTime); if (this.debugMode && Math.random() < 0.01) { // 1%的概率打印调试信息 console.log(`行为树执行完成, 单位: ${this.node.name}`); } } catch (error) { console.error(`行为树执行错误:`, error); } } /** * 暂停行为树 */ pause() { this.isRunning = false; } /** * 恢复行为树 */ resume() { if (this.isLoaded) { this.isRunning = true; } } /** * 停止行为树 */ stop() { this.isRunning = false; } /** * 重新加载行为树 */ async reloadBehaviorTree() { if (this.currentBehaviorTreeName && this.unitController) { this.stop(); await this.initializeBehaviorTree(this.currentBehaviorTreeName, this.unitController); } } /** * 重置行为树 */ reset() { if (this.behaviorTree) { this.behaviorTree.reset(); } } onDestroy() { this.stop(); this.behaviorTree = null; this.blackboard = null; this.context = null; } }