import { World, Entity, Scene, createLogger, Time, Core, ComponentRegistry, Component } from '@esengine/ecs-framework'; import { BehaviorTreeNode as BehaviorTreeNodeComponent, BlackboardComponent, ActiveNode, PropertyBindings, LogOutput, RootExecutionSystem, LeafExecutionSystem, DecoratorExecutionSystem, CompositeExecutionSystem, SubTreeExecutionSystem, FileSystemAssetLoader, CompositeNodeComponent, TaskStatus, NodeType, WaitAction, LogAction, SetBlackboardValueAction, ModifyBlackboardValueAction, ExecuteAction, BlackboardCompareCondition, BlackboardExistsCondition, RandomProbabilityCondition, ExecuteCondition, RootNode, SequenceNode, SelectorNode, ParallelNode, ParallelSelectorNode, RandomSequenceNode, RandomSelectorNode, SubTreeNode, InverterNode, RepeaterNode, UntilSuccessNode, UntilFailNode, AlwaysSucceedNode, AlwaysFailNode, ConditionalNode, CooldownNode, TimeoutNode, AbortType, CompareOperator } from '@esengine/behavior-tree'; import type { BehaviorTreeNode } from '../stores/behaviorTreeStore'; import { TauriAPI } from '../api/tauri'; const logger = createLogger('BehaviorTreeExecutor'); export interface ExecutionStatus { nodeId: string; status: 'running' | 'success' | 'failure' | 'idle'; message?: string; } export interface ExecutionLog { timestamp: number; message: string; level: 'info' | 'success' | 'error' | 'warning'; nodeId?: string; } export type ExecutionCallback = ( statuses: ExecutionStatus[], logs: ExecutionLog[], blackboardVariables?: Record ) => void; /** * 真实的行为树执行器 * * 使用真实的 ECS 系统执行行为树 */ export class BehaviorTreeExecutor { private world: World; private scene: Scene; private rootEntity: Entity | null = null; private entityMap: Map = new Map(); private blackboardVariables: Record = {}; private initialBlackboardVariables: Record = {}; private callback: ExecutionCallback | null = null; private isRunning = false; private isPaused = false; private executionLogs: ExecutionLog[] = []; private lastStatuses: Map = new Map(); private debugMode = false; private tickCount = 0; // 存储节点ID -> 属性绑定信息的映射 private propertyBindingsMap: Map> = new Map(); // 标记是否已添加 SubTreeExecutionSystem private hasSubTreeSystem = false; constructor() { this.world = new World({ name: 'BehaviorTreeWorld' }); this.scene = this.world.createScene('BehaviorTreeScene'); // 只注册基础执行系统 this.scene.addSystem(new RootExecutionSystem()); this.scene.addSystem(new LeafExecutionSystem()); this.scene.addSystem(new DecoratorExecutionSystem()); this.scene.addSystem(new CompositeExecutionSystem()); // SubTreeExecutionSystem 按需添加 } /** * 检测是否有 SubTree 节点 */ private detectSubTreeNodes(nodes: BehaviorTreeNode[]): boolean { return nodes.some(node => node.template.displayName === '子树'); } /** * 从编辑器节点构建真实的 Entity 树 */ buildTree( nodes: BehaviorTreeNode[], rootNodeId: string, blackboard: Record, connections: Array<{ from: string; to: string; fromProperty?: string; toProperty?: string; connectionType: 'node' | 'property' }>, callback: ExecutionCallback, projectPath?: string | null ): void { this.cleanup(); this.blackboardVariables = { ...blackboard }; this.callback = callback; const nodeMap = new Map(); nodes.forEach(node => nodeMap.set(node.id, node)); // 检测是否有 SubTree 节点 const hasSubTreeNode = this.detectSubTreeNodes(nodes); if (hasSubTreeNode) { // 按需添加 SubTreeExecutionSystem if (!this.hasSubTreeSystem) { this.scene.addSystem(new SubTreeExecutionSystem()); this.hasSubTreeSystem = true; logger.debug('检测到 SubTree 节点,已添加 SubTreeExecutionSystem'); } // 配置资产加载器以支持 SubTree 节点 if (projectPath) { const assetLoader = new FileSystemAssetLoader({ basePath: `${projectPath}/.ecs/behaviors`, format: 'json', extension: '.btree', enableCache: true, readFile: async (path: string) => { const content = await TauriAPI.readFileContent(path); return content; } }); Core.services.registerInstance(FileSystemAssetLoader, assetLoader); logger.info(`已配置资产加载器: ${projectPath}/.ecs/behaviors`); } else { logger.warn( '检测到 SubTree 节点,但未提供项目路径。\n' + 'SubTree 节点需要项目路径来加载子树资产。\n' + '请在编辑器中打开项目,或确保运行时环境已正确配置资产路径。' ); } } const rootNode = nodeMap.get(rootNodeId); if (!rootNode) { logger.error('未找到根节点'); return; } // 先创建黑板组件 const blackboardComp = new BlackboardComponent(); Object.entries(this.blackboardVariables).forEach(([key, value]) => { const type = typeof value === 'number' ? 'number' : typeof value === 'string' ? 'string' : typeof value === 'boolean' ? 'boolean' : 'object'; blackboardComp.defineVariable(key, type as any, value); }); // 在创建实体之前先处理属性连接,这样创建组件时就能读到正确的值 this.applyPropertyConnections(connections, nodeMap, blackboardComp); // 创建实体树 this.rootEntity = this.createEntityFromNode(rootNode, nodeMap, null); if (this.rootEntity) { // 将黑板组件添加到根实体 this.rootEntity.addComponent(blackboardComp); // 添加LogOutput组件,用于收集日志 this.rootEntity.addComponent(new LogOutput()); if (this.debugMode) { this.logDebugTreeStructure(); // 立即触发一次回调,显示 debug 信息 if (this.callback) { this.callback([], this.executionLogs); } } } } /** * 应用属性连接 * 记录属性到黑板变量的绑定关系 */ private applyPropertyConnections( connections: Array<{ from: string; to: string; fromProperty?: string; toProperty?: string; connectionType: 'node' | 'property' }>, nodeMap: Map, blackboard: BlackboardComponent ): void { // 清空之前的绑定信息 this.propertyBindingsMap.clear(); // 过滤出属性类型的连接 const propertyConnections = connections.filter(conn => conn.connectionType === 'property'); logger.info(`[属性绑定] 找到 ${propertyConnections.length} 个属性连接`); propertyConnections.forEach(conn => { const fromNode = nodeMap.get(conn.from); const toNode = nodeMap.get(conn.to); if (!fromNode || !toNode || !conn.toProperty) { logger.warn(`[属性绑定] 连接数据不完整: from=${conn.from}, to=${conn.to}, toProperty=${conn.toProperty}`); return; } let variableName: string | undefined; // 检查 from 节点是否是黑板变量节点 if (fromNode.data.nodeType === 'blackboard-variable') { // 黑板变量节点,变量名在 data.variableName 中 variableName = fromNode.data.variableName; } else if (conn.fromProperty) { // 普通节点的属性连接 variableName = conn.fromProperty; } if (!variableName) { logger.warn(`[属性绑定] 无法确定变量名: from节点=${fromNode.template.displayName}`); return; } if (!blackboard.hasVariable(variableName)) { logger.warn(`[属性绑定] 黑板变量不存在: ${variableName}`); return; } // 记录绑定信息到 Map let nodeBindings = this.propertyBindingsMap.get(toNode.id); if (!nodeBindings) { nodeBindings = new Map(); this.propertyBindingsMap.set(toNode.id, nodeBindings); } nodeBindings.set(conn.toProperty, variableName); logger.info(`[属性绑定] 成功绑定: 节点 "${toNode.template.displayName}" 的属性 "${conn.toProperty}" -> 黑板变量 "${variableName}"`); }); } /** * 递归创建 Entity */ private createEntityFromNode( node: BehaviorTreeNode, nodeMap: Map, parent: Entity | null ): Entity { const displayName = node.template.displayName || 'Node'; const entityName = `${displayName}#${node.id}`; const entity = this.scene.createEntity(entityName); this.entityMap.set(node.id, entity); if (parent) { parent.addChild(entity); } const btNode = new BehaviorTreeNodeComponent(); btNode.nodeType = this.getNodeType(node); entity.addComponent(btNode); this.addNodeComponents(entity, node); // 检查是否有属性绑定,如果有则添加 PropertyBindings 组件 const bindings = this.propertyBindingsMap.get(node.id); if (bindings && bindings.size > 0) { const propertyBindings = new PropertyBindings(); bindings.forEach((variableName, propertyName) => { propertyBindings.addBinding(propertyName, variableName); }); entity.addComponent(propertyBindings); logger.info(`[PropertyBindings] 为节点 "${node.template.displayName}" 添加了 ${bindings.size} 个属性绑定`); } node.children.forEach(childId => { const childNode = nodeMap.get(childId); if (childNode) { this.createEntityFromNode(childNode, nodeMap, entity); } }); return entity; } /** * 获取节点类型 */ private getNodeType(node: BehaviorTreeNode): NodeType { const type = node.template.type; if (type === NodeType.Composite) return NodeType.Composite; if (type === NodeType.Decorator) return NodeType.Decorator; if (type === NodeType.Action) return NodeType.Action; if (type === NodeType.Condition) return NodeType.Condition; return NodeType.Action; } /** * 根据节点数据添加对应的组件 */ private addNodeComponents(entity: Entity, node: BehaviorTreeNode): void { const category = node.template.category; const data = node.data; const nodeType = node.template.type; if (category === '根节点' || data.nodeType === 'root') { // 根节点使用专门的 RootNode 组件 entity.addComponent(new RootNode()); } else if (nodeType === NodeType.Action) { // 根据节点类型而不是 category 来判断,这样可以支持自定义 category this.addActionComponent(entity, node); } else if (nodeType === NodeType.Condition) { this.addConditionComponent(entity, node); } else if (nodeType === NodeType.Composite) { this.addCompositeComponent(entity, node); } else if (nodeType === NodeType.Decorator) { this.addDecoratorComponent(entity, node); } } /** * 添加动作组件 */ private addActionComponent(entity: Entity, node: BehaviorTreeNode): void { const displayName = node.template.displayName; if (displayName === '等待') { const action = new WaitAction(); action.waitTime = node.data.waitTime ?? 1.0; entity.addComponent(action); } else if (displayName === '日志') { const action = new LogAction(); action.message = node.data.message ?? ''; action.level = node.data.level ?? 'log'; entity.addComponent(action); } else if (displayName === '设置变量') { const action = new SetBlackboardValueAction(); action.variableName = node.data.variableName ?? ''; action.value = node.data.value; entity.addComponent(action); } else if (displayName === '修改变量') { const action = new ModifyBlackboardValueAction(); action.variableName = node.data.variableName ?? ''; action.operation = node.data.operation ?? 'add'; action.operand = node.data.operand ?? 0; entity.addComponent(action); } else if (displayName === '自定义动作') { const action = new ExecuteAction(); action.actionCode = node.data.actionCode ?? 'return TaskStatus.Success;'; entity.addComponent(action); } else { const ComponentClass = node.template.componentClass || (node.template.className ? ComponentRegistry.getComponentType(node.template.className) : null); if (ComponentClass) { try { const component = new (ComponentClass as any)(); Object.assign(component, node.data); entity.addComponent(component as Component); } catch (error) { logger.error(`创建动作组件失败: ${node.template.className}, error: ${error}`); } } else { logger.warn(`未找到动作组件类: ${node.template.className}`); } } } /** * 添加条件组件 */ private addConditionComponent(entity: Entity, node: BehaviorTreeNode): void { const displayName = node.template.displayName; if (displayName === '比较变量') { const condition = new BlackboardCompareCondition(); condition.variableName = node.data.variableName ?? ''; condition.operator = (node.data.operator as CompareOperator) ?? CompareOperator.Equal; condition.compareValue = node.data.compareValue; condition.invertResult = node.data.invertResult ?? false; entity.addComponent(condition); } else if (displayName === '变量存在') { const condition = new BlackboardExistsCondition(); condition.variableName = node.data.variableName ?? ''; condition.checkNotNull = node.data.checkNotNull ?? false; condition.invertResult = node.data.invertResult ?? false; entity.addComponent(condition); } else if (displayName === '随机概率') { const condition = new RandomProbabilityCondition(); condition.probability = node.data.probability ?? 0.5; entity.addComponent(condition); } else if (displayName === '执行条件') { const condition = new ExecuteCondition(); condition.conditionCode = node.data.conditionCode ?? ''; condition.invertResult = node.data.invertResult ?? false; entity.addComponent(condition); } else { const ComponentClass = node.template.componentClass || (node.template.className ? ComponentRegistry.getComponentType(node.template.className) : null); if (ComponentClass) { try { const component = new (ComponentClass as any)(); Object.assign(component, node.data); entity.addComponent(component as Component); } catch (error) { logger.error(`创建条件组件失败: ${node.template.className}, error: ${error}`); } } else { logger.warn(`未找到条件组件类: ${node.template.className}`); } } } /** * 添加复合节点组件 */ private addCompositeComponent(entity: Entity, node: BehaviorTreeNode): void { const displayName = node.template.displayName; if (displayName === '序列') { const composite = new SequenceNode(); composite.abortType = (node.data.abortType as AbortType) ?? AbortType.None; entity.addComponent(composite); } else if (displayName === '选择') { const composite = new SelectorNode(); composite.abortType = (node.data.abortType as AbortType) ?? AbortType.None; entity.addComponent(composite); } else if (displayName === '并行') { const composite = new ParallelNode(); composite.successPolicy = node.data.successPolicy ?? 'all'; composite.failurePolicy = node.data.failurePolicy ?? 'one'; entity.addComponent(composite); } else if (displayName === '并行选择') { const composite = new ParallelSelectorNode(); composite.failurePolicy = node.data.failurePolicy ?? 'one'; entity.addComponent(composite); } else if (displayName === '随机序列') { const composite = new RandomSequenceNode(); entity.addComponent(composite); } else if (displayName === '随机选择') { const composite = new RandomSelectorNode(); entity.addComponent(composite); } else if (displayName === '子树') { const composite = new SubTreeNode(); composite.assetId = node.data.assetId ?? ''; composite.inheritParentBlackboard = node.data.inheritParentBlackboard ?? true; composite.propagateFailure = node.data.propagateFailure ?? true; entity.addComponent(composite); } } /** * 添加装饰器组件 */ private addDecoratorComponent(entity: Entity, node: BehaviorTreeNode): void { const displayName = node.template.displayName; if (displayName === '反转') { entity.addComponent(new InverterNode()); } else if (displayName === '重复') { const decorator = new RepeaterNode(); decorator.repeatCount = node.data.repeatCount ?? -1; decorator.endOnFailure = node.data.endOnFailure ?? false; entity.addComponent(decorator); } else if (displayName === '直到成功') { entity.addComponent(new UntilSuccessNode()); } else if (displayName === '直到失败') { entity.addComponent(new UntilFailNode()); } else if (displayName === '总是成功') { entity.addComponent(new AlwaysSucceedNode()); } else if (displayName === '总是失败') { entity.addComponent(new AlwaysFailNode()); } else if (displayName === '条件装饰器') { const decorator = new ConditionalNode(); decorator.conditionCode = node.data.conditionCode; decorator.shouldReevaluate = node.data.shouldReevaluate ?? true; entity.addComponent(decorator); } else if (displayName === '冷却') { const decorator = new CooldownNode(); decorator.cooldownTime = node.data.cooldownTime ?? 1.0; entity.addComponent(decorator); } else if (displayName === '超时') { const decorator = new TimeoutNode(); decorator.timeoutDuration = node.data.timeoutDuration ?? 1.0; entity.addComponent(decorator); } } /** * 开始执行 */ start(): void { if (!this.rootEntity) { logger.error('未构建行为树'); return; } this.isRunning = true; this.isPaused = false; this.executionLogs = []; this.lastStatuses.clear(); this.tickCount = 0; // 保存黑板变量的初始值(深拷贝) this.initialBlackboardVariables = JSON.parse(JSON.stringify(this.blackboardVariables)); this.addLog('开始执行行为树', 'info'); // 打印树结构用于调试 this.addLog('=== 行为树结构 ===', 'info'); this.logEntityStructure(this.rootEntity, 0); this.addLog('===================', 'info'); this.rootEntity.addComponent(new ActiveNode()); } /** * 暂停执行 */ pause(): void { this.isPaused = true; } /** * 恢复执行 */ resume(): void { this.isPaused = false; } /** * 停止执行 */ stop(): void { this.isRunning = false; this.isPaused = false; if (this.rootEntity) { this.deactivateAllNodes(this.rootEntity); // 恢复黑板变量到初始值 this.restoreBlackboardVariables(); } } /** * 恢复黑板变量到初始值 */ private restoreBlackboardVariables(): void { if (!this.rootEntity) { return; } const blackboard = this.rootEntity.getComponent(BlackboardComponent); if (!blackboard) { return; } // 恢复所有变量到初始值 Object.entries(this.initialBlackboardVariables).forEach(([key, value]) => { blackboard.setValue(key, value, true); }); // 同步到 blackboardVariables this.blackboardVariables = JSON.parse(JSON.stringify(this.initialBlackboardVariables)); this.addLog('已恢复黑板变量到初始值', 'info'); } /** * 递归停用所有节点 */ private deactivateAllNodes(entity: Entity): void { entity.removeComponentByType(ActiveNode); const btNode = entity.getComponent(BehaviorTreeNodeComponent); if (btNode) { btNode.reset(); } entity.children.forEach((child: Entity) => this.deactivateAllNodes(child)); } /** * 执行一帧 */ tick(deltaTime: number): void { if (!this.isRunning || this.isPaused) { return; } // 更新全局时间信息 Time.update(deltaTime); this.tickCount++; if (this.debugMode) { this.addLog(`=== Tick ${this.tickCount} ===`, 'info'); } this.scene.update(); if (this.debugMode) { this.logDebugSystemExecution(); } this.collectExecutionStatus(); } /** * 收集所有节点的执行状态 */ private collectExecutionStatus(): void { if (!this.callback) return; const statuses: ExecutionStatus[] = []; this.entityMap.forEach((entity, nodeId) => { const btNode = entity.getComponent(BehaviorTreeNodeComponent); if (!btNode) return; let status: 'running' | 'success' | 'failure' | 'idle' = 'idle'; if (entity.hasComponent(ActiveNode)) { status = 'running'; } if (btNode.status === TaskStatus.Success) { status = 'success'; } else if (btNode.status === TaskStatus.Failure) { status = 'failure'; } else if (btNode.status === TaskStatus.Running) { status = 'running'; } // 检测状态变化并记录日志 const lastStatus = this.lastStatuses.get(nodeId); if (lastStatus !== status) { this.onNodeStatusChanged(nodeId, entity.name, lastStatus || 'idle', status, entity); this.lastStatuses.set(nodeId, status); } statuses.push({ nodeId, status }); }); // 收集LogOutput组件中的日志 if (this.rootEntity) { const logOutput = this.rootEntity.getComponent(LogOutput); if (logOutput && logOutput.messages.length > 0) { // 将LogOutput中的日志转换为ExecutionLog格式并添加到日志列表 logOutput.messages.forEach((msg) => { this.addLog( msg.message, msg.level === 'error' ? 'error' : msg.level === 'warn' ? 'warning' : 'info' ); }); // 清空已处理的日志 logOutput.clear(); } } // 获取当前黑板变量 const currentBlackboardVars = this.getBlackboardVariables(); this.callback(statuses, this.executionLogs, currentBlackboardVars); } /** * 节点状态变化时记录日志 */ private onNodeStatusChanged( nodeId: string, nodeName: string, oldStatus: string, newStatus: string, entity: Entity ): void { if (newStatus === 'running') { this.addLog(`[${nodeName}] 开始执行`, 'info', nodeId); } else if (newStatus === 'success') { // 检查是否是空的复合节点 // 排除动态加载子节点的节点(如 SubTreeNode),它们的子节点是运行时动态加载的 const btNode = entity.getComponent(BehaviorTreeNodeComponent); const hasDynamicChildren = entity.hasComponent(SubTreeNode); if (btNode && btNode.nodeType === NodeType.Composite && entity.children.length === 0 && !hasDynamicChildren) { this.addLog(`[${nodeName}] 执行成功(空节点,无子节点)`, 'warning', nodeId); } else { this.addLog(`[${nodeName}] 执行成功`, 'success', nodeId); } } else if (newStatus === 'failure') { this.addLog(`[${nodeName}] 执行失败`, 'error', nodeId); } } /** * 添加日志 */ private addLog(message: string, level: 'info' | 'success' | 'error' | 'warning', nodeId?: string): void { this.executionLogs.push({ timestamp: Date.now(), message, level, nodeId }); // 限制日志数量,避免内存泄漏 if (this.executionLogs.length > 1000) { this.executionLogs.shift(); } } /** * 获取当前tick计数 */ getTickCount(): number { return this.tickCount; } /** * 获取黑板变量 */ getBlackboardVariables(): Record { if (!this.rootEntity) return {}; const blackboard = this.rootEntity.getComponent(BlackboardComponent); if (!blackboard) return {}; const variables: Record = {}; const names = blackboard.getVariableNames(); names.forEach((name: string) => { variables[name] = blackboard.getValue(name); }); return variables; } /** * 更新黑板变量 */ updateBlackboardVariable(key: string, value: any): void { if (!this.rootEntity) { logger.warn('无法更新黑板变量:未构建行为树'); return; } const blackboard = this.rootEntity.getComponent(BlackboardComponent); if (!blackboard) { logger.warn('无法更新黑板变量:未找到黑板组件'); return; } if (!blackboard.hasVariable(key)) { logger.warn(`无法更新黑板变量:变量 "${key}" 不存在`); return; } blackboard.setValue(key, value); this.blackboardVariables[key] = value; logger.info(`黑板变量已更新: ${key} = ${JSON.stringify(value)}`); } /** * 记录树结构的 debug 信息 */ private logDebugTreeStructure(): void { if (!this.rootEntity) return; this.addLog('=== 行为树结构 Debug 信息 ===', 'info'); this.logEntityStructure(this.rootEntity, 0); this.addLog('=== Debug 信息结束 ===', 'info'); } /** * 递归记录实体结构 */ private logEntityStructure(entity: Entity, depth: number): void { const indent = ' '.repeat(depth); const nodeId = Array.from(this.entityMap.entries()).find(([_, e]) => e === entity)?.[0] || 'unknown'; const btNode = entity.getComponent(BehaviorTreeNodeComponent); // 获取节点的具体类型组件 const allComponents = entity.components.map(c => c.constructor.name); const nodeTypeComponent = allComponents.find(name => name !== 'BehaviorTreeNode' && name !== 'ActiveNode' && name !== 'BlackboardComponent' && name !== 'LogOutput' && name !== 'PropertyBindings' ) || 'Unknown'; // 构建节点显示名称 let nodeName = entity.name; if (nodeTypeComponent !== 'Unknown') { nodeName = `${nodeName} [${nodeTypeComponent}]`; } this.addLog( `${indent}└─ ${nodeName} (id: ${nodeId})`, 'info' ); // 检查是否是 SubTreeNode,如果是则显示子树内部结构 const subTreeNode = entity.getComponent(SubTreeNode); if (subTreeNode) { const subTreeRoot = subTreeNode.getSubTreeRoot(); if (subTreeRoot) { this.addLog(`${indent} [SubTree] 资产ID: ${subTreeNode.assetId}`, 'info'); this.addLog(`${indent} [SubTree] 内部结构:`, 'info'); this.logEntityStructure(subTreeRoot, depth + 1); } else { this.addLog(`${indent} [SubTree] 资产ID: ${subTreeNode.assetId} (未加载)`, 'info'); } } if (entity.children.length > 0) { this.addLog(`${indent} 子节点数: ${entity.children.length}`, 'info'); entity.children.forEach((child: Entity) => { this.logEntityStructure(child, depth + 1); }); } else if (btNode && (btNode.nodeType === NodeType.Decorator || btNode.nodeType === NodeType.Composite)) { // SubTreeNode 是特殊情况,不需要静态子节点 if (!subTreeNode) { this.addLog(`${indent} ⚠ 警告: 此节点应该有子节点`, 'warning'); } } } /** * 记录系统执行的 debug 信息 */ private logDebugSystemExecution(): void { if (!this.rootEntity) return; const activeEntities: Entity[] = []; this.entityMap.forEach((entity) => { if (entity.hasComponent(ActiveNode)) { activeEntities.push(entity); } }); if (activeEntities.length > 0) { this.addLog(`活跃节点数: ${activeEntities.length}`, 'info'); activeEntities.forEach((entity) => { const nodeId = Array.from(this.entityMap.entries()).find(([_, e]) => e === entity)?.[0]; const btNode = entity.getComponent(BehaviorTreeNodeComponent); // 显示该节点的详细信息 const components = entity.components.map(c => c.constructor.name).join(', '); this.addLog( ` - [${entity.name}] status=${btNode?.status}, nodeType=${btNode?.nodeType}, children=${entity.children.length}`, 'info', nodeId ); this.addLog(` 组件: ${components}`, 'info', nodeId); // 显示子节点状态 if (entity.children.length > 0) { entity.children.forEach((child: Entity, index: number) => { const childBtNode = child.getComponent(BehaviorTreeNodeComponent); const childActive = child.hasComponent(ActiveNode); this.addLog( ` 子节点${index}: [${child.name}] status=${childBtNode?.status}, active=${childActive}`, 'info', nodeId ); }); } }); } } /** * 清理资源 */ cleanup(): void { this.stop(); this.entityMap.clear(); this.propertyBindingsMap.clear(); this.rootEntity = null; this.scene.destroyAllEntities(); } /** * 销毁 */ destroy(): void { this.cleanup(); } }