Files
esengine/docs/guide/behavior-tree/editor-workflow.md

241 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 编辑器工作流
本教程介绍如何使用行为树编辑器创建AI并在游戏中加载使用。
## 完整流程
```
1. 启动编辑器
2. 创建行为树并定义黑板变量
3. 添加和配置节点
4. 导出JSON文件
5. 在游戏中加载并使用
```
## 使用编辑器创建
### 启动编辑器
```bash
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)
```
## 在游戏中加载
### 加载JSON资产
```typescript
import { Core, Scene } from '@esengine/ecs-framework';
import {
BehaviorTreePlugin,
BehaviorTreeAssetSerializer,
BehaviorTreeAssetLoader,
BehaviorTreeStarter
} from '@esengine/behavior-tree';
// 初始化
Core.create();
const plugin = new BehaviorTreePlugin();
await Core.installPlugin(plugin);
const scene = new Scene();
plugin.setupScene(scene);
Core.setScene(scene);
// 加载行为树
const jsonString = await loadJsonFromFile('enemy-ai.btree.json');
const asset = BehaviorTreeAssetSerializer.deserialize(jsonString);
const aiEntity = BehaviorTreeAssetLoader.instantiate(asset, scene);
// 设置黑板初始值
const blackboard = aiEntity.getComponent(BlackboardComponent);
blackboard?.setValue('health', 100);
blackboard?.setValue('moveSpeed', 5.0);
// 启动AI
BehaviorTreeStarter.start(aiEntity);
// 游戏循环
setInterval(() => {
Core.update(0.016); // 60 FPS
}, 16);
```
## 实现自定义动作
编辑器中的ExecuteAction节点需要在代码中提供实际逻辑。有两种方式
### 方式1通过事件系统推荐
在Action节点中触发事件在游戏代码中监听
```typescript
// 在编辑器的ExecuteAction节点中
entity.scene?.eventSystem.emit('ai:attack', {
attacker: entity,
target: blackboard?.getValue('target')
});
return TaskStatus.Success;
```
```typescript
// 在游戏代码中监听
Core.scene.eventSystem.on('ai:attack', (data) => {
const { attacker, target } = data;
// 执行实际的攻击逻辑
performAttack(attacker, target);
});
```
### 方式2创建自定义组件
创建专用的Action组件详见[自定义动作](./custom-actions.md)
```typescript
import { Component, ECSComponent, Entity } from '@esengine/ecs-framework';
import { BehaviorNode, BehaviorProperty, NodeType, TaskStatus } from '@esengine/behavior-tree';
@BehaviorNode({
displayName: '攻击目标',
category: '战斗',
type: NodeType.Action,
description: '对目标造成伤害'
})
@ECSComponent('AttackAction')
export class AttackAction extends Component {
@BehaviorProperty({
label: '伤害值',
type: 'number'
})
damage: number = 10;
execute(entity: Entity, blackboard?: BlackboardComponent): TaskStatus {
const target = blackboard?.getValue('target');
if (!target) return TaskStatus.Failure;
// 执行攻击逻辑
performAttack(entity, target, this.damage);
return TaskStatus.Success;
}
}
```
## 调试技巧
### 1. 使用日志
在编辑器中添加Log节点输出调试信息
```typescript
.log('进入战斗分支', 'info')
.action('Attack', (entity, blackboard) => {
console.log('目标:', blackboard?.getValue('target'));
return TaskStatus.Success;
})
```
### 2. 监控黑板
```typescript
const blackboard = aiEntity.getComponent(BlackboardComponent);
console.log('黑板状态:', blackboard?.getAllVariables());
```
### 3. 检查节点状态
```typescript
const node = aiEntity.getComponent(BehaviorTreeNode);
console.log('节点状态:', node?.status);
```
## 完整示例
```typescript
import { Core, Scene, Entity } from '@esengine/ecs-framework';
import {
BehaviorTreePlugin,
BehaviorTreeBuilder,
BehaviorTreeStarter,
BlackboardValueType,
TaskStatus
} from '@esengine/behavior-tree';
// 初始化
Core.create();
const plugin = new BehaviorTreePlugin();
await Core.installPlugin(plugin);
const scene = new Scene();
plugin.setupScene(scene);
Core.setScene(scene);
// 直接用代码构建(不用编辑器)
const aiEntity = BehaviorTreeBuilder.create(scene, 'EnemyAI')
.blackboard()
.defineVariable('health', BlackboardValueType.Number, 100)
.defineVariable('hasTarget', BlackboardValueType.Boolean, false)
.endBlackboard()
.selector('Root')
.sequence('Combat')
.condition((e, bb) => bb?.getValue('hasTarget') === true, 'CheckTarget')
.action('Attack', (e, bb) => {
console.log('攻击!');
return TaskStatus.Success;
})
.end()
.action('Idle', () => {
console.log('空闲');
return TaskStatus.Success;
})
.end()
.build();
BehaviorTreeStarter.start(aiEntity);
// 游戏循环
setInterval(() => {
Core.update(0.016);
}, 16);
```
## 下一步
- 查看[自定义动作](./custom-actions.md)学习如何创建专用的Action组件
- 查看[高级用法](./advanced-usage.md)了解子树、异步操作等高级特性
- 查看[最佳实践](./best-practices.md)优化你的AI设计