Files
esengine/docs/guide/behavior-tree/editor-workflow.md
yhh ad96edfad0 fix: 恢复 @esengine/ecs-framework 包名
上一个提交错误地将 npm 包名也改了,这里恢复正确的包名。
只更新 GitHub 仓库 URL,不改变 npm 包名。
2025-12-08 21:26:35 +08:00

6.2 KiB
Raw Blame History

编辑器工作流

本教程介绍如何使用行为树编辑器创建AI并在游戏中加载使用。

完整流程

1. 启动编辑器
2. 创建行为树并定义黑板变量
3. 添加和配置节点
4. 导出JSON文件
5. 在游戏中加载并使用

使用编辑器创建

启动编辑器

cd packages/editor-app
npm run tauri:dev

基本操作

  1. 创建行为树文件新建项目 → 创建行为树文件
  2. 定义黑板变量:在黑板面板中添加共享变量
  3. 添加节点:从节点面板拖拽到画布
  4. 连接节点:拖拽连接点建立父子关系
  5. 配置属性:选中节点后在属性面板编辑
  6. 导出文件导出JSON格式

示例敌人AI的黑板变量

在编辑器黑板面板中定义:

health: Number = 100
target: Object = null
moveSpeed: Number = 5.0
attackRange: Number = 2.0

示例:行为树结构

Root: Selector
├── Combat Sequence
│   ├── CheckHasTarget (Condition)
│   ├── CheckInAttackRange (Condition)
│   └── ExecuteAttack (Action)
├── Patrol Sequence
│   ├── MoveToNextPatrolPoint (Action)
│   └── Wait 2s
└── Idle (Action)

在游戏中使用

使用Builder API创建

推荐使用Builder API在代码中创建行为树

import { Core, Scene } from '@esengine/ecs-framework';
import {
    BehaviorTreePlugin,
    BehaviorTreeBuilder,
    BehaviorTreeStarter,
    BehaviorTreeRuntimeComponent
} from '@esengine/behavior-tree';

// 初始化
Core.create();
const plugin = new BehaviorTreePlugin();
await Core.installPlugin(plugin);

const scene = new Scene();
plugin.setupScene(scene);
Core.setScene(scene);

// 使用Builder创建行为树
const tree = BehaviorTreeBuilder.create('EnemyAI')
    .defineBlackboardVariable('health', 100)
    .defineBlackboardVariable('target', null)
    .defineBlackboardVariable('moveSpeed', 5.0)
    .selector('MainBehavior')
        .sequence('AttackBranch')
            .blackboardExists('target')
            .blackboardCompare('health', 30, 'greater')
            .log('攻击目标', 'Attack')
        .end()
        .log('巡逻', 'Patrol')
    .end()
    .build();

// 创建实体并启动行为树
const entity = scene.createEntity('Enemy');
BehaviorTreeStarter.start(entity, tree);

// 访问和修改黑板
const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
runtime?.setBlackboardValue('target', someTarget);

// 游戏循环
setInterval(() => {
    Core.update(0.016); // 60 FPS
}, 16);

实现自定义执行器

要扩展行为树的功能,需要创建自定义执行器(详见自定义节点执行器

import {
    INodeExecutor,
    NodeExecutionContext,
    BindingHelper,
    NodeExecutorMetadata
} from '@esengine/behavior-tree';
import { TaskStatus, NodeType } from '@esengine/behavior-tree';

@NodeExecutorMetadata({
    implementationType: 'AttackAction',
    nodeType: NodeType.Action,
    displayName: '攻击目标',
    description: '对目标造成伤害',
    category: '战斗',
    configSchema: {
        damage: {
            type: 'number',
            default: 10,
            supportBinding: true
        }
    }
})
export class AttackAction implements INodeExecutor {
    execute(context: NodeExecutionContext): TaskStatus {
        const damage = BindingHelper.getValue<number>(context, 'damage', 10);
        const target = context.runtime.getBlackboardValue('target');

        if (!target) {
            return TaskStatus.Failure;
        }

        // 执行攻击逻辑
        performAttack(context.entity, target, damage);
        return TaskStatus.Success;
    }

    reset(context: NodeExecutionContext): void {
        // 清理状态
    }
}

调试技巧

1. 使用日志节点

在行为树中添加Log节点输出调试信息

const tree = BehaviorTreeBuilder.create('DebugAI')
    .log('开始战斗序列', 'StartCombat')
    .sequence('Combat')
        .blackboardCompare('health', 0, 'greater')
        .log('执行攻击', 'Attack')
    .end()
    .build();

2. 监控黑板状态

const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
console.log('黑板变量:', runtime?.getAllBlackboardVariables());
console.log('活动节点:', Array.from(runtime?.activeNodeIds || []));

3. 在自定义执行器中调试

export class DebugAction implements INodeExecutor {
    execute(context: NodeExecutionContext): TaskStatus {
        const { nodeData, runtime, state } = context;

        console.group(`[${nodeData.name}]`);
        console.log('配置:', nodeData.config);
        console.log('状态:', state);
        console.log('黑板:', runtime.getAllBlackboardVariables());
        console.groupEnd();

        return TaskStatus.Success;
    }
}

完整示例

import { Core, Scene } from '@esengine/ecs-framework';
import {
    BehaviorTreePlugin,
    BehaviorTreeBuilder,
    BehaviorTreeStarter,
    BehaviorTreeRuntimeComponent
} from '@esengine/behavior-tree';

// 初始化
Core.create();
const plugin = new BehaviorTreePlugin();
await Core.installPlugin(plugin);

const scene = new Scene();
plugin.setupScene(scene);
Core.setScene(scene);

// 使用Builder API构建行为树
const tree = BehaviorTreeBuilder.create('EnemyAI')
    .defineBlackboardVariable('health', 100)
    .defineBlackboardVariable('hasTarget', false)
    .selector('Root')
        .sequence('Combat')
            .blackboardCompare('hasTarget', true, 'equals')
            .log('攻击玩家', 'Attack')
        .end()
        .log('空闲', 'Idle')
    .end()
    .build();

// 创建实体并启动
const entity = scene.createEntity('Enemy');
BehaviorTreeStarter.start(entity, tree);

// 模拟发现目标
setTimeout(() => {
    const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
    runtime?.setBlackboardValue('hasTarget', true);
}, 2000);

// 游戏循环
setInterval(() => {
    Core.update(0.016);
}, 16);

下一步