更新rts示例代码(矿工自动采矿)

This commit is contained in:
YHH
2025-06-24 23:51:59 +08:00
parent 0f18a1979e
commit 01084a8897
27 changed files with 1561 additions and 8904 deletions

View File

@@ -1,122 +0,0 @@
# 行为树 RTS 演示项目
这是一个展示`@esengine/ai`行为树系统在RTS游戏中应用的完整演示项目。
## 项目概述
该演示项目展示了如何在Cocos Creator 3D环境中使用行为树系统创建智能的RTS单位AI。项目包含三种不同类型的单位每种都有独特的行为模式和AI策略。
## 单位类型
### 1. 工人 (Worker)
- **文件**: `worker-ai.btree`, `worker-ai.bt.json`
- **特点**: 专注于资源收集、建造和修理
- **行为优先级**: 紧急情况 > 命令执行 > 空闲行为
- **主要功能**:
- 资源收集和运输
- 建筑建造
- 结构修理
- 自动寻找附近资源
- 生命值过低时撤退
### 2. 士兵 (Soldier)
- **文件**: `soldier-ai.btree`, `soldier-ai.bt.json`
- **特点**: 专注于战斗、防御和战术行动
- **行为优先级**: 战斗 > 命令执行 > 防御行为
- **主要功能**:
- 近战和远程攻击
- 敌人检测和交战
- 战术移动和撤退
- 区域防御和巡逻
- 队形保持
### 3. 侦察兵 (Scout)
- **文件**: `scout-ai.btree`, `scout-ai.bt.json`
- **特点**: 专注于探索、侦察和信息收集
- **行为优先级**: 生存 > 命令执行 > 自主侦察
- **主要功能**:
- 区域探索和侦察
- 威胁检测和规避
- 隐蔽移动和撤退
- 情报收集和报告
- 自主探索未知区域
## 技术特点
### 行为树设计
- **选择器(Selector)**: 根据优先级选择行为分支
- **序列器(Sequence)**: 按顺序执行一系列行为
- **条件装饰器(Conditional Decorator)**: 基于条件执行子节点
- **事件动作(Event Action)**: 执行具体的游戏行为
- **等待动作(Wait Action)**: 添加时间延迟
### 黑板系统
每个单位都有独立的黑板变量,用于存储和共享状态信息:
- 单位属性(生命值、移动速度、攻击力等)
- 状态标志(是否移动、是否有目标等)
- 位置信息(当前位置、目标位置等)
- 特殊能力(隐蔽、战斗模式等)
### 文件格式
#### .btree 文件(编辑器格式)
- 包含完整的编辑器状态和元数据
- 包含节点位置、连接关系、属性配置
- 包含黑板变量定义和初始值
- 支持编辑器的撤销/重做、剪贴板等功能
#### .bt.json 文件(运行时格式)
- 精简的运行时格式,只包含游戏所需的核心数据
- 优化的数据结构,适合快速加载和执行
- 移除了编辑器相关的元数据
## 代码结构
### 核心组件
- **RTSDemo.ts**: 主控制器,管理整个演示场景
- **UnitController.ts**: 单位控制器,管理单位的基本行为和状态
- **BehaviorTreeManager.ts**: 行为树管理器,集成`@esengine/ai`系统
- **RTSCameraController.ts**: RTS相机控制器
- **UIController.ts**: 用户界面控制器
### 关键特性
- **纯Cocos Creator实现**: 不依赖其他框架,专注展示行为树功能
- **实时状态同步**: 单位状态自动同步到行为树黑板
- **命令系统**: 支持移动、攻击、收集、巡逻等RTS命令
- **可视化调试**: 实时显示单位状态和行为信息
## 使用方法
### 1. 在行为树编辑器中
1. 打开对应的`.btree`文件进行编辑
2. 修改节点逻辑、添加新行为或调整优先级
3. 导出为`.bt.json`文件供游戏运行时使用
### 2. 在游戏中
1. 运行场景观察不同单位的AI行为
2. 使用UI按钮发布命令测试单位响应
3. 观察单位在不同情况下的行为切换
### 3. 扩展开发
- 添加新的行为节点类型
- 创建更复杂的AI策略
- 集成更多游戏机制(资源系统、建筑系统等)
## 演示价值
这个项目完整展示了:
1. **行为树在RTS游戏中的实际应用**
2. **不同单位类型的AI差异化设计**
3. **复杂游戏逻辑的行为树实现方式**
4. **黑板系统在状态管理中的作用**
5. **行为树编辑器与游戏运行时的集成**
## 技术亮点
- **模块化设计**: 每个单位类型独立的行为树设计
- **优先级系统**: 清晰的行为优先级和决策逻辑
- **状态管理**: 完善的黑板变量系统
- **实时调试**: 支持运行时状态监控和调试
- **可扩展性**: 易于添加新的单位类型和行为
这个演示项目可以作为学习行为树系统的完整案例也可以作为实际RTS游戏开发的起点。

View File

@@ -1,165 +0,0 @@
# 行为树游戏演示文档
## 概述
本演示展示了两个真实游戏场景的行为树AI系统
1. **RPG角色AI** (`rpg-character-ai.btree`) - 智能RPG角色行为系统
2. **RTS单位AI** (`rts-unit-ai.btree`) - 智能RTS单位行为系统
这些行为树使用编辑器格式(`.btree`),可以在行为树编辑器中打开、编辑和可视化。
## 行为树详解
### 1. RPG角色AI (`rpg-character-ai.btree`)
**优先级系统**:生存 > 战斗 > 任务 > 探索 > 休息
#### 主要行为模式:
1. **生存行为**(最高优先级)
- 触发条件:生命值 < 30
- 行为:使用治疗物品 → 逃跑到安全区域
- 确保角色在危险时优先保命
2. **战斗行为**
- 触发条件:发现敌人
- 智能攻击选择:
- 远程攻击:距离 > 5 时使用弓箭
- 近战攻击:距离 ≤ 2 时使用剑
- 魔法攻击:魔法值 > 20 时释放法术
3. **任务行为**
- 触发条件:有活跃任务
- 任务类型收集物品、与NPC对话、前往指定地点
4. **探索行为**
- 无紧急事务时进行
- 活动:寻找宝藏、收集资源
5. **休息行为**(最低优先级)
- 默认行为:恢复生命值、修理装备
#### 黑板变量:
- `hasEnemy`: 是否发现敌人
- `hasActiveQuest`: 是否有活跃任务
- `character.health`: 角色生命值
- `character.mana`: 角色魔法值
- `character.distanceToEnemy`: 与敌人的距离
### 2. RTS单位AI (`rts-unit-ai.btree`)
**优先级系统**:紧急防御 > 战斗 > 建造 > 资源收集 > 巡逻
#### 主要行为模式:
1. **紧急防御**(最高优先级)
- 触发条件:基地受到攻击
- 行为:立即返回基地 → 参与基地防御
- 确保基地安全是最高优先级
2. **战斗行为**
- 触发条件:发现敌方目标
- 行为:锁定目标 → 攻击目标
- 主动寻找并消灭敌人
3. **建造行为**
- 触发条件:有建造任务
- 行为:前往建造地点 → 执行建造
- 按指令建造建筑物
4. **资源收集行为**
- 默认经济行为
- 行为:寻找资源 → 收集资源 → 运送回基地
- 为基地提供经济支持
5. **巡逻行为**(最低优先级)
- 空闲时的默认行为
- 行为:沿路线巡逻 → 扫描周围区域
- 保持警戒状态
#### 黑板变量:
- `baseUnderAttack`: 基地是否受到攻击
- `hasTarget`: 是否发现敌方目标
- `hasBuildOrder`: 是否有建造任务
## 演示脚本
### RealisticGameDemo.ts
演示脚本展示了RPG角色AI的完整功能
#### 功能特性:
- **实时状态显示**:生命值、魔法值、敌人状态、任务状态
- **交互式事件触发**
- 低生命值按钮:模拟角色受伤
- 敌人按钮:切换敌人发现状态
- 任务按钮:切换任务状态
- 重置按钮:恢复初始状态
- **实时日志系统**显示AI决策和行为执行过程
- **智能行为响应**AI根据状态变化自动调整行为
#### 事件处理器:
- 治疗物品使用恢复30点生命值
- 逃跑行为:移除敌人威胁,增加距离
- 各种攻击方式:消耗不同的魔法值
- 任务相关行为:模拟真实游戏交互
- 探索和休息:提供持续的角色发展
## 使用指南
### 1. 在编辑器中打开
1. 启动Cocos Creator
2. 打开行为树编辑器扩展
3. 加载 `assets/resources/rpg-character-ai.btree``rts-unit-ai.btree`
4. 可视化查看和编辑行为树结构
### 2. 在游戏中运行
1.`RealisticGameDemo` 组件添加到场景节点
2. 配置UI组件
- 状态标签:显示角色当前状态
- 日志标签:显示行为执行日志
- 控制按钮:触发不同的游戏事件
3. 运行场景观察AI行为
### 3. 自定义和扩展
#### 添加新的行为节点:
1. 在编辑器中添加新的事件动作节点
2. 在演示脚本中注册对应的事件处理器
3. 实现具体的行为逻辑
#### 修改优先级:
1. 在编辑器中调整选择器节点的子节点顺序
2. 更高位置的节点具有更高优先级
#### 添加新的条件:
1. 在黑板中定义新的变量
2. 为条件装饰器配置相应的条件检查
3. 在代码中更新黑板变量值
## 实际游戏应用
### RPG游戏中的应用
- **NPC AI**为游戏中的NPC提供智能行为
- **伙伴AI**:玩家队友的自动战斗和支援行为
- **敌人AI**:敌人的智能战斗和逃跑策略
- **宠物AI**:宠物的跟随、战斗和辅助行为
### RTS游戏中的应用
- **单位AI**:军事单位的自动化行为
- **工人AI**:资源收集和建造单位的智能调度
- **防御AI**:自动防御系统的智能响应
- **经济AI**:自动化的经济发展策略
## 学习要点
1. **优先级设计**合理的优先级确保AI在复杂情况下做出正确决策
2. **状态管理**通过黑板系统有效管理AI状态
3. **事件驱动**:使用事件系统实现松耦合的行为实现
4. **条件判断**智能的条件系统让AI能够适应不同情况
5. **模块化设计**:每个行为模块独立,便于维护和扩展
这些行为树演示了如何构建商业级游戏AI系统为开发者提供了完整的参考实现。

View File

@@ -0,0 +1,111 @@
{
"name": "miner-ai",
"description": "简化版矿工AI - 挖矿存储循环",
"blackboard": {
"variables": [
{
"name": "unitType",
"type": "string",
"value": "miner",
"group": "基础属性",
"description": "单位类型"
},
{
"name": "currentCommand",
"type": "string",
"value": "mine",
"group": "命令状态",
"description": "当前命令"
},
{
"name": "hasOre",
"type": "boolean",
"value": false,
"group": "工作状态",
"description": "是否携带矿石"
},
{
"name": "targetPosition",
"type": "vector3",
"value": null,
"group": "移动属性",
"description": "目标位置"
},
{
"name": "hasTarget",
"type": "boolean",
"value": false,
"group": "移动属性",
"description": "是否有目标"
},
{
"name": "isMoving",
"type": "boolean",
"value": false,
"group": "移动属性",
"description": "是否正在移动"
},
{
"name": "currentHealth",
"type": "number",
"value": 100,
"group": "基础属性",
"description": "当前生命值"
},
{
"name": "maxHealth",
"type": "number",
"value": 100,
"group": "基础属性",
"description": "最大生命值"
}
]
},
"root": {
"type": "selector",
"name": "矿工主选择器",
"children": [
{
"type": "sequence",
"name": "存储矿石序列",
"children": [
{
"type": "blackboard-value-comparison",
"name": "检查是否携带矿石",
"variable": "hasOre",
"operator": "==",
"value": true
},
{
"type": "execute-action",
"name": "前往仓库存储",
"action": "store-ore"
}
]
},
{
"type": "sequence",
"name": "挖矿序列",
"children": [
{
"type": "blackboard-value-comparison",
"name": "检查是否没有矿石",
"variable": "hasOre",
"operator": "==",
"value": false
},
{
"type": "execute-action",
"name": "寻找并挖掘矿石",
"action": "find-and-mine-ore"
}
]
},
{
"type": "execute-action",
"name": "默认待机",
"action": "idle-behavior"
}
]
}
}

View File

@@ -2,7 +2,7 @@
"ver": "2.0.1", "ver": "2.0.1",
"importer": "json", "importer": "json",
"imported": true, "imported": true,
"uuid": "59141420-59cc-425f-b519-1073df8b93f8", "uuid": "7ecbbfe3-a63f-4558-89e2-85e3f084ee02",
"files": [ "files": [
".json" ".json"
], ],

View File

@@ -0,0 +1,454 @@
{
"nodes": [
{
"id": "root",
"type": "root",
"name": "矿工AI根节点",
"position": {
"x": 400,
"y": 100
},
"properties": {},
"children": [
"main-selector"
],
"canHaveChildren": true,
"canHaveParent": false,
"hasError": false
},
{
"id": "main-selector",
"type": "selector",
"name": "矿工主选择器",
"position": {
"x": 400,
"y": 200
},
"properties": {
"description": {
"name": "描述",
"type": "string",
"value": "矿工主要行为选择:有矿石就存储,没矿石就挖矿,否则待机",
"required": false
}
},
"children": [
"store-conditional",
"mine-conditional",
"idle-action"
],
"canHaveChildren": true,
"canHaveParent": true,
"hasError": false
},
{
"id": "store-conditional",
"type": "conditional-decorator",
"name": "检查是否携带矿石",
"position": {
"x": 200,
"y": 250
},
"properties": {
"conditionType": {
"name": "条件类型",
"type": "string",
"value": "blackboardCompare",
"description": "条件判断类型",
"required": false
},
"executeWhenTrue": {
"name": "条件为真时执行",
"type": "boolean",
"value": true,
"description": "条件为真时是否执行子节点",
"required": false
},
"executeWhenFalse": {
"name": "条件为假时执行",
"type": "boolean",
"value": false,
"description": "条件为假时是否执行子节点",
"required": false
},
"checkInterval": {
"name": "检查间隔",
"type": "number",
"value": 0,
"description": "条件检查间隔时间0表示每帧检查",
"required": false
},
"abortType": {
"name": "中止类型",
"type": "select",
"value": "None",
"description": "决定节点在何种情况下会被中止",
"options": ["None", "LowerPriority", "Self", "Both"],
"required": false
},
"shouldReevaluate": true,
"variableName": "hasOre",
"operator": "equal",
"compareValue": "true"
},
"children": [
"store-sequence"
],
"attachedCondition": {
"type": "blackboard-value-comparison",
"name": "黑板值比较",
"icon": "⚖️"
},
"conditionExpanded": false,
"canHaveChildren": true,
"canHaveParent": true,
"hasError": false
},
{
"id": "mine-conditional",
"type": "conditional-decorator",
"name": "检查是否没有矿石",
"position": {
"x": 400,
"y": 250
},
"properties": {
"conditionType": {
"name": "条件类型",
"type": "string",
"value": "blackboardCompare",
"description": "条件判断类型",
"required": false
},
"executeWhenTrue": {
"name": "条件为真时执行",
"type": "boolean",
"value": true,
"description": "条件为真时是否执行子节点",
"required": false
},
"executeWhenFalse": {
"name": "条件为假时执行",
"type": "boolean",
"value": false,
"description": "条件为假时是否执行子节点",
"required": false
},
"checkInterval": {
"name": "检查间隔",
"type": "number",
"value": 0,
"description": "条件检查间隔时间0表示每帧检查",
"required": false
},
"abortType": {
"name": "中止类型",
"type": "select",
"value": "None",
"description": "决定节点在何种情况下会被中止",
"options": ["None", "LowerPriority", "Self", "Both"],
"required": false
},
"shouldReevaluate": true,
"variableName": "hasOre",
"operator": "equal",
"compareValue": "false"
},
"children": [
"mine-sequence"
],
"attachedCondition": {
"type": "blackboard-value-comparison",
"name": "黑板值比较",
"icon": "⚖️"
},
"conditionExpanded": false,
"canHaveChildren": true,
"canHaveParent": true,
"hasError": false
},
{
"id": "store-sequence",
"type": "sequence",
"name": "存储矿石序列",
"position": {
"x": 200,
"y": 350
},
"properties": {
"description": {
"name": "description",
"type": "string",
"value": "去仓库存储矿石,然后设置状态为无矿石",
"required": false
}
},
"children": [
"store-ore-action",
"set-no-ore"
],
"canHaveChildren": true,
"canHaveParent": true,
"hasError": false
},
{
"id": "mine-sequence",
"type": "sequence",
"name": "挖矿序列",
"position": {
"x": 400,
"y": 350
},
"properties": {
"description": {
"name": "description",
"type": "string",
"value": "寻找并挖掘矿石,然后设置状态为有矿石",
"required": false
}
},
"children": [
"mine-ore-action",
"set-has-ore"
],
"canHaveChildren": true,
"canHaveParent": true,
"hasError": false
},
{
"id": "store-ore-action",
"type": "event-action",
"name": "前往仓库存储",
"position": {
"x": 150,
"y": 450
},
"properties": {
"eventName": {
"name": "事件名称",
"type": "string",
"value": "store-ore",
"description": "要执行的事件名称",
"required": true
},
"parameters": {
"name": "事件参数",
"type": "string",
"value": "{}",
"description": "传递给事件处理函数的参数JSON格式",
"required": false
},
"timeout": {
"name": "超时时间",
"type": "number",
"value": 0,
"description": "事件执行超时时间0表示无限制",
"required": false
}
},
"children": [],
"canHaveChildren": false,
"canHaveParent": true,
"hasError": false
},
{
"id": "set-no-ore",
"type": "set-blackboard-value",
"name": "设置无矿石状态",
"position": {
"x": 250,
"y": 450
},
"properties": {
"variableName": {
"name": "变量名",
"type": "string",
"value": "hasOre",
"description": "黑板变量名",
"required": true
},
"value": {
"name": "设置值",
"type": "string",
"value": "false",
"description": "要设置的值(留空则使用源变量)",
"required": false
},
"force": {
"name": "强制设置",
"type": "boolean",
"value": false,
"description": "是否忽略只读限制",
"required": false
}
},
"children": [],
"canHaveChildren": false,
"canHaveParent": true,
"hasError": false
},
{
"id": "mine-ore-action",
"type": "event-action",
"name": "寻找并挖掘矿石",
"position": {
"x": 350,
"y": 450
},
"properties": {
"eventName": {
"name": "事件名称",
"type": "string",
"value": "find-and-mine-ore",
"description": "要执行的事件名称",
"required": true
},
"parameters": {
"name": "事件参数",
"type": "string",
"value": "{}",
"description": "传递给事件处理函数的参数JSON格式",
"required": false
},
"timeout": {
"name": "超时时间",
"type": "number",
"value": 0,
"description": "事件执行超时时间0表示无限制",
"required": false
}
},
"children": [],
"canHaveChildren": false,
"canHaveParent": true,
"hasError": false
},
{
"id": "set-has-ore",
"type": "set-blackboard-value",
"name": "设置有矿石状态",
"position": {
"x": 450,
"y": 450
},
"properties": {
"variableName": {
"name": "变量名",
"type": "string",
"value": "hasOre",
"description": "黑板变量名",
"required": true
},
"value": {
"name": "设置值",
"type": "string",
"value": "true",
"description": "要设置的值(留空则使用源变量)",
"required": false
},
"force": {
"name": "强制设置",
"type": "boolean",
"value": false,
"description": "是否忽略只读限制",
"required": false
}
},
"children": [],
"canHaveChildren": false,
"canHaveParent": true,
"hasError": false
},
{
"id": "idle-action",
"type": "event-action",
"name": "默认待机",
"position": {
"x": 600,
"y": 250
},
"properties": {
"eventName": {
"name": "事件名称",
"type": "string",
"value": "idle-behavior",
"description": "要执行的事件名称",
"required": true
},
"parameters": {
"name": "事件参数",
"type": "string",
"value": "{}",
"description": "传递给事件处理函数的参数JSON格式",
"required": false
},
"timeout": {
"name": "超时时间",
"type": "number",
"value": 0,
"description": "事件执行超时时间0表示无限制",
"required": false
}
},
"children": [],
"canHaveChildren": false,
"canHaveParent": true,
"hasError": false
}
],
"connections": [],
"metadata": {
"name": "miner-ai",
"description": "矿工AI示例 - 展示条件装饰器的正确使用方式",
"version": "1.0",
"created": "2025-06-24T15:00:13.826Z"
},
"blackboard": [
{
"name": "unitType",
"type": "string",
"value": "miner",
"description": "单位类型 - 可拖拽到事件参数中",
"group": "基础属性"
},
{
"name": "hasOre",
"type": "boolean",
"value": false,
"description": "是否携带矿石 - 核心状态变量,被条件节点和设置节点使用",
"group": "工作状态"
},
{
"name": "currentHealth",
"type": "number",
"value": 100,
"description": "当前生命值 - 可拖拽用于健康检查条件",
"group": "基础属性"
},
{
"name": "maxHealth",
"type": "number",
"value": 100,
"description": "最大生命值",
"group": "基础属性"
},
{
"name": "targetPosition",
"type": "object",
"value": {
"x": 0,
"y": 0,
"z": 0
},
"description": "目标位置 - 移动系统使用",
"group": "移动属性"
},
{
"name": "isMoving",
"type": "boolean",
"value": false,
"description": "是否正在移动",
"group": "移动属性"
}
]
}

View File

@@ -2,7 +2,7 @@
"ver": "1.0.0", "ver": "1.0.0",
"importer": "*", "importer": "*",
"imported": true, "imported": true,
"uuid": "96872e28-7488-4d80-906b-edcc3511c84b", "uuid": "2dded9a7-03cd-465f-8419-7199e562c403",
"files": [ "files": [
".btree", ".btree",
".json" ".json"

View File

@@ -1,859 +0,0 @@
{
"nodes": [
{
"id": "root",
"type": "root",
"name": "侦察兵AI根节点",
"children": [
"main-selector"
]
},
{
"id": "main-selector",
"type": "selector",
"name": "主选择器",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "根据优先级选择行为:生存 > 命令执行 > 自主侦察",
"description": "",
"required": false
}
},
"children": [
"survival-sequence",
"command-sequence",
"autonomous-sequence"
]
},
{
"id": "survival-sequence",
"type": "sequence",
"name": "生存序列",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "处理威胁和生存相关行为",
"description": "",
"required": false
}
},
"children": [
"threat-detection",
"survival-selector"
]
},
{
"id": "threat-detection",
"type": "conditional-decorator",
"name": "威胁检测",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "检测周围是否有威胁",
"description": "",
"required": false
}
},
"children": [
"survival-selector"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "threatDetected",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "survival-selector",
"type": "selector",
"name": "生存选择器",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "选择合适的生存策略",
"description": "",
"required": false
}
},
"children": [
"stealth-escape",
"evasive-maneuver",
"emergency-retreat"
]
},
{
"id": "stealth-escape",
"type": "sequence",
"name": "隐蔽脱离",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "使用隐蔽能力脱离危险",
"description": "",
"required": false
}
},
"children": [
"can-stealth-check",
"activate-stealth",
"stealth-retreat"
]
},
{
"id": "can-stealth-check",
"type": "conditional-decorator",
"name": "隐蔽能力检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"activate-stealth"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "stealthAvailable",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "activate-stealth",
"type": "event-action",
"name": "激活隐蔽",
"properties": {
"eventName": "activate-stealth",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "激活隐蔽模式",
"description": "",
"required": false
}
}
},
{
"id": "stealth-retreat",
"type": "event-action",
"name": "隐蔽撤退",
"properties": {
"eventName": "stealth-retreat",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "在隐蔽状态下撤退",
"description": "",
"required": false
}
}
},
{
"id": "evasive-maneuver",
"type": "event-action",
"name": "规避机动",
"properties": {
"eventName": "evasive-maneuver",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "执行规避机动动作",
"description": "",
"required": false
}
}
},
{
"id": "emergency-retreat",
"type": "event-action",
"name": "紧急撤退",
"properties": {
"eventName": "emergency-retreat",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "快速撤退到安全区域",
"description": "",
"required": false
}
}
},
{
"id": "command-sequence",
"type": "sequence",
"name": "命令执行",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "执行玩家发布的侦察命令",
"description": "",
"required": false
}
},
"children": [
"has-command-check",
"command-selector"
]
},
{
"id": "has-command-check",
"type": "conditional-decorator",
"name": "命令检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "检查是否有待执行的命令",
"description": "",
"required": false
}
},
"children": [
"command-selector"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "hasTarget",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "command-selector",
"type": "selector",
"name": "命令选择器",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "根据命令类型选择执行方式",
"description": "",
"required": false
}
},
"children": [
"scout-command",
"move-command",
"observe-command",
"patrol-command"
]
},
{
"id": "scout-command",
"type": "sequence",
"name": "侦察命令",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "执行区域侦察任务",
"description": "",
"required": false
}
},
"children": [
"is-scout-command",
"scout-sequence"
]
},
{
"id": "is-scout-command",
"type": "conditional-decorator",
"name": "侦察命令检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"scout-sequence"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "scout"
}
}
},
{
"id": "scout-sequence",
"type": "sequence",
"name": "侦察序列",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "完整的侦察流程",
"description": "",
"required": false
}
},
"children": [
"approach-carefully",
"scan-area",
"report-findings"
]
},
{
"id": "approach-carefully",
"type": "event-action",
"name": "谨慎接近",
"properties": {
"eventName": "approach-carefully",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "谨慎接近目标区域",
"description": "",
"required": false
}
}
},
{
"id": "scan-area",
"type": "event-action",
"name": "扫描区域",
"properties": {
"eventName": "scan-area",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "扫描并记录区域信息",
"description": "",
"required": false
}
}
},
{
"id": "report-findings",
"type": "event-action",
"name": "报告发现",
"properties": {
"eventName": "report-findings",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "向指挥部报告侦察结果",
"description": "",
"required": false
}
}
},
{
"id": "move-command",
"type": "sequence",
"name": "移动命令",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "执行移动到目标位置",
"description": "",
"required": false
}
},
"children": [
"is-move-command",
"stealth-move"
]
},
{
"id": "is-move-command",
"type": "conditional-decorator",
"name": "移动命令检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"stealth-move"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "move"
}
}
},
{
"id": "stealth-move",
"type": "event-action",
"name": "隐蔽移动",
"properties": {
"eventName": "stealth-move",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "以隐蔽方式移动到目标位置",
"description": "",
"required": false
}
}
},
{
"id": "observe-command",
"type": "sequence",
"name": "观察命令",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "执行目标观察任务",
"description": "",
"required": false
}
},
"children": [
"is-observe-command",
"observe-target"
]
},
{
"id": "is-observe-command",
"type": "conditional-decorator",
"name": "观察命令检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"observe-target"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "observe"
}
}
},
{
"id": "observe-target",
"type": "event-action",
"name": "观察目标",
"properties": {
"eventName": "observe-target",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "持续观察指定目标",
"description": "",
"required": false
}
}
},
{
"id": "patrol-command",
"type": "sequence",
"name": "巡逻命令",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "执行区域巡逻",
"description": "",
"required": false
}
},
"children": [
"is-patrol-command",
"reconnaissance-patrol"
]
},
{
"id": "is-patrol-command",
"type": "conditional-decorator",
"name": "巡逻命令检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"reconnaissance-patrol"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "patrol"
}
}
},
{
"id": "reconnaissance-patrol",
"type": "event-action",
"name": "侦察巡逻",
"properties": {
"eventName": "reconnaissance-patrol",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "在指定区域进行侦察巡逻",
"description": "",
"required": false
}
}
},
{
"id": "autonomous-sequence",
"type": "sequence",
"name": "自主行为",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "没有命令时的自主侦察行为",
"description": "",
"required": false
}
},
"children": [
"autonomous-selector"
]
},
{
"id": "autonomous-selector",
"type": "selector",
"name": "自主选择器",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "选择自主行为模式",
"description": "",
"required": false
}
},
"children": [
"explore-unknown",
"monitor-area",
"return-to-base"
]
},
{
"id": "explore-unknown",
"type": "sequence",
"name": "探索未知区域",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "自主探索未知区域",
"description": "",
"required": false
}
},
"children": [
"has-unknown-area",
"explore-action"
]
},
{
"id": "has-unknown-area",
"type": "conditional-decorator",
"name": "未知区域检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"explore-action"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "hasUnknownArea",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "explore-action",
"type": "event-action",
"name": "探索行动",
"properties": {
"eventName": "explore-unknown-area",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "探索最近的未知区域",
"description": "",
"required": false
}
}
},
{
"id": "monitor-area",
"type": "sequence",
"name": "监控区域",
"properties": {
"abortType": "None",
"description": {
"name": "description",
"type": "string",
"value": "监控重要区域",
"description": "",
"required": false
}
},
"children": [
"has-monitoring-target",
"monitor-action"
]
},
{
"id": "has-monitoring-target",
"type": "conditional-decorator",
"name": "监控目标检查",
"properties": {
"conditionType": "custom",
"executeWhenTrue": true,
"executeWhenFalse": false,
"checkInterval": 0,
"abortType": "None"
},
"children": [
"monitor-action"
],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "hasMonitoringTarget",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "monitor-action",
"type": "event-action",
"name": "监控行动",
"properties": {
"eventName": "monitor-strategic-area",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "监控战略重要区域",
"description": "",
"required": false
}
}
},
{
"id": "return-to-base",
"type": "event-action",
"name": "返回基地",
"properties": {
"eventName": "return-to-base",
"parameters": "{}",
"timeout": 0,
"description": {
"name": "description",
"type": "string",
"value": "返回基地待命",
"description": "",
"required": false
}
}
}
],
"blackboard": [
{
"name": "unitType",
"type": "string",
"value": "scout",
"description": "单位类型"
},
{
"name": "currentHealth",
"type": "number",
"value": 80,
"description": "当前生命值"
},
{
"name": "maxHealth",
"type": "number",
"value": 80,
"description": "最大生命值"
},
{
"name": "threatDetected",
"type": "boolean",
"value": false,
"description": "是否检测到威胁"
},
{
"name": "stealthAvailable",
"type": "boolean",
"value": true,
"description": "隐蔽能力是否可用"
},
{
"name": "currentCommand",
"type": "string",
"value": "idle",
"description": "当前执行的命令"
},
{
"name": "hasTarget",
"type": "boolean",
"value": false,
"description": "是否有目标"
},
{
"name": "targetPosition",
"type": "object",
"value": {
"x": 0,
"y": 0,
"z": 0
},
"description": "目标位置"
},
{
"name": "hasUnknownArea",
"type": "boolean",
"value": true,
"description": "是否有未探索的区域"
},
{
"name": "hasMonitoringTarget",
"type": "boolean",
"value": false,
"description": "是否有需要监控的目标"
},
{
"name": "visionRange",
"type": "number",
"value": 8,
"description": "视野范围"
},
{
"name": "moveSpeed",
"type": "number",
"value": 5,
"description": "移动速度"
},
{
"name": "stealthDuration",
"type": "number",
"value": 10,
"description": "隐蔽持续时间"
},
{
"name": "detectionRadius",
"type": "number",
"value": 6,
"description": "威胁检测半径"
},
{
"name": "lastReportTime",
"type": "number",
"value": 0,
"description": "上次报告时间"
},
{
"name": "exploredAreas",
"type": "array",
"value": [],
"description": "已探索区域列表"
},
{
"name": "intelligenceData",
"type": "object",
"value": {},
"description": "收集的情报数据"
}
],
"metadata": {
"name": "behavior-tree",
"created": "2025-06-24T09:20:19.582Z",
"version": "1.0",
"exportType": "clean"
}
}

View File

@@ -1,11 +0,0 @@
{
"ver": "2.0.1",
"importer": "json",
"imported": true,
"uuid": "1fb4b238-4ceb-4daa-817a-ac745bf598ca",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,483 +0,0 @@
{
"id": "soldier-ai",
"name": "士兵AI行为树",
"description": "士兵单位的战斗AI系统包含攻击、防御、巡逻等军事行为",
"version": "1.0.0",
"author": "ECS Framework",
"nodes": [
{
"id": "root",
"type": "root",
"name": "士兵AI根节点",
"description": "士兵AI的根节点管理所有战斗行为",
"children": ["main-selector"]
},
{
"id": "main-selector",
"type": "selector",
"name": "主行为选择器",
"description": "按优先级选择士兵行为:撤退 > 战斗 > 巡逻 > 待命",
"children": ["retreat-behavior", "combat-behavior", "patrol-behavior", "standby-behavior"]
},
{
"id": "retreat-behavior",
"type": "conditional-decorator",
"name": "撤退行为",
"description": "生命值过低时撤退",
"children": ["retreat-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "shouldRetreat",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "retreat-sequence",
"type": "sequence",
"name": "撤退序列",
"description": "执行撤退的完整流程",
"children": ["set-retreat-state", "call-for-help", "retreat-move"]
},
{
"id": "set-retreat-state",
"type": "set-blackboard-value",
"name": "设置撤退状态",
"description": "将士兵状态设置为撤退",
"properties": {
"variableName": "currentState",
"value": "retreating"
}
},
{
"id": "call-for-help",
"type": "event-action",
"name": "呼叫支援",
"description": "向附近友军发出支援请求",
"properties": {
"eventName": "call-for-help"
}
},
{
"id": "retreat-move",
"type": "event-action",
"name": "撤退移动",
"description": "快速移动到安全区域",
"properties": {
"eventName": "retreat-to-safety"
}
},
{
"id": "combat-behavior",
"type": "conditional-decorator",
"name": "战斗行为",
"description": "发现敌人时进入战斗状态",
"children": ["combat-selector"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "hasEnemy",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "combat-selector",
"type": "selector",
"name": "战斗选择器",
"description": "根据距离选择战斗策略",
"children": ["ranged-attack", "close-combat", "chase-enemy"]
},
{
"id": "ranged-attack",
"type": "conditional-decorator",
"name": "远程攻击",
"description": "在远程攻击范围内时使用远程武器",
"children": ["ranged-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "isInRangedRange",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "ranged-sequence",
"type": "sequence",
"name": "远程攻击序列",
"description": "执行远程攻击的完整流程",
"children": ["aim-target", "ranged-cooldown-check", "fire-ranged"]
},
{
"id": "aim-target",
"type": "event-action",
"name": "瞄准目标",
"description": "瞄准敌方目标",
"properties": {
"eventName": "aim-at-target"
}
},
{
"id": "ranged-cooldown-check",
"type": "conditional-decorator",
"name": "远程冷却检查",
"description": "检查远程攻击冷却时间",
"children": ["execute-ranged"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "canRangedAttack",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "execute-ranged",
"type": "event-action",
"name": "执行远程攻击",
"description": "发射远程武器",
"properties": {
"eventName": "ranged-attack"
}
},
{
"id": "fire-ranged",
"type": "log-action",
"name": "远程攻击日志",
"description": "记录远程攻击",
"properties": {
"message": "士兵执行远程攻击"
}
},
{
"id": "close-combat",
"type": "conditional-decorator",
"name": "近战攻击",
"description": "在近战范围内时使用近战武器",
"children": ["melee-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "isInMeleeRange",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "melee-sequence",
"type": "sequence",
"name": "近战攻击序列",
"description": "执行近战攻击的完整流程",
"children": ["melee-cooldown-check", "execute-melee", "melee-log"]
},
{
"id": "melee-cooldown-check",
"type": "conditional-decorator",
"name": "近战冷却检查",
"description": "检查近战攻击冷却时间",
"children": ["melee-attack"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "canMeleeAttack",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "melee-attack",
"type": "event-action",
"name": "近战攻击",
"description": "执行近战攻击",
"properties": {
"eventName": "melee-attack"
}
},
{
"id": "execute-melee",
"type": "set-blackboard-value",
"name": "更新近战冷却",
"description": "重置近战攻击冷却时间",
"properties": {
"variableName": "lastMeleeTime",
"value": "currentTime"
}
},
{
"id": "melee-log",
"type": "log-action",
"name": "近战攻击日志",
"description": "记录近战攻击",
"properties": {
"message": "士兵执行近战攻击"
}
},
{
"id": "chase-enemy",
"type": "sequence",
"name": "追击敌人",
"description": "追击敌方目标",
"children": ["set-chase-state", "move-to-enemy"]
},
{
"id": "set-chase-state",
"type": "set-blackboard-value",
"name": "设置追击状态",
"description": "将士兵状态设置为追击",
"properties": {
"variableName": "currentState",
"value": "chasing"
}
},
{
"id": "move-to-enemy",
"type": "event-action",
"name": "移动到敌人",
"description": "快速移动到敌人位置",
"properties": {
"eventName": "move-to-target"
}
},
{
"id": "patrol-behavior",
"type": "conditional-decorator",
"name": "巡逻行为",
"description": "没有敌人时执行巡逻",
"children": ["patrol-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "patrol"
}
}
},
{
"id": "patrol-sequence",
"type": "sequence",
"name": "巡逻序列",
"description": "执行巡逻的完整流程",
"children": ["set-patrol-state", "patrol-move", "patrol-scan", "patrol-wait"]
},
{
"id": "set-patrol-state",
"type": "set-blackboard-value",
"name": "设置巡逻状态",
"description": "将士兵状态设置为巡逻",
"properties": {
"variableName": "currentState",
"value": "patrolling"
}
},
{
"id": "patrol-move",
"type": "event-action",
"name": "巡逻移动",
"description": "沿巡逻路线移动",
"properties": {
"eventName": "patrol-move"
}
},
{
"id": "patrol-scan",
"type": "event-action",
"name": "扫描敌人",
"description": "扫描周围是否有敌人",
"properties": {
"eventName": "scan-for-enemies"
}
},
{
"id": "patrol-wait",
"type": "wait-action",
"name": "巡逻等待",
"description": "在巡逻点等待",
"properties": {
"waitTime": 2.0
}
},
{
"id": "standby-behavior",
"type": "sequence",
"name": "待命行为",
"description": "默认的待命状态",
"children": ["set-standby-state", "standby-wait"]
},
{
"id": "set-standby-state",
"type": "set-blackboard-value",
"name": "设置待命状态",
"description": "将士兵状态设置为待命",
"properties": {
"variableName": "currentState",
"value": "standby"
}
},
{
"id": "standby-wait",
"type": "wait-action",
"name": "待命等待",
"description": "待命状态下等待",
"properties": {
"waitTime": 1.0
}
}
],
"blackboard": [
{
"name": "currentState",
"type": "string",
"value": "standby",
"description": "士兵当前状态standby、patrolling、chasing、attacking、retreating",
"group": "状态"
},
{
"name": "currentCommand",
"type": "string",
"value": "patrol",
"description": "当前接收的命令patrol、attack、defend、move、standby",
"group": "命令"
},
{
"name": "hasEnemy",
"type": "boolean",
"value": false,
"description": "是否发现敌人",
"group": "战斗"
},
{
"name": "enemyDistance",
"type": "number",
"value": 999,
"description": "与最近敌人的距离",
"group": "战斗"
},
{
"name": "isInMeleeRange",
"type": "boolean",
"value": false,
"description": "是否在近战攻击范围内",
"group": "战斗"
},
{
"name": "isInRangedRange",
"type": "boolean",
"value": false,
"description": "是否在远程攻击范围内",
"group": "战斗"
},
{
"name": "canMeleeAttack",
"type": "boolean",
"value": true,
"description": "是否可以进行近战攻击(冷却检查)",
"group": "战斗"
},
{
"name": "canRangedAttack",
"type": "boolean",
"value": true,
"description": "是否可以进行远程攻击(冷却检查)",
"group": "战斗"
},
{
"name": "lastMeleeTime",
"type": "number",
"value": 0,
"description": "上次近战攻击时间",
"group": "战斗"
},
{
"name": "lastRangedTime",
"type": "number",
"value": 0,
"description": "上次远程攻击时间",
"group": "战斗"
},
{
"name": "meleeCooldown",
"type": "number",
"value": 1.0,
"description": "近战攻击冷却时间",
"group": "属性"
},
{
"name": "rangedCooldown",
"type": "number",
"value": 2.0,
"description": "远程攻击冷却时间",
"group": "属性"
},
{
"name": "meleeRange",
"type": "number",
"value": 2.0,
"description": "近战攻击范围",
"group": "属性"
},
{
"name": "rangedRange",
"type": "number",
"value": 8.0,
"description": "远程攻击范围",
"group": "属性"
},
{
"name": "shouldRetreat",
"type": "boolean",
"value": false,
"description": "是否应该撤退(生命值低或寡不敌众)",
"group": "战斗"
},
{
"name": "currentHealth",
"type": "number",
"value": 100,
"description": "当前生命值",
"group": "状态"
},
{
"name": "maxHealth",
"type": "number",
"value": 100,
"description": "最大生命值",
"group": "状态"
},
{
"name": "armor",
"type": "number",
"value": 10,
"description": "护甲值",
"group": "属性"
},
{
"name": "moveSpeed",
"type": "number",
"value": 4.0,
"description": "移动速度",
"group": "属性"
},
{
"name": "patrolRadius",
"type": "number",
"value": 10.0,
"description": "巡逻半径",
"group": "属性"
}
],
"metadata": {
"created": "2024-01-01T00:00:00.000Z",
"nodeCount": 35,
"editorVersion": "1.0.0",
"description": "士兵AI展示了完整的战斗单位行为模式包括多种攻击方式、战术撤退、巡逻警戒等军事行为的智能决策。"
}
}

View File

@@ -1,11 +0,0 @@
{
"ver": "2.0.1",
"importer": "json",
"imported": true,
"uuid": "a71fbedb-9435-4637-b7a5-e0fb8b99d3c1",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
{
"ver": "1.0.0",
"importer": "*",
"imported": true,
"uuid": "843934be-5d8e-49b3-93e5-34999ca6f50e",
"files": [
".btree",
".json"
],
"subMetas": {},
"userData": {}
}

View File

@@ -1,380 +0,0 @@
{
"id": "worker-ai",
"name": "工人AI行为树",
"description": "工人单位的智能行为系统,包含资源收集、建造、修理等功能",
"version": "1.0.0",
"author": "ECS Framework",
"nodes": [
{
"id": "root",
"type": "root",
"name": "工人AI根节点",
"description": "工人AI的根节点管理所有工人行为",
"children": ["main-selector"]
},
{
"id": "main-selector",
"type": "selector",
"name": "主行为选择器",
"description": "按优先级选择工人行为:逃跑 > 执行命令 > 空闲",
"children": ["flee-behavior", "command-behavior", "idle-behavior"]
},
{
"id": "flee-behavior",
"type": "conditional-decorator",
"name": "逃跑行为",
"description": "生命值低时逃跑到安全区域",
"children": ["flee-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "isLowHealth",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "flee-sequence",
"type": "sequence",
"name": "逃跑序列",
"description": "执行逃跑行为的完整序列",
"children": ["set-flee-state", "move-to-safety", "heal-self"]
},
{
"id": "set-flee-state",
"type": "set-blackboard-value",
"name": "设置逃跑状态",
"description": "将工人状态设置为逃跑",
"properties": {
"variableName": "currentState",
"value": "fleeing"
}
},
{
"id": "move-to-safety",
"type": "event-action",
"name": "移动到安全区域",
"description": "移动到最近的安全建筑",
"properties": {
"eventName": "move-to-safety"
}
},
{
"id": "heal-self",
"type": "event-action",
"name": "自我治疗",
"description": "使用治疗物品恢复生命值",
"properties": {
"eventName": "heal-self"
}
},
{
"id": "command-behavior",
"type": "conditional-decorator",
"name": "命令行为",
"description": "有命令时执行相应行为",
"children": ["command-selector"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "hasTarget",
"compareOperator": "equals",
"compareValue": true
}
}
},
{
"id": "command-selector",
"type": "selector",
"name": "命令选择器",
"description": "根据命令类型选择行为",
"children": ["gather-behavior", "build-behavior", "repair-behavior", "move-behavior"]
},
{
"id": "gather-behavior",
"type": "conditional-decorator",
"name": "收集行为",
"description": "收集资源的行为",
"children": ["gather-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "gather"
}
}
},
{
"id": "gather-sequence",
"type": "sequence",
"name": "收集序列",
"description": "完整的资源收集流程",
"children": ["move-to-resource", "collect-resource", "return-to-base"]
},
{
"id": "move-to-resource",
"type": "event-action",
"name": "移动到资源",
"description": "移动到目标资源点",
"properties": {
"eventName": "move-to-target"
}
},
{
"id": "collect-resource",
"type": "event-action",
"name": "收集资源",
"description": "执行资源收集动作",
"properties": {
"eventName": "gather-resource"
}
},
{
"id": "return-to-base",
"type": "event-action",
"name": "返回基地",
"description": "将资源运回基地",
"properties": {
"eventName": "return-to-base"
}
},
{
"id": "build-behavior",
"type": "conditional-decorator",
"name": "建造行为",
"description": "建造建筑的行为",
"children": ["build-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "build"
}
}
},
{
"id": "build-sequence",
"type": "sequence",
"name": "建造序列",
"description": "完整的建造流程",
"children": ["move-to-build-site", "construct-building"]
},
{
"id": "move-to-build-site",
"type": "event-action",
"name": "移动到建筑工地",
"description": "移动到指定的建筑位置",
"properties": {
"eventName": "move-to-target"
}
},
{
"id": "construct-building",
"type": "event-action",
"name": "建造建筑",
"description": "执行建筑建造动作",
"properties": {
"eventName": "construct-building"
}
},
{
"id": "repair-behavior",
"type": "conditional-decorator",
"name": "修理行为",
"description": "修理损坏建筑的行为",
"children": ["repair-sequence"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "repair"
}
}
},
{
"id": "repair-sequence",
"type": "sequence",
"name": "修理序列",
"description": "完整的修理流程",
"children": ["move-to-building", "repair-building"]
},
{
"id": "move-to-building",
"type": "event-action",
"name": "移动到建筑",
"description": "移动到需要修理的建筑",
"properties": {
"eventName": "move-to-target"
}
},
{
"id": "repair-building",
"type": "event-action",
"name": "修理建筑",
"description": "执行建筑修理动作",
"properties": {
"eventName": "repair-building"
}
},
{
"id": "move-behavior",
"type": "conditional-decorator",
"name": "移动行为",
"description": "单纯的移动行为",
"children": ["simple-move"],
"condition": {
"type": "blackboard-value-comparison",
"properties": {
"variableName": "currentCommand",
"compareOperator": "equals",
"compareValue": "move"
}
}
},
{
"id": "simple-move",
"type": "event-action",
"name": "简单移动",
"description": "移动到指定位置",
"properties": {
"eventName": "move-to-target"
}
},
{
"id": "idle-behavior",
"type": "sequence",
"name": "空闲行为",
"description": "没有任务时的默认行为",
"children": ["set-idle-state", "idle-wait"]
},
{
"id": "set-idle-state",
"type": "set-blackboard-value",
"name": "设置空闲状态",
"description": "将工人状态设置为空闲",
"properties": {
"variableName": "currentState",
"value": "idle"
}
},
{
"id": "idle-wait",
"type": "wait-action",
"name": "空闲等待",
"description": "空闲时等待一段时间",
"properties": {
"waitTime": 1.0
}
}
],
"blackboard": [
{
"name": "currentState",
"type": "string",
"value": "idle",
"description": "工人当前状态idle、working、fleeing、gathering、building、repairing",
"group": "状态"
},
{
"name": "currentCommand",
"type": "string",
"value": "idle",
"description": "当前接收的命令idle、move、gather、build、repair、attack",
"group": "命令"
},
{
"name": "hasTarget",
"type": "boolean",
"value": false,
"description": "是否有目标任务",
"group": "目标"
},
{
"name": "targetPosition",
"type": "object",
"value": {"x": 0, "y": 0, "z": 0},
"description": "目标位置坐标",
"group": "目标"
},
{
"name": "currentHealth",
"type": "number",
"value": 100,
"description": "当前生命值",
"group": "状态"
},
{
"name": "maxHealth",
"type": "number",
"value": 100,
"description": "最大生命值",
"group": "状态"
},
{
"name": "healthPercentage",
"type": "number",
"value": 1.0,
"description": "生命值百分比",
"group": "状态"
},
{
"name": "isLowHealth",
"type": "boolean",
"value": false,
"description": "是否生命值较低低于30%",
"group": "状态"
},
{
"name": "moveSpeed",
"type": "number",
"value": 3.0,
"description": "移动速度",
"group": "属性"
},
{
"name": "gatherSpeed",
"type": "number",
"value": 1.0,
"description": "资源收集速度",
"group": "属性"
},
{
"name": "buildSpeed",
"type": "number",
"value": 1.0,
"description": "建造速度",
"group": "属性"
},
{
"name": "carryCapacity",
"type": "number",
"value": 10,
"description": "携带容量",
"group": "属性"
},
{
"name": "currentLoad",
"type": "number",
"value": 0,
"description": "当前携带量",
"group": "状态"
},
{
"name": "resourceType",
"type": "string",
"value": "none",
"description": "携带的资源类型",
"group": "状态"
}
],
"metadata": {
"created": "2024-01-01T00:00:00.000Z",
"nodeCount": 30,
"editorVersion": "1.0.0",
"description": "工人AI展示了完整的RTS单位行为模式包括生存、工作、建造等多种行为的优先级管理和状态切换。"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
{
"ver": "1.0.0",
"importer": "*",
"imported": true,
"uuid": "f7fcacf2-eab6-4bef-b7b4-55d13707c90c",
"files": [
".btree",
".json"
],
"subMetas": {},
"userData": {}
}

View File

@@ -21,6 +21,15 @@
}, },
{ {
"__id__": 5 "__id__": 5
},
{
"__id__": 7
},
{
"__id__": 9
},
{
"__id__": 10
} }
], ],
"_active": true, "_active": true,
@@ -55,7 +64,7 @@
}, },
"autoReleaseAssets": false, "autoReleaseAssets": false,
"_globals": { "_globals": {
"__id__": 7 "__id__": 16
}, },
"_id": "ff354f0b-c2f5-4dea-8ffb-0152d175d11c" "_id": "ff354f0b-c2f5-4dea-8ffb-0152d175d11c"
}, },
@@ -247,30 +256,351 @@
"_id": "7dWQTpwS5LrIHnc1zAPUtf" "_id": "7dWQTpwS5LrIHnc1zAPUtf"
}, },
{ {
"__type__": "cc.SceneGlobals", "__type__": "cc.Node",
"ambient": { "_name": "RTSDemo",
"__id__": 8 "_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
}, },
"shadows": { "_children": [],
"_active": true,
"_components": [
{
"__id__": 8
}
],
"_prefab": null,
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": "aaq4MG2HtHboRayLQRrQKj"
},
{
"__type__": "c33869Km+9Bb7dw/OyRztvE",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 7
},
"_enabled": true,
"__prefab": null,
"gameWorld": {
"__id__": 9 "__id__": 9
}, },
"_skybox": { "mainCamera": {
"__id__": 6
},
"uiRoot": {
"__id__": 10 "__id__": 10
}, },
"fog": { "_id": "950MqG3LtHsLiq9V5owd43"
},
{
"__type__": "cc.Node",
"_name": "GameWorld",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [],
"_prefab": null,
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": "8b9QorrGZIl64tVv0Z0vRQ"
},
{
"__type__": "cc.Node",
"_name": "Canvas",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [
{
"__id__": 11 "__id__": 11
}, }
"octree": { ],
"__id__": 12 "_active": true,
}, "_components": [
"skin": { {
"__id__": 13 "__id__": 13
}, },
"lightProbeInfo": { {
"__id__": 14 "__id__": 14
}, },
"postSettings": { {
"__id__": 15 "__id__": 15
}
],
"_prefab": null,
"_lpos": {
"__type__": "cc.Vec3",
"x": 640,
"y": 360,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": "4edRVPFLtIz5pR5edsryvx"
},
{
"__type__": "cc.Node",
"_name": "Camera",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 10
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 12
}
],
"_prefab": null,
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 1000
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 1073741824,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": "dfyZdh0bxJop4PyQrmHEP6"
},
{
"__type__": "cc.Camera",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 11
},
"_enabled": true,
"__prefab": null,
"_projection": 0,
"_priority": 1073741824,
"_fov": 45,
"_fovAxis": 0,
"_orthoHeight": 499.8270893371758,
"_near": 1,
"_far": 2000,
"_color": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_depth": 1,
"_stencil": 0,
"_clearFlags": 6,
"_rect": {
"__type__": "cc.Rect",
"x": 0,
"y": 0,
"width": 1,
"height": 1
},
"_aperture": 19,
"_shutter": 7,
"_iso": 0,
"_screenScale": 1,
"_visibility": 41943040,
"_targetTexture": null,
"_postProcess": null,
"_usePostProcess": false,
"_cameraType": -1,
"_trackingType": 0,
"_id": "48lLOhLY5Onqokj70aNP+E"
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": null,
"_contentSize": {
"__type__": "cc.Size",
"width": 1280,
"height": 720
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": "c3qBrLTLNImoltQDlZ6coz"
},
{
"__type__": "cc.Canvas",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": null,
"_cameraComponent": {
"__id__": 12
},
"_alignCanvasWithScreen": true,
"_id": "9d3SdE3ORAOZ6AG/imW6NO"
},
{
"__type__": "cc.Widget",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 10
},
"_enabled": true,
"__prefab": null,
"_alignFlags": 45,
"_target": null,
"_left": 0,
"_right": 0,
"_top": 0,
"_bottom": 0,
"_horizontalCenter": 0,
"_verticalCenter": 0,
"_isAbsLeft": true,
"_isAbsRight": true,
"_isAbsTop": true,
"_isAbsBottom": true,
"_isAbsHorizontalCenter": true,
"_isAbsVerticalCenter": true,
"_originalWidth": 0,
"_originalHeight": 0,
"_alignMode": 2,
"_lockFlags": 0,
"_id": "4a8iJypC1J8pMml467hQ6c"
},
{
"__type__": "cc.SceneGlobals",
"ambient": {
"__id__": 17
},
"shadows": {
"__id__": 18
},
"_skybox": {
"__id__": 19
},
"fog": {
"__id__": 20
},
"octree": {
"__id__": 21
},
"skin": {
"__id__": 22
},
"lightProbeInfo": {
"__id__": 23
},
"postSettings": {
"__id__": 24
}, },
"bakedWithStationaryMainLight": false, "bakedWithStationaryMainLight": false,
"bakedWithHighpLightmap": false "bakedWithHighpLightmap": false

View File

@@ -1,236 +1,174 @@
import { _decorator, Component, Node, Vec3, instantiate, Prefab, Camera } from 'cc'; import { _decorator, Component, Node, Vec3, Color, MeshRenderer, Material, BoxCollider, geometry, PhysicsSystem, director } from 'cc';
import { SimplePrefabFactory } from './components/SimplePrefabFactory';
import { UnitController } from './components/UnitController'; import { UnitController } from './components/UnitController';
import { RTSCameraController } from './controllers/RTSCameraController'; import { BehaviorTreeManager } from './components/BehaviorTreeManager';
import { UIController } from './controllers/UIController';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
/** /**
* RTS演示项目主控制器 * 简化版矿工挖矿演示
* 展示行为树在3D RTS游戏中的应用 * 核心逻辑:矿工挖矿 → 运输 → 存储 → 重复
*/ */
@ccclass('RTSDemo') @ccclass('MinerDemo')
export class RTSDemo extends Component { export class MinerDemo extends Component {
@property(Prefab) @property
unitPrefab: Prefab = null!; minerCount: number = 3; // 矿工数量
@property(Prefab) @property
buildingPrefab: Prefab = null!; oreCount: number = 8; // 矿石数量
@property(Prefab) private factory: SimplePrefabFactory = new SimplePrefabFactory();
resourcePrefab: Prefab = null!; private miners: Node[] = [];
private ores: Node[] = [];
private warehouse: Node | null = null;
private ground: Node | null = null;
@property(Node) start() {
gameWorld: Node = null!; console.log('🎮 启动矿工挖矿演示');
this.createWorld();
@property(Camera) this.createWarehouse();
mainCamera: Camera = null!; this.createOres();
this.createMiners();
@property(Node) this.logGameStatus();
uiRoot: Node = null!;
private cameraController: RTSCameraController = null!;
private uiController: UIController = null!;
// 游戏状态
private units: Node[] = [];
private buildings: Node[] = [];
private resources: Node[] = [];
private selectedUnits: Node[] = [];
onLoad() {
console.log('RTS Demo 初始化开始...');
this.initializeControllers();
this.setupScene();
console.log('RTS Demo 初始化完成!');
} }
/** /**
* 初始化控制器 * 创建游戏世界
*/ */
private initializeControllers() { private createWorld() {
// 相机控制器 // 创建地面
this.cameraController = this.mainCamera.getComponent(RTSCameraController) || this.ground = this.factory.createGround(this.node, new Vec3(0, 0, 0), new Vec3(20, 0.2, 20));
this.mainCamera.addComponent(RTSCameraController); console.log('🌍 创建游戏世界20x20地面');
// UI控制器
this.uiController = this.uiRoot.getComponent(UIController) ||
this.uiRoot.addComponent(UIController);
// 设置UI回调
this.uiController.onUnitSelected = this.onUnitSelected.bind(this);
this.uiController.onCommandIssued = this.onCommandIssued.bind(this);
console.log('控制器初始化完成');
} }
/** /**
* 设置场景 * 创建仓库
*/ */
private setupScene() { private createWarehouse() {
this.createUnits(); // 在地图中心创建仓库
this.createBuildings(); this.warehouse = this.factory.createBuilding(
this.createResources(); this.node,
new Vec3(0, 1, 0),
// 设置初始相机位置 new Vec3(2, 2, 2),
this.mainCamera.node.setPosition(0, 20, 15); Color.GRAY,
this.mainCamera.node.lookAt(Vec3.ZERO); 'warehouse'
);
console.log('场景设置完成'); console.log('🏭 创建仓库:位置(0,1,0)');
} }
/** /**
* 创建单位 * 创建矿石
*/ */
private createUnits() { private createOres() {
const unitTypes = [ console.log(`⛏️ 创建${this.oreCount}个矿石`);
{ name: 'Worker', behaviorTree: 'worker-ai', color: 'blue' },
{ name: 'Soldier', behaviorTree: 'soldier-ai', color: 'red' },
{ name: 'Scout', behaviorTree: 'scout-ai', color: 'green' }
];
unitTypes.forEach((type, typeIndex) => { for (let i = 0; i < this.oreCount; i++) {
for (let i = 0; i < 3; i++) { // 随机分布矿石,避开仓库区域
const unit = instantiate(this.unitPrefab); let position: Vec3;
unit.name = `${type.name}_${i + 1}`; do {
position = new Vec3(
(Math.random() - 0.5) * 16, // -8到8
0.5,
(Math.random() - 0.5) * 16 // -8到8
);
} while (Vec3.distance(position, new Vec3(0, 0.5, 0)) < 4); // 距离仓库至少4米
// 设置位置 const ore = this.factory.createResource(
const angle = (i / 3) * Math.PI * 2; this.node,
const radius = 3 + typeIndex * 2; position,
const x = Math.cos(angle) * radius; new Vec3(0.8, 0.8, 0.8),
const z = Math.sin(angle) * radius; Color.YELLOW,
unit.setPosition(x, 0, z); 'ore'
);
// 添加到场景 this.ores.push(ore);
this.gameWorld.addChild(unit); console.log(` 💎 矿石${i+1}:位置(${position.x.toFixed(1)}, ${position.y.toFixed(1)}, ${position.z.toFixed(1)})`);
this.units.push(unit);
// 配置单位组件
const unitController = unit.getComponent(UnitController) || unit.addComponent(UnitController);
unitController.setup({
unitType: type.name.toLowerCase(),
behaviorTreeName: type.behaviorTree,
maxHealth: 100,
moveSpeed: 3,
attackRange: 2,
attackDamage: 25,
color: type.color
});
console.log(`创建单位: ${unit.name} at (${x.toFixed(1)}, 0, ${z.toFixed(1)})`);
} }
});
} }
/** /**
* 创建建筑 * 创建矿工
*/ */
private createBuildings() { private createMiners() {
const buildingPositions = [ console.log(`👷 创建${this.minerCount}个矿工`);
{ pos: new Vec3(-10, 0, -10), name: 'MainBase' },
{ pos: new Vec3(10, 0, 10), name: 'Barracks' },
{ pos: new Vec3(-8, 0, 8), name: 'ResourceCenter' }
];
buildingPositions.forEach((building, index) => { for (let i = 0; i < this.minerCount; i++) {
const buildingNode = instantiate(this.buildingPrefab); // 矿工围绕仓库分布
buildingNode.name = building.name; const angle = (i / this.minerCount) * Math.PI * 2;
buildingNode.setPosition(building.pos); const radius = 3;
const position = new Vec3(
Math.cos(angle) * radius,
1,
Math.sin(angle) * radius
);
this.gameWorld.addChild(buildingNode); const miner = this.factory.createUnit(
this.buildings.push(buildingNode); this.node,
position,
new Vec3(0.8, 0.8, 0.8),
Color.BLUE,
'miner'
);
console.log(`创建建筑: ${building.name} at ${building.pos}`); // 添加矿工控制器
}); const unitController = miner.addComponent(UnitController);
unitController.unitType = 'miner';
unitController.maxHealth = 100;
unitController.currentHealth = 100;
unitController.moveSpeed = 2.0;
unitController.currentCommand = 'mine'; // 默认挖矿命令
// 添加行为树管理器
const behaviorManager = miner.addComponent(BehaviorTreeManager);
// 初始化行为树
behaviorManager.initializeBehaviorTree('miner-ai', unitController);
this.miners.push(miner);
console.log(` 👷 矿工${i+1}:位置(${position.x.toFixed(1)}, ${position.y.toFixed(1)}, ${position.z.toFixed(1)})`);
}
} }
/** /**
* 创建资源 * 记录游戏状态
*/ */
private createResources() { private logGameStatus() {
const resourcePositions = [ console.log('\n📊 游戏状态总览:');
new Vec3(5, 0, -5), console.log(` 🏭 仓库1个`);
new Vec3(-5, 0, 5), console.log(` 💎 矿石:${this.ores.length}`);
new Vec3(8, 0, -8), console.log(` 👷 矿工:${this.miners.length}`);
new Vec3(-8, 0, -5), console.log(` 🎯 游戏目标:矿工自动挖矿并运输到仓库`);
new Vec3(6, 0, 6) console.log('\n🎮 游戏逻辑:');
]; console.log(' 1. 矿工寻找最近的矿石');
console.log(' 2. 移动到矿石位置并挖掘');
resourcePositions.forEach((pos, index) => { console.log(' 3. 携带矿石返回仓库');
const resource = instantiate(this.resourcePrefab); console.log(' 4. 存储矿石并重复循环');
resource.name = `Resource_${index + 1}`;
resource.setPosition(pos);
this.gameWorld.addChild(resource);
this.resources.push(resource);
console.log(`创建资源: ${resource.name} at ${pos}`);
});
} }
/** /**
* 单位选择回调 * 获取所有矿石位置供AI使用
*/ */
private onUnitSelected(units: Node[]) { public getAllOres(): Node[] {
// 取消之前的选择 return this.ores.filter(ore => ore && ore.isValid);
this.selectedUnits.forEach(unit => {
const unitController = unit.getComponent(UnitController);
if (unitController) {
unitController.setSelected(false);
}
});
// 设置新选择
this.selectedUnits = units;
this.selectedUnits.forEach(unit => {
const unitController = unit.getComponent(UnitController);
if (unitController) {
unitController.setSelected(true);
}
});
console.log(`选择了 ${units.length} 个单位`);
this.uiController.setSelectedUnitsCount(units.length);
} }
/** /**
* 命令发布回调 * 获取仓库位置供AI使用
*/ */
private onCommandIssued(command: string, target?: Vec3 | Node) { public getWarehouse(): Node | null {
if (this.selectedUnits.length === 0) { return this.warehouse;
console.log('没有选择单位');
return;
}
this.selectedUnits.forEach(unit => {
const unitController = unit.getComponent(UnitController);
if (unitController) {
unitController.issueCommand(command, target);
}
});
console.log(`发布命令: ${command}${this.selectedUnits.length} 个单位`);
} }
/** /**
* 获取所有单位 * 移除已开采的矿石
*/ */
getAllUnits(): Node[] { public removeOre(ore: Node) {
return [...this.units]; const index = this.ores.indexOf(ore);
if (index > -1) {
this.ores.splice(index, 1);
ore.destroy();
console.log(`💎 矿石已开采,剩余${this.ores.length}个矿石`);
} }
/**
* 获取所有建筑
*/
getAllBuildings(): Node[] {
return [...this.buildings];
}
/**
* 获取所有资源
*/
getAllResources(): Node[] {
return [...this.resources];
} }
} }

View File

@@ -88,11 +88,16 @@ export class BehaviorTreeComponent extends ECSComponent {
private setupBlackboard() { private setupBlackboard() {
if (!this.blackboard || !this.cocosNode) return; if (!this.blackboard || !this.cocosNode) return;
// 设置基础信息 // 注意:只设置行为树中实际定义的变量
this.blackboard.setValue('entityName', this.cocosNode.name); // 这些变量需要在对应的.btree文件的blackboard数组中预先定义
this.blackboard.setValue('currentTime', Date.now() / 1000);
this.blackboard.setValue('deltaTime', 0.016); // 设置基础信息 - 注释掉未在行为树中定义的变量
this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition); // this.blackboard.setValue('entityName', this.cocosNode.name);
// this.blackboard.setValue('currentTime', Date.now() / 1000);
// this.blackboard.setValue('deltaTime', 0.016);
// this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition);
console.log('BehaviorTreeComponent黑板设置完成未设置任何变量以避免警告');
} }
/** /**
@@ -107,13 +112,14 @@ export class BehaviorTreeComponent extends ECSComponent {
this.lastTickTime = 0; this.lastTickTime = 0;
// 更新黑板中的时间信息 // 更新黑板中的时间信息 - 注释掉未在行为树中定义的变量
if (this.blackboard) { if (this.blackboard) {
this.blackboard.setValue('deltaTime', deltaTime); // 只更新行为树中实际定义的变量
this.blackboard.setValue('currentTime', Date.now() / 1000); // this.blackboard.setValue('deltaTime', deltaTime);
if (this.cocosNode) { // this.blackboard.setValue('currentTime', Date.now() / 1000);
this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition); // if (this.cocosNode) {
} // this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition);
// }
} }
// 执行行为树 // 执行行为树

View File

@@ -1,17 +1,20 @@
import { _decorator, Component, resources, JsonAsset } from 'cc'; import { _decorator, Component, resources, JsonAsset, Vec3 } from 'cc';
import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig } from '@esengine/ai'; import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig, ExecutionContext, EventRegistry } from '@esengine/ai';
import { UnitController } from './UnitController'; import { UnitController } from './UnitController';
import { RTSBehaviorHandler } from './RTSBehaviorHandler';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
/** /**
* 执行上下文接口 * 游戏执行上下文接口
* 继承框架的ExecutionContext添加游戏特定的属性
*/ */
interface GameExecutionContext { interface GameExecutionContext extends ExecutionContext {
blackboard?: Blackboard;
unitController: UnitController; unitController: UnitController;
gameObject: any; gameObject: any;
[key: string]: any; eventRegistry?: EventRegistry;
// 确保继承索引签名
[key: string]: unknown;
} }
/** /**
@@ -24,16 +27,18 @@ export class BehaviorTreeManager extends Component {
debugMode: boolean = true; debugMode: boolean = true;
@property @property
tickInterval: number = 0.1; // 行为树更新间隔(秒) tickInterval: number = 0.1; // 行为树更新间隔(秒)- 10fps更新频率平衡性能和响应性
private behaviorTree: BehaviorTree<GameExecutionContext> | null = null; private behaviorTree: BehaviorTree<GameExecutionContext> | null = null;
private blackboard: Blackboard | null = null; private blackboard: Blackboard | null = null;
private context: GameExecutionContext | null = null; private context: GameExecutionContext | null = null;
private eventRegistry: EventRegistry | null = null;
private isLoaded: boolean = false; private isLoaded: boolean = false;
private isRunning: boolean = false; private isRunning: boolean = false;
private lastTickTime: number = 0; private lastTickTime: number = 0;
private unitController: UnitController | null = null; private unitController: UnitController | null = null;
private currentBehaviorTreeName: string = ''; private currentBehaviorTreeName: string = '';
private behaviorHandler: RTSBehaviorHandler | null = null;
/** /**
* 初始化行为树 * 初始化行为树
@@ -42,12 +47,22 @@ export class BehaviorTreeManager extends Component {
this.currentBehaviorTreeName = behaviorTreeName; this.currentBehaviorTreeName = behaviorTreeName;
this.unitController = unitController; this.unitController = unitController;
// 获取RTSBehaviorHandler组件
this.behaviorHandler = this.getComponent(RTSBehaviorHandler);
if (!this.behaviorHandler) {
console.error(`BehaviorTreeManager: 未找到RTSBehaviorHandler组件 - ${this.node.name}`);
return;
}
try { try {
await this.loadBehaviorTree(behaviorTreeName); await this.loadBehaviorTree(behaviorTreeName);
this.setupBlackboard(); this.setupBlackboard();
this.isLoaded = true; this.isLoaded = true;
this.isRunning = true; this.isRunning = true;
console.log(`行为树初始化成功: ${behaviorTreeName}`); console.log(`行为树初始化成功: ${behaviorTreeName} for ${this.unitController.node.name}`);
console.log(` - 行为树: ${this.behaviorTree ? '已创建' : '未创建'}`);
console.log(` - 黑板变量: ${this.blackboard ? '已创建' : '未创建'}`);
console.log(` - 运行状态: ${this.isRunning ? '运行中' : '已停止'}`);
} catch (error) { } catch (error) {
console.error(`行为树初始化失败: ${behaviorTreeName}`, error); console.error(`行为树初始化失败: ${behaviorTreeName}`, error);
} }
@@ -59,6 +74,7 @@ export class BehaviorTreeManager extends Component {
private async loadBehaviorTree(behaviorTreeName: string): Promise<void> { private async loadBehaviorTree(behaviorTreeName: string): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const jsonPath = `${behaviorTreeName}.bt`; const jsonPath = `${behaviorTreeName}.bt`;
console.log(`🔍 尝试加载行为树文件: ${jsonPath}`);
resources.load(jsonPath, JsonAsset, (err, asset) => { resources.load(jsonPath, JsonAsset, (err, asset) => {
if (err) { if (err) {
@@ -72,15 +88,17 @@ export class BehaviorTreeManager extends Component {
// 创建执行上下文 // 创建执行上下文
this.blackboard = new Blackboard(); this.blackboard = new Blackboard();
this.eventRegistry = this.createEventRegistry();
this.context = { this.context = {
blackboard: this.blackboard, blackboard: this.blackboard,
unitController: this.unitController!, unitController: this.unitController!,
gameObject: this.node gameObject: this.node,
}; eventRegistry: this.eventRegistry
} as GameExecutionContext;
// 从JSON数据创建行为树 // 从JSON数据创建行为树
const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig(behaviorTreeData, this.context); const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig<GameExecutionContext>(behaviorTreeData, this.context);
this.behaviorTree = buildResult.tree as BehaviorTree<GameExecutionContext>; this.behaviorTree = buildResult.tree;
this.blackboard = buildResult.blackboard; this.blackboard = buildResult.blackboard;
resolve(); resolve();
@@ -92,35 +110,70 @@ export class BehaviorTreeManager extends Component {
}); });
} }
/**
* 创建事件注册表
*/
private createEventRegistry(): EventRegistry {
const registry = new EventRegistry();
// 注册简化的矿工行为事件处理器
const eventHandlers = {
// 矿工核心行为
'find-and-mine-ore': (context: any, params?: any) => this.callBehaviorHandler('onFindAndMineOre', params),
'store-ore': (context: any, params?: any) => this.callBehaviorHandler('onStoreOre', params),
'idle-behavior': (context: any, params?: any) => this.callBehaviorHandler('onIdleBehavior', params)
};
// 将事件处理器注册到EventRegistry
Object.entries(eventHandlers).forEach(([eventName, handler]) => {
registry.registerAction(eventName, handler);
});
return registry;
}
/**
* 调用行为处理器的方法
*/
private callBehaviorHandler(methodName: string, params: any = {}): string {
if (!this.behaviorHandler) {
console.error(`BehaviorTreeManager: RTSBehaviorHandler未初始化 - ${this.node.name}`);
return 'failure';
}
try {
// 直接调用RTSBehaviorHandler的方法
const method = (this.behaviorHandler as any)[methodName];
if (typeof method === 'function') {
console.log(`🎯 调用行为处理器: ${methodName} (${this.node.name})`);
const result = method.call(this.behaviorHandler, params);
console.log(`📤 行为处理器返回: ${methodName} -> "${result}" (${this.node.name})`);
return result || 'success'; // 确保有返回值
} else {
console.error(`BehaviorTreeManager: 方法不存在: ${methodName}`);
return 'failure';
}
} catch (error) {
console.error(`BehaviorTreeManager: 调用方法失败: ${methodName}`, error);
return 'failure';
}
}
/** /**
* 设置黑板基础信息 * 设置黑板基础信息
*/ */
private setupBlackboard() { private setupBlackboard() {
if (!this.unitController || !this.blackboard) return; if (!this.unitController || !this.blackboard) return;
// 设置单位基础信息 // 设置矿工基础信息
this.blackboard.setValue('entityName', this.node.name);
this.blackboard.setValue('unitType', this.unitController.unitType); this.blackboard.setValue('unitType', this.unitController.unitType);
this.blackboard.setValue('maxHealth', this.unitController.maxHealth);
this.blackboard.setValue('currentHealth', this.unitController.currentHealth); this.blackboard.setValue('currentHealth', this.unitController.currentHealth);
this.blackboard.setValue('moveSpeed', this.unitController.moveSpeed); this.blackboard.setValue('maxHealth', this.unitController.maxHealth);
this.blackboard.setValue('attackRange', this.unitController.attackRange); this.blackboard.setValue('currentCommand', 'mine');
this.blackboard.setValue('attackDamage', this.unitController.attackDamage); this.blackboard.setValue('hasOre', false);
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('hasTarget', false);
this.blackboard.setValue('isSelected', false); this.blackboard.setValue('targetPosition', null);
this.blackboard.setValue('isMoving', false);
// 设置单位控制器引用,供行为树节点使用
this.blackboard.setValue('unitController', this.unitController);
this.blackboard.setValue('gameObject', this.node);
} }
/** /**
@@ -165,45 +218,20 @@ export class BehaviorTreeManager extends Component {
this.lastTickTime = 0; 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) { if (this.unitController) {
this.blackboard.setValue('currentHealth', this.unitController.currentHealth); 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('currentCommand', this.unitController.currentCommand);
this.blackboard.setValue('isSelected', this.unitController.isSelected); this.blackboard.setValue('hasTarget', this.unitController.targetPosition && !this.unitController.targetPosition.equals(Vec3.ZERO));
this.blackboard.setValue('targetPosition', this.unitController.targetPosition); this.blackboard.setValue('targetPosition', this.unitController.targetPosition);
this.blackboard.setValue('targetNode', this.unitController.targetNode); this.blackboard.setValue('isMoving', this.unitController.targetPosition && !this.unitController.targetPosition.equals(Vec3.ZERO));
// 更新距离信息
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 { try {
this.behaviorTree.tick(deltaTime); this.behaviorTree.tick(deltaTime);
if (this.debugMode && Math.random() < 0.01) { // 1%的概率打印调试信息
console.log(`行为树执行完成, 单位: ${this.node.name}`);
}
} catch (error) { } catch (error) {
console.error(`行为树执行错误:`, error); console.error(`行为树执行错误: ${this.node.name}`, error);
} }
} }

View File

@@ -0,0 +1,142 @@
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组件引用
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组件');
}
}
/**
* 寻找并挖掘矿石
* @param params 事件参数,包含黑板变量值
*/
onFindAndMineOre(params: any = {}): string {
if (!this.unitController || !this.minerDemo) return 'failure';
// 从参数中获取黑板变量值
const unitType = params.unitType || 'unknown';
const currentHealth = params.currentHealth || 100;
console.log(`⛏️ ${unitType}矿工开始寻找矿石 (生命值: ${currentHealth})`);
// 获取所有可用矿石
const ores = this.minerDemo.getAllOres();
if (ores.length === 0) {
console.log(`👷 ${this.node.name}: 没有可挖掘的矿石了`);
return 'failure';
}
// 寻找最近的矿石
const currentPos = this.node.worldPosition;
let nearestOre: Node | null = null;
let minDistance = Infinity;
for (const ore of ores) {
const distance = Vec3.distance(currentPos, ore.worldPosition);
if (distance < minDistance) {
minDistance = distance;
nearestOre = ore;
}
}
if (!nearestOre) return 'failure';
// 检查是否已经到达矿石位置
if (minDistance < 1.5) {
// 开始挖掘
console.log(`⛏️ ${this.node.name}: 开始挖掘矿石`);
// 设置携带矿石状态(更新黑板)
this.unitController.setBlackboardValue('hasOre', true);
// 移除矿石
this.minerDemo.removeOre(nearestOre);
// 清除移动目标
this.unitController.clearTarget();
return 'success';
} else {
// 移动到矿石位置
this.unitController.setTarget(nearestOre.worldPosition);
console.log(`🚶 ${this.node.name}: 前往矿石位置 距离${minDistance.toFixed(1)}`);
return 'running';
}
}
/**
* 前往仓库存储矿石
* @param params 事件参数,包含黑板变量值
*/
onStoreOre(params: any = {}): string {
if (!this.unitController || !this.minerDemo) return 'failure';
// 从参数中获取黑板变量值
const unitType = params.unitType || 'unknown';
const targetPosition = params.targetPosition || null;
console.log(`🏭 ${unitType}矿工前往仓库存储 (目标位置: ${JSON.stringify(targetPosition)})`);
const warehouse = this.minerDemo.getWarehouse();
if (!warehouse) {
console.log(`👷 ${this.node.name}: 找不到仓库`);
return 'failure';
}
// 计算到仓库的距离
const currentPos = this.node.worldPosition;
const warehousePos = warehouse.worldPosition;
const distance = Vec3.distance(currentPos, warehousePos);
// 检查是否已经到达仓库
if (distance < 2.5) {
// 存储矿石
console.log(`🏭 ${this.node.name}: 在仓库存储矿石`);
// 清除携带矿石状态(更新黑板)
this.unitController.setBlackboardValue('hasOre', false);
// 清除移动目标
this.unitController.clearTarget();
return 'success';
} else {
// 移动到仓库
this.unitController.setTarget(warehousePos);
console.log(`🚚 ${this.node.name}: 运输矿石到仓库 距离${distance.toFixed(1)}`);
return 'running';
}
}
/**
* 待机行为
* @param params 事件参数,包含黑板变量值
*/
onIdleBehavior(params: any = {}): string {
// 从参数中获取黑板变量值
const unitType = params.unitType || 'unknown';
console.log(`😴 ${unitType}矿工待机中`);
return 'success';
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "739ff9ee-42d5-4542-bb5b-3e7611c729e2",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,131 @@
import { _decorator, Component, Node, Vec3, MeshRenderer, BoxCollider, RigidBody, Mesh, Material, Color, primitives, utils } from 'cc';
const { ccclass, property } = _decorator;
/**
* 简单预制体工厂 - 创建基本的游戏对象
* 用于在没有预制体资源时创建基本的单位、建筑和资源
*/
@ccclass('SimplePrefabFactory')
export class SimplePrefabFactory extends Component {
/**
* 创建单位节点
*/
static createUnit(name: string, color: Color = Color.WHITE): Node {
const unit = new Node(name);
// 添加网格渲染器
const meshRenderer = unit.addComponent(MeshRenderer);
// 创建立方体网格
const mesh = utils.createMesh(primitives.box({ width: 1, height: 1, length: 1 }));
meshRenderer.mesh = mesh;
// 创建材质
const material = new Material();
material.initialize({ effectName: 'builtin-unlit' });
material.setProperty('mainColor', color);
meshRenderer.material = material;
// 添加碰撞器
const collider = unit.addComponent(BoxCollider);
collider.size = new Vec3(1, 1, 1);
// 添加刚体
const rigidBody = unit.addComponent(RigidBody);
rigidBody.type = RigidBody.Type.KINEMATIC;
console.log(`创建单位: ${name}`);
return unit;
}
/**
* 创建建筑节点
*/
static createBuilding(name: string, size: Vec3 = new Vec3(2, 2, 2), color: Color = Color.GRAY): Node {
const building = new Node(name);
// 添加网格渲染器
const meshRenderer = building.addComponent(MeshRenderer);
// 创建立方体网格
const mesh = utils.createMesh(primitives.box({
width: size.x,
height: size.y,
length: size.z
}));
meshRenderer.mesh = mesh;
// 创建材质
const material = new Material();
material.initialize({ effectName: 'builtin-unlit' });
material.setProperty('mainColor', color);
meshRenderer.material = material;
// 添加碰撞器
const collider = building.addComponent(BoxCollider);
collider.size = size;
console.log(`创建建筑: ${name}`);
return building;
}
/**
* 创建资源节点
*/
static createResource(name: string, color: Color = Color.YELLOW): Node {
const resource = new Node(name);
// 添加网格渲染器
const meshRenderer = resource.addComponent(MeshRenderer);
// 创建球体网格
const mesh = utils.createMesh(primitives.sphere(0.5));
meshRenderer.mesh = mesh;
// 创建材质
const material = new Material();
material.initialize({ effectName: 'builtin-unlit' });
material.setProperty('mainColor', color);
meshRenderer.material = material;
// 添加碰撞器
const collider = resource.addComponent(BoxCollider);
collider.size = new Vec3(1, 1, 1);
console.log(`创建资源: ${name}`);
return resource;
}
/**
* 创建地面节点
*/
static createGround(size: Vec3 = new Vec3(50, 0.1, 50), color: Color = new Color(100, 150, 100, 255)): Node {
const ground = new Node('Ground');
// 添加网格渲染器
const meshRenderer = ground.addComponent(MeshRenderer);
// 创建平面网格
const mesh = utils.createMesh(primitives.box({
width: size.x,
height: size.y,
length: size.z
}));
meshRenderer.mesh = mesh;
// 创建材质
const material = new Material();
material.initialize({ effectName: 'builtin-unlit' });
material.setProperty('mainColor', color);
meshRenderer.material = material;
// 添加碰撞器
const collider = ground.addComponent(BoxCollider);
collider.size = size;
console.log(`创建地面: ${size}`);
return ground;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "ac45cfc7-cf47-4315-bdf0-ba002b45b4b6",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -1,5 +1,6 @@
import { _decorator, Component, Node, Vec3, Material, MeshRenderer, Color, tween } from 'cc'; import { _decorator, Component, Node, Vec3, Material, MeshRenderer, Color, tween } from 'cc';
import { BehaviorTreeManager } from './BehaviorTreeManager'; import { BehaviorTreeManager } from './BehaviorTreeManager';
import { RTSBehaviorHandler } from './RTSBehaviorHandler';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -29,7 +30,7 @@ export class UnitController extends Component {
public unitType: string = ''; public unitType: string = '';
public maxHealth: number = 100; public maxHealth: number = 100;
public currentHealth: number = 100; public currentHealth: number = 100;
public moveSpeed: number = 3; public moveSpeed: number = 1.5;
public attackRange: number = 2; public attackRange: number = 2;
public attackDamage: number = 25; public attackDamage: number = 25;
public isSelected: boolean = false; public isSelected: boolean = false;
@@ -40,7 +41,13 @@ export class UnitController extends Component {
public attackCooldown: number = 1.5; public attackCooldown: number = 1.5;
public color: string = 'white'; public color: string = 'white';
// 移动状态管理
private isMoving: boolean = false;
private moveStartTime: number = 0;
private lastTargetUpdateTime: number = 0;
private behaviorTreeManager: BehaviorTreeManager | null = null; private behaviorTreeManager: BehaviorTreeManager | null = null;
private behaviorHandler: Component | null = null;
private meshRenderer: MeshRenderer | null = null; private meshRenderer: MeshRenderer | null = null;
onLoad() { onLoad() {
@@ -48,6 +55,14 @@ export class UnitController extends Component {
// 创建行为树管理器 // 创建行为树管理器
this.behaviorTreeManager = this.addComponent(BehaviorTreeManager); this.behaviorTreeManager = this.addComponent(BehaviorTreeManager);
// 添加RTS行为处理器
try {
// 添加RTSBehaviorHandler组件
this.behaviorHandler = this.addComponent(RTSBehaviorHandler);
} catch (error) {
console.warn('RTSBehaviorHandler组件添加失败将使用默认行为处理', error);
}
} }
/** /**
@@ -65,12 +80,15 @@ export class UnitController extends Component {
// 设置材质颜色 // 设置材质颜色
this.setUnitColor(config.color); this.setUnitColor(config.color);
// 设置节点名称显示单位类型
this.node.name = `${config.unitType.toUpperCase()}_${this.node.name}`;
// 初始化行为树 // 初始化行为树
if (this.behaviorTreeManager) { if (this.behaviorTreeManager) {
this.behaviorTreeManager.initializeBehaviorTree(config.behaviorTreeName, this); this.behaviorTreeManager.initializeBehaviorTree(config.behaviorTreeName, this);
} }
console.log(`单位 ${this.node.name} 设置完成 - 类型: ${config.unitType}, 行为树: ${config.behaviorTreeName}`); console.log(`🎮 单位设置完成: ${this.node.name} | 类型: ${config.unitType.toUpperCase()} | 行为树: ${config.behaviorTreeName}`);
} }
/** /**
@@ -93,6 +111,8 @@ export class UnitController extends Component {
this.meshRenderer.material.setProperty('mainColor', color); this.meshRenderer.material.setProperty('mainColor', color);
} }
/** /**
* 设置选择状态 * 设置选择状态
*/ */
@@ -165,6 +185,29 @@ export class UnitController extends Component {
console.log(`单位 ${this.node.name} 接收命令: ${command}`, target); console.log(`单位 ${this.node.name} 接收命令: ${command}`, target);
} }
/**
* 设置黑板变量值
*/
setBlackboardValue(key: string, value: any) {
if (this.behaviorTreeManager) {
this.behaviorTreeManager.updateBlackboardValue(key, value);
}
}
/**
* 设置移动目标
*/
setTarget(position: Vec3) {
this.targetPosition = position.clone();
}
/**
* 清除移动目标
*/
clearTarget() {
this.targetPosition = Vec3.ZERO.clone();
}
/** /**
* 受到伤害 * 受到伤害
*/ */
@@ -219,23 +262,45 @@ export class UnitController extends Component {
} }
/** /**
* 移动到目标位置 * 移动到目标位置只在水平面移动不改变Y轴
*/ */
moveToTarget(targetPos: Vec3, speed?: number): boolean { moveToTarget(targetPos: Vec3, speed?: number, deltaTime?: number): boolean {
const currentPos = this.node.worldPosition; const currentPos = this.node.worldPosition;
const distance = currentPos.subtract(targetPos).length();
if (distance < 0.5) { // 只计算水平面距离忽略Y轴
const currentPos2D = new Vec3(currentPos.x, 0, currentPos.z);
const targetPos2D = new Vec3(targetPos.x, 0, targetPos.z);
const distance = currentPos2D.subtract(targetPos2D).length();
if (distance < 0.8) { // 增加到达阈值,减少抖动
this.isMoving = false;
return true; // 已到达目标 return true; // 已到达目标
} }
// 简单的移动逻辑 // 平滑移动逻辑(只在水平面)
const direction = targetPos.subtract(currentPos).normalize(); const direction2D = targetPos2D.subtract(currentPos2D).normalize();
const moveSpeed = speed || this.moveSpeed; const moveSpeed = speed || this.moveSpeed;
const deltaTime = 1/60; // 假设60fps const dt = deltaTime || 0.016; // 使用传入的deltaTime或默认值
// 计算移动距离,确保不会超过目标位置
const moveDistance = Math.min(moveSpeed * dt, distance);
const movement2D = direction2D.multiplyScalar(moveDistance);
// 新位置保持原有的Y轴位置
const newPosition = new Vec3(
currentPos.x + movement2D.x,
currentPos.y, // 保持Y轴不变
currentPos.z + movement2D.z
);
const newPosition = currentPos.add(direction.multiplyScalar(moveSpeed * deltaTime));
this.node.setWorldPosition(newPosition); this.node.setWorldPosition(newPosition);
this.isMoving = true;
// 减少日志输出频率
if (Date.now() - this.moveStartTime > 1000) { // 每秒输出一次
console.log(`${this.node.name}: 移动中 距离目标${distance.toFixed(2)}`);
this.moveStartTime = Date.now();
}
return false; // 还在移动中 return false; // 还在移动中
} }
@@ -263,26 +328,56 @@ export class UnitController extends Component {
} }
update(deltaTime: number) { update(deltaTime: number) {
// 更新行为树黑板中的时间相关变量 // 自动移动逻辑 - 如果有目标位置就自动移动
if (this.behaviorTreeManager) { if (this.targetPosition && !this.targetPosition.equals(Vec3.ZERO)) {
this.behaviorTreeManager.updateBlackboardValue('deltaTime', deltaTime); const arrived = this.moveToTarget(this.targetPosition, undefined, deltaTime);
this.behaviorTreeManager.updateBlackboardValue('currentTime', Date.now() / 1000); if (arrived) {
this.behaviorTreeManager.updateBlackboardValue('worldPosition', this.node.worldPosition); // 不要清除目标位置,让行为树决定下一步动作
this.isMoving = false;
// 更新距离信息 // 更新黑板状态
if (this.targetPosition) { if (this.behaviorTreeManager) {
const distance = this.node.worldPosition.subtract(this.targetPosition).length(); this.behaviorTreeManager.updateBlackboardValue('isMoving', false);
this.behaviorTreeManager.updateBlackboardValue('distanceToTarget', distance); // 不要设置hasTarget为false让行为树自己管理
this.behaviorTreeManager.updateBlackboardValue('isInAttackRange', distance <= this.attackRange); }
this.behaviorTreeManager.updateBlackboardValue('isCloseToTarget', distance <= 1.0); } else {
this.isMoving = true;
// 更新移动状态到黑板
if (this.behaviorTreeManager) {
this.behaviorTreeManager.updateBlackboardValue('isMoving', true);
}
}
} }
// 更新状态标志 // 更新行为树黑板中的核心变量
this.behaviorTreeManager.updateBlackboardValue('isIdle', this.currentCommand === 'idle'); if (this.behaviorTreeManager) {
this.behaviorTreeManager.updateBlackboardValue('isMoving', this.currentCommand === 'move'); // 基础属性更新
this.behaviorTreeManager.updateBlackboardValue('isAttacking', this.currentCommand === 'attack'); this.behaviorTreeManager.updateBlackboardValue('currentHealth', this.currentHealth);
this.behaviorTreeManager.updateBlackboardValue('isGathering', this.currentCommand === 'gather'); this.behaviorTreeManager.updateBlackboardValue('healthPercentage', this.currentHealth / this.maxHealth);
this.behaviorTreeManager.updateBlackboardValue('isPatrolling', this.currentCommand === 'patrol'); this.behaviorTreeManager.updateBlackboardValue('isLowHealth', this.currentHealth < this.maxHealth * 0.3);
// 命令状态更新
this.behaviorTreeManager.updateBlackboardValue('currentCommand', this.currentCommand);
this.behaviorTreeManager.updateBlackboardValue('hasTarget', this.targetPosition && !this.targetPosition.equals(Vec3.ZERO));
this.behaviorTreeManager.updateBlackboardValue('targetPosition', this.targetPosition);
this.behaviorTreeManager.updateBlackboardValue('isSelected', this.isSelected);
this.behaviorTreeManager.updateBlackboardValue('isMoving', this.isMoving);
// 位置信息更新
this.behaviorTreeManager.updateBlackboardValue('worldPosition', this.node.worldPosition);
// 根据单位类型设置特定的黑板变量
if (this.unitType === 'worker') {
// 工人特有的变量
// 这里可以添加工人特有的状态更新
} else if (this.unitType === 'soldier') {
// 士兵特有的变量
this.behaviorTreeManager.updateBlackboardValue('lastAttackTime', this.lastAttackTime);
} else if (this.unitType === 'scout') {
// 侦察兵特有的变量
// 这里可以添加侦察兵特有的状态更新
}
} }
// 调试信息显示 // 调试信息显示