From 0f18a1979e0b1a766f9d359d2429d8b60d02ad60 Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Tue, 24 Jun 2025 19:34:37 +0800 Subject: [PATCH] rts-demo --- .../cocos-ecs/README_BehaviorTree_Demo.md | 122 + .../README_BehaviorTree_Game_Demo.md | 165 ++ .../assets/resources/scout-ai.bt.json | 859 ++++++ .../assets/resources/scout-ai.bt.json.meta | 11 + .../cocos-ecs/assets/resources/scout-ai.btree | 2598 +++++++++++++++++ .../assets/resources/scout-ai.btree.meta | 12 + .../assets/resources/soldier-ai.bt.json | 483 +++ .../assets/resources/soldier-ai.bt.json.meta | 11 + .../assets/resources/soldier-ai.btree | 1915 ++++++++++++ .../assets/resources/soldier-ai.btree.meta | 12 + .../assets/resources/worker-ai.bt.json | 380 +++ .../assets/resources/worker-ai.bt.json.meta | 11 + .../assets/resources/worker-ai.btree | 2028 +++++++++++++ .../assets/resources/worker-ai.btree.meta | 12 + .../cocos/cocos-ecs/assets/scenes/scene.scene | 2 +- .../cocos/cocos-ecs/assets/scripts/RTSDemo.ts | 236 ++ ...ealthComponent.ts.meta => RTSDemo.ts.meta} | 2 +- .../assets/scripts/{ecs => }/components.meta | 2 +- .../components/BehaviorTreeComponent.ts | 159 + .../BehaviorTreeComponent.ts.meta} | 2 +- .../scripts/components/BehaviorTreeManager.ts | 258 ++ .../BehaviorTreeManager.ts.meta} | 2 +- .../scripts/components/UnitComponent.ts | 345 +++ .../UnitComponent.ts.meta} | 2 +- .../scripts/components/UnitController.ts | 306 ++ .../scripts/components/UnitController.ts.meta | 9 + .../scripts/{ecs.meta => controllers.meta} | 2 +- .../controllers/RTSCameraController.ts | 203 ++ .../controllers/RTSCameraController.ts.meta | 9 + .../scripts/controllers/UIController.ts | 225 ++ .../scripts/controllers/UIController.ts.meta | 9 + .../assets/scripts/ecs/BehaviorTreeExample.ts | 270 -- .../scripts/ecs/BehaviorTreeTestScene.ts | 202 -- .../assets/scripts/ecs/ECSManager.ts | 99 - .../cocos-ecs/assets/scripts/ecs/README.md | 153 - .../assets/scripts/ecs/README.md.meta | 11 - .../scripts/ecs/components/HealthComponent.ts | 102 - .../ecs/components/PlayerInputComponent.ts | 124 - .../components/PlayerInputComponent.ts.meta | 9 - .../ecs/components/PositionComponent.ts | 62 - .../ecs/components/PositionComponent.ts.meta | 9 - .../ecs/components/VelocityComponent.ts | 94 - .../ecs/components/VelocityComponent.ts.meta | 9 - .../assets/scripts/ecs/examples.meta | 9 - .../assets/scripts/ecs/factories.meta | 9 - .../cocos-ecs/assets/scripts/ecs/scenes.meta | 9 - .../scripts/ecs/scenes/ExampleGameScene.ts | 316 -- .../ecs/scenes/ExampleGameScene.ts.meta | 9 - .../assets/scripts/ecs/scenes/GameScene.ts | 57 - .../scripts/ecs/scenes/GameScene.ts.meta | 9 - .../cocos-ecs/assets/scripts/ecs/systems.meta | 9 - .../scripts/ecs/systems/HealthSystem.ts | 228 -- .../scripts/ecs/systems/HealthSystem.ts.meta | 9 - .../scripts/ecs/systems/MovementSystem.ts | 99 - .../ecs/systems/MovementSystem.ts.meta | 9 - .../scripts/ecs/systems/PlayerInputSystem.ts | 173 -- .../ecs/systems/PlayerInputSystem.ts.meta | 9 - extensions/cocos/cocos-ecs/enemy-ai.bt.json | 214 ++ .../cocos/cocos-ecs/extensions/behaviour-tree | 2 +- extensions/cocos/cocos-ecs/package-lock.json | 9 +- extensions/cocos/cocos-ecs/package.json | 2 +- thirdparty/BehaviourTree-ai | 2 +- 62 files changed, 10606 insertions(+), 2113 deletions(-) create mode 100644 extensions/cocos/cocos-ecs/README_BehaviorTree_Demo.md create mode 100644 extensions/cocos/cocos-ecs/README_BehaviorTree_Game_Demo.md create mode 100644 extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json create mode 100644 extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json.meta create mode 100644 extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree create mode 100644 extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree.meta create mode 100644 extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json create mode 100644 extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json.meta create mode 100644 extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree create mode 100644 extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree.meta create mode 100644 extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json create mode 100644 extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json.meta create mode 100644 extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree create mode 100644 extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree.meta create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts rename extensions/cocos/cocos-ecs/assets/scripts/{ecs/components/HealthComponent.ts.meta => RTSDemo.ts.meta} (70%) rename extensions/cocos/cocos-ecs/assets/scripts/{ecs => }/components.meta (70%) create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts rename extensions/cocos/cocos-ecs/assets/scripts/{ecs/BehaviorTreeTestScene.ts.meta => components/BehaviorTreeComponent.ts.meta} (70%) create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts rename extensions/cocos/cocos-ecs/assets/scripts/{ecs/BehaviorTreeExample.ts.meta => components/BehaviorTreeManager.ts.meta} (70%) create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts rename extensions/cocos/cocos-ecs/assets/scripts/{ecs/ECSManager.ts.meta => components/UnitComponent.ts.meta} (70%) create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts.meta rename extensions/cocos/cocos-ecs/assets/scripts/{ecs.meta => controllers.meta} (70%) create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts.meta create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts create mode 100644 extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/examples.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/factories.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts.meta delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts delete mode 100644 extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts.meta create mode 100644 extensions/cocos/cocos-ecs/enemy-ai.bt.json diff --git a/extensions/cocos/cocos-ecs/README_BehaviorTree_Demo.md b/extensions/cocos/cocos-ecs/README_BehaviorTree_Demo.md new file mode 100644 index 00000000..5bee10d8 --- /dev/null +++ b/extensions/cocos/cocos-ecs/README_BehaviorTree_Demo.md @@ -0,0 +1,122 @@ +# 行为树 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游戏开发的起点。 \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/README_BehaviorTree_Game_Demo.md b/extensions/cocos/cocos-ecs/README_BehaviorTree_Game_Demo.md new file mode 100644 index 00000000..a9a4210d --- /dev/null +++ b/extensions/cocos/cocos-ecs/README_BehaviorTree_Game_Demo.md @@ -0,0 +1,165 @@ +# 行为树游戏演示文档 + +## 概述 + +本演示展示了两个真实游戏场景的行为树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系统,为开发者提供了完整的参考实现。 \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json new file mode 100644 index 00000000..671816fd --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json @@ -0,0 +1,859 @@ +{ + "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" + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json.meta b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json.meta new file mode 100644 index 00000000..43ccbae3 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.bt.json.meta @@ -0,0 +1,11 @@ +{ + "ver": "2.0.1", + "importer": "json", + "imported": true, + "uuid": "1fb4b238-4ceb-4daa-817a-ac745bf598ca", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree new file mode 100644 index 00000000..92000bf7 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree @@ -0,0 +1,2598 @@ +{ + "nodes": [ + { + "id": "root", + "type": "root", + "name": "侦察兵AI根节点", + "position": { + "x": 400, + "y": 50 + }, + "properties": {}, + "children": [ + "main-selector" + ], + "x": 2115, + "y": 50, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "main-selector", + "type": "selector", + "name": "主选择器", + "position": { + "x": 400, + "y": 150 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "根据优先级选择行为:生存 > 命令执行 > 自主侦察", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "survival-sequence", + "command-sequence", + "autonomous-sequence" + ], + "x": 2125, + "y": 180, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "survival-sequence", + "type": "sequence", + "name": "生存序列", + "position": { + "x": 200, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "处理威胁和生存相关行为", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "threat-detection" + ], + "x": 860, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "threat-detection", + "type": "conditional-decorator", + "name": "威胁检测", + "position": { + "x": 150, + "y": 350 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "检测周围是否有威胁", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "threatDetected", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "survival-selector" + ], + "x": 860, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "threatDetected", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "survival-selector", + "type": "selector", + "name": "生存选择器", + "position": { + "x": 200, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "选择合适的生存策略", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "stealth-escape", + "evasive-maneuver", + "emergency-retreat" + ], + "x": 860, + "y": 874.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "stealth-escape", + "type": "sequence", + "name": "隐蔽脱离", + "position": { + "x": 100, + "y": 550 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "使用隐蔽能力脱离危险", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "can-stealth-check", + "activate-stealth", + "stealth-retreat" + ], + "x": 630, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "can-stealth-check", + "type": "conditional-decorator", + "name": "隐蔽能力检查", + "position": { + "x": 50, + "y": 650 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "stealthAvailable", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "activate-stealth" + ], + "x": 400, + "y": 1266.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "stealthAvailable", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "activate-stealth", + "type": "event-action", + "name": "激活隐蔽", + "position": { + "x": 100, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "activate-stealth", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "激活隐蔽模式", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 630, + "y": 1266.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "stealth-retreat", + "type": "event-action", + "name": "隐蔽撤退", + "position": { + "x": 150, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "stealth-retreat", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "在隐蔽状态下撤退", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 860, + "y": 1266.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "evasive-maneuver", + "type": "event-action", + "name": "规避机动", + "position": { + "x": 200, + "y": 550 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "evasive-maneuver", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行规避机动动作", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1090, + "y": 1070.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "emergency-retreat", + "type": "event-action", + "name": "紧急撤退", + "position": { + "x": 300, + "y": 550 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "emergency-retreat", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "快速撤退到安全区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1320, + "y": 1070.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "command-sequence", + "type": "sequence", + "name": "命令执行", + "position": { + "x": 400, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行玩家发布的侦察命令", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "has-command-check" + ], + "x": 2125, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "has-command-check", + "type": "conditional-decorator", + "name": "命令检查", + "position": { + "x": 350, + "y": 350 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "检查是否有待执行的命令", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasTarget", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "command-selector" + ], + "x": 2125, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasTarget", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "command-selector", + "type": "selector", + "name": "命令选择器", + "position": { + "x": 400, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "根据命令类型选择执行方式", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "scout-command", + "move-command", + "observe-command", + "patrol-command" + ], + "x": 2125, + "y": 874.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "scout-command", + "type": "conditional-decorator", + "name": "侦察命令", + "position": { + "x": 300, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行区域侦察任务", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "scout" + } + }, + "children": [ + "scout-sequence" + ], + "x": 1780, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "scout" + } + } + }, + { + "id": "scout-sequence", + "type": "sequence", + "name": "侦察序列", + "position": { + "x": 300, + "y": 750 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "完整的侦察流程", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "approach-carefully", + "scan-area", + "report-findings" + ], + "x": 1780, + "y": 1373.8000000000002, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "approach-carefully", + "type": "event-action", + "name": "谨慎接近", + "position": { + "x": 200, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "approach-carefully", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "谨慎接近目标区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1550, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "scan-area", + "type": "event-action", + "name": "扫描区域", + "position": { + "x": 300, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "scan-area", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "扫描并记录区域信息", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1780, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "report-findings", + "type": "event-action", + "name": "报告发现", + "position": { + "x": 400, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "report-findings", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "向指挥部报告侦察结果", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2010, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "move-command", + "type": "conditional-decorator", + "name": "移动命令", + "position": { + "x": 400, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行移动到目标位置", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "move" + } + }, + "children": [ + "stealth-move" + ], + "x": 2240, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "move" + } + } + }, + { + "id": "stealth-move", + "type": "event-action", + "name": "隐蔽移动", + "position": { + "x": 400, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "stealth-move", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "以隐蔽方式移动到目标位置", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2240, + "y": 1373.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "observe-command", + "type": "conditional-decorator", + "name": "观察命令", + "position": { + "x": 500, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行目标观察任务", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "observe" + } + }, + "children": [ + "observe-target" + ], + "x": 2470, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "observe" + } + } + }, + { + "id": "observe-target", + "type": "event-action", + "name": "观察目标", + "position": { + "x": 500, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "observe-target", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "持续观察指定目标", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2470, + "y": 1373.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-command", + "type": "conditional-decorator", + "name": "巡逻命令", + "position": { + "x": 600, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行区域巡逻", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "patrol" + } + }, + "children": [ + "reconnaissance-patrol" + ], + "x": 2700, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "patrol" + } + } + }, + { + "id": "reconnaissance-patrol", + "type": "event-action", + "name": "侦察巡逻", + "position": { + "x": 600, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "reconnaissance-patrol", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "在指定区域进行侦察巡逻", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2700, + "y": 1373.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "autonomous-sequence", + "type": "sequence", + "name": "自主行为", + "position": { + "x": 600, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "没有命令时的自主侦察行为", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "autonomous-selector" + ], + "x": 3390, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "autonomous-selector", + "type": "selector", + "name": "自主选择器", + "position": { + "x": 600, + "y": 350 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "选择自主行为模式", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "explore-unknown", + "monitor-area", + "return-to-base" + ], + "x": 3390, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "explore-unknown", + "type": "sequence", + "name": "探索未知区域", + "position": { + "x": 550, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "自主探索未知区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "has-unknown-area", + "explore-action" + ], + "x": 3045, + "y": 768, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "has-unknown-area", + "type": "conditional-decorator", + "name": "未知区域检查", + "position": { + "x": 500, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasUnknownArea", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "explore-action" + ], + "x": 2930, + "y": 964, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasUnknownArea", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "explore-action", + "type": "event-action", + "name": "探索行动", + "position": { + "x": 550, + "y": 650 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "explore-unknown-area", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "探索最近的未知区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 3160, + "y": 964, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "monitor-area", + "type": "sequence", + "name": "监控区域", + "position": { + "x": 650, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "监控重要区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "has-monitoring-target", + "monitor-action" + ], + "x": 3505, + "y": 768, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "has-monitoring-target", + "type": "conditional-decorator", + "name": "监控目标检查", + "position": { + "x": 600, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasMonitoringTarget", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "monitor-action" + ], + "x": 3390, + "y": 964, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasMonitoringTarget", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "monitor-action", + "type": "event-action", + "name": "监控行动", + "position": { + "x": 650, + "y": 650 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "monitor-strategic-area", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "监控战略重要区域", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 3620, + "y": 964, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "return-to-base", + "type": "event-action", + "name": "返回基地", + "position": { + "x": 750, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "return-to-base", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "返回基地待命", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 3850, + "y": 768, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + } + ], + "connections": [ + { + "id": "root-main-selector", + "sourceId": "root", + "targetId": "main-selector", + "path": "M 2195 128 C 2195 158 2205 152 2205 182", + "active": false + }, + { + "id": "main-selector-survival-sequence", + "sourceId": "main-selector", + "targetId": "survival-sequence", + "path": "M 2205 278 C 2205 328 940 328 940 378", + "active": false + }, + { + "id": "main-selector-command-sequence", + "sourceId": "main-selector", + "targetId": "command-sequence", + "path": "M 2205 278 C 2205 328 2205 328 2205 378", + "active": false + }, + { + "id": "main-selector-autonomous-sequence", + "sourceId": "main-selector", + "targetId": "autonomous-sequence", + "path": "M 2205 278 C 2205 328 3470 328 3470 378", + "active": false + }, + { + "id": "survival-sequence-threat-detection", + "sourceId": "survival-sequence", + "targetId": "threat-detection", + "path": "M 940 474 C 940 524 970 524 970 574", + "active": false + }, + { + "id": "threat-detection-survival-selector", + "sourceId": "threat-detection", + "targetId": "survival-selector", + "path": "M 970 757.78125 C 970 817.3359375 940 817.3359375 940 876.890625", + "active": false + }, + { + "id": "survival-selector-stealth-escape", + "sourceId": "survival-selector", + "targetId": "stealth-escape", + "path": "M 940 972.890625 C 940 1022.890625 710 1022.890625 710 1072.890625", + "active": false + }, + { + "id": "survival-selector-evasive-maneuver", + "sourceId": "survival-selector", + "targetId": "evasive-maneuver", + "path": "M 940 972.890625 C 940 1022.890625 1170 1022.890625 1170 1072.890625", + "active": false + }, + { + "id": "survival-selector-emergency-retreat", + "sourceId": "survival-selector", + "targetId": "emergency-retreat", + "path": "M 940 972.890625 C 940 1022.890625 1400 1022.890625 1400 1072.890625", + "active": false + }, + { + "id": "stealth-escape-can-stealth-check", + "sourceId": "stealth-escape", + "targetId": "can-stealth-check", + "path": "M 710 1168.890625 C 710 1218.890625 510 1218.890625 510 1268.890625", + "active": false + }, + { + "id": "stealth-escape-activate-stealth", + "sourceId": "stealth-escape", + "targetId": "activate-stealth", + "path": "M 710 1168.890625 C 710 1218.890625 710 1218.890625 710 1268.890625", + "active": false + }, + { + "id": "stealth-escape-stealth-retreat", + "sourceId": "stealth-escape", + "targetId": "stealth-retreat", + "path": "M 710 1168.890625 C 710 1218.890625 940 1218.890625 940 1268.890625", + "active": false + }, + { + "id": "can-stealth-check-activate-stealth", + "sourceId": "can-stealth-check", + "targetId": "activate-stealth", + "path": "M 510 1452.671875 C 510 1532.671875 710 1188.890625 710 1268.890625", + "active": false + }, + { + "id": "command-sequence-has-command-check", + "sourceId": "command-sequence", + "targetId": "has-command-check", + "path": "M 2205 474 C 2205 524 2235 524 2235 574", + "active": false + }, + { + "id": "has-command-check-command-selector", + "sourceId": "has-command-check", + "targetId": "command-selector", + "path": "M 2235 757.78125 C 2235 817.3359375 2205 817.3359375 2205 876.890625", + "active": false + }, + { + "id": "command-selector-scout-command", + "sourceId": "command-selector", + "targetId": "scout-command", + "path": "M 2205 972.890625 C 2205 1022.890625 1890 1022.890625 1890 1072.890625", + "active": false + }, + { + "id": "command-selector-move-command", + "sourceId": "command-selector", + "targetId": "move-command", + "path": "M 2205 972.890625 C 2205 1022.890625 2350 1022.890625 2350 1072.890625", + "active": false + }, + { + "id": "command-selector-observe-command", + "sourceId": "command-selector", + "targetId": "observe-command", + "path": "M 2205 972.890625 C 2205 1022.890625 2580 1022.890625 2580 1072.890625", + "active": false + }, + { + "id": "command-selector-patrol-command", + "sourceId": "command-selector", + "targetId": "patrol-command", + "path": "M 2205 972.890625 C 2205 1022.890625 2810 1022.890625 2810 1072.890625", + "active": false + }, + { + "id": "scout-command-scout-sequence", + "sourceId": "scout-command", + "targetId": "scout-sequence", + "path": "M 1890 1256.671875 C 1890 1316.234375 1860 1316.234375 1860 1375.796875", + "active": false + }, + { + "id": "scout-sequence-approach-carefully", + "sourceId": "scout-sequence", + "targetId": "approach-carefully", + "path": "M 1860 1471.796875 C 1860 1521.796875 1630 1521.796875 1630 1571.796875", + "active": false + }, + { + "id": "scout-sequence-scan-area", + "sourceId": "scout-sequence", + "targetId": "scan-area", + "path": "M 1860 1471.796875 C 1860 1521.796875 1860 1521.796875 1860 1571.796875", + "active": false + }, + { + "id": "scout-sequence-report-findings", + "sourceId": "scout-sequence", + "targetId": "report-findings", + "path": "M 1860 1471.796875 C 1860 1521.796875 2090 1521.796875 2090 1571.796875", + "active": false + }, + { + "id": "move-command-stealth-move", + "sourceId": "move-command", + "targetId": "stealth-move", + "path": "M 2350 1256.671875 C 2350 1316.234375 2320 1316.234375 2320 1375.796875", + "active": false + }, + { + "id": "observe-command-observe-target", + "sourceId": "observe-command", + "targetId": "observe-target", + "path": "M 2580 1256.671875 C 2580 1316.234375 2550 1316.234375 2550 1375.796875", + "active": false + }, + { + "id": "patrol-command-reconnaissance-patrol", + "sourceId": "patrol-command", + "targetId": "reconnaissance-patrol", + "path": "M 2810 1256.671875 C 2810 1316.234375 2780 1316.234375 2780 1375.796875", + "active": false + }, + { + "id": "autonomous-sequence-autonomous-selector", + "sourceId": "autonomous-sequence", + "targetId": "autonomous-selector", + "path": "M 3470 474 C 3470 524 3470 524 3470 574", + "active": false + }, + { + "id": "autonomous-selector-explore-unknown", + "sourceId": "autonomous-selector", + "targetId": "explore-unknown", + "path": "M 3470 670 C 3470 720 3125 720 3125 770", + "active": false + }, + { + "id": "autonomous-selector-monitor-area", + "sourceId": "autonomous-selector", + "targetId": "monitor-area", + "path": "M 3470 670 C 3470 720 3585 720 3585 770", + "active": false + }, + { + "id": "autonomous-selector-return-to-base", + "sourceId": "autonomous-selector", + "targetId": "return-to-base", + "path": "M 3470 670 C 3470 720 3930 720 3930 770", + "active": false + }, + { + "id": "explore-unknown-has-unknown-area", + "sourceId": "explore-unknown", + "targetId": "has-unknown-area", + "path": "M 3125 866 C 3125 916 3040 916 3040 966", + "active": false + }, + { + "id": "explore-unknown-explore-action", + "sourceId": "explore-unknown", + "targetId": "explore-action", + "path": "M 3125 866 C 3125 916 3240 916 3240 966", + "active": false + }, + { + "id": "has-unknown-area-explore-action", + "sourceId": "has-unknown-area", + "targetId": "explore-action", + "path": "M 3040 1149.78125 C 3040 1229.78125 3240 886 3240 966", + "active": false + }, + { + "id": "monitor-area-has-monitoring-target", + "sourceId": "monitor-area", + "targetId": "has-monitoring-target", + "path": "M 3585 866 C 3585 916 3500 916 3500 966", + "active": false + }, + { + "id": "monitor-area-monitor-action", + "sourceId": "monitor-area", + "targetId": "monitor-action", + "path": "M 3585 866 C 3585 916 3700 916 3700 966", + "active": false + }, + { + "id": "has-monitoring-target-monitor-action", + "sourceId": "has-monitoring-target", + "targetId": "monitor-action", + "path": "M 3500 1149.78125 C 3500 1229.78125 3700 886 3700 966", + "active": false + } + ], + "metadata": { + "name": "assets/resources/scout-ai.btree", + "created": "2025-06-24T09:47:19.046Z", + "version": "1.0" + }, + "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": "收集的情报数据" + } + ] +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree.meta b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree.meta new file mode 100644 index 00000000..d93248c6 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/scout-ai.btree.meta @@ -0,0 +1,12 @@ +{ + "ver": "1.0.0", + "importer": "*", + "imported": true, + "uuid": "96872e28-7488-4d80-906b-edcc3511c84b", + "files": [ + ".btree", + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json new file mode 100644 index 00000000..bf95352f --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json @@ -0,0 +1,483 @@ +{ + "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展示了完整的战斗单位行为模式,包括多种攻击方式、战术撤退、巡逻警戒等军事行为的智能决策。" + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json.meta b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json.meta new file mode 100644 index 00000000..c7d782bc --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.bt.json.meta @@ -0,0 +1,11 @@ +{ + "ver": "2.0.1", + "importer": "json", + "imported": true, + "uuid": "a71fbedb-9435-4637-b7a5-e0fb8b99d3c1", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree new file mode 100644 index 00000000..a71c25b0 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree @@ -0,0 +1,1915 @@ +{ + "nodes": [ + { + "id": "root", + "type": "root", + "name": "士兵AI根节点", + "position": { + "x": 400, + "y": 50 + }, + "properties": {}, + "children": [ + "main-selector" + ], + "x": 2230, + "y": 50, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "main-selector", + "type": "selector", + "name": "主行为选择器", + "position": { + "x": 400, + "y": 150 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "Self", + "LowerPriority", + "Both" + ], + "required": false + } + }, + "children": [ + "retreat-behavior", + "combat-behavior", + "patrol-behavior", + "standby-behavior" + ], + "x": 2240, + "y": 180, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "retreat-behavior", + "type": "conditional-decorator", + "name": "撤退行为", + "position": { + "x": 150, + "y": 250 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "retreat-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "shouldRetreat", + "operator": "equal", + "compareValue": true + } + }, + "x": 630, + "y": 358, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "shouldRetreat", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "retreat-sequence", + "type": "sequence", + "name": "撤退序列", + "position": { + "x": 150, + "y": 350 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "set-retreat-state", + "call-for-help", + "retreat-move" + ], + "x": 630, + "y": 637.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "set-retreat-state", + "type": "set-blackboard-value", + "name": "设置撤退状态", + "position": { + "x": 50, + "y": 450 + }, + "properties": { + "variableName": { + "name": "变量名", + "type": "string", + "value": "currentState", + "description": "要设置的黑板变量名", + "required": true + }, + "value": { + "name": "值", + "type": "string", + "value": "retreating", + "description": "要设置的值", + "required": false + }, + "sourceVariable": { + "name": "源变量名", + "type": "string", + "value": "", + "description": "从另一个黑板变量复制值", + "required": false + }, + "force": { + "name": "强制设置", + "type": "boolean", + "value": false, + "description": "是否忽略只读限制", + "required": false + } + }, + "children": [], + "x": 400, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "call-for-help", + "type": "event-action", + "name": "呼叫支援", + "position": { + "x": 150, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "call-for-help", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 630, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "retreat-move", + "type": "event-action", + "name": "撤退移动", + "position": { + "x": 250, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "retreat-to-safety", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 860, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "combat-behavior", + "type": "conditional-decorator", + "name": "战斗行为", + "position": { + "x": 350, + "y": 250 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "combat-selector" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasEnemy", + "operator": "equal", + "compareValue": true + } + }, + "x": 1895, + "y": 358, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasEnemy", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "combat-selector", + "type": "selector", + "name": "战斗选择器", + "position": { + "x": 350, + "y": 350 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "Self", + "LowerPriority", + "Both" + ], + "required": false + } + }, + "children": [ + "ranged-attack", + "close-combat", + "chase-enemy" + ], + "x": 1895, + "y": 637.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "ranged-attack", + "type": "conditional-decorator", + "name": "远程攻击", + "position": { + "x": 250, + "y": 450 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "ranged-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "isInRangedRange", + "operator": "equal", + "compareValue": true + } + }, + "x": 1320, + "y": 815.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "isInRangedRange", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "ranged-sequence", + "type": "sequence", + "name": "远程攻击序列", + "position": { + "x": 250, + "y": 550 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "aim-target", + "ranged-cooldown-check", + "fire-ranged" + ], + "x": 1320, + "y": 1095, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "aim-target", + "type": "event-action", + "name": "瞄准目标", + "position": { + "x": 150, + "y": 650 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "aim-at-target", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 1090, + "y": 1273, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "ranged-cooldown-check", + "type": "conditional-decorator", + "name": "远程冷却检查", + "position": { + "x": 250, + "y": 650 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "execute-ranged" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "canRangedAttack", + "operator": "equal", + "compareValue": true + } + }, + "x": 1320, + "y": 1273, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "canRangedAttack", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "execute-ranged", + "type": "event-action", + "name": "执行远程攻击", + "position": { + "x": 250, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "ranged-attack", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 1320, + "y": 1552.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "fire-ranged", + "type": "log-action", + "name": "远程攻击日志", + "position": { + "x": 350, + "y": 650 + }, + "properties": { + "message": { + "name": "日志消息", + "type": "string", + "value": "士兵执行远程攻击", + "description": "要记录的日志消息", + "required": true + }, + "logLevel": { + "name": "日志级别", + "type": "select", + "value": "info", + "description": "日志输出级别", + "options": [ + "debug", + "info", + "warn", + "error" + ], + "required": false + } + }, + "children": [], + "x": 1550, + "y": 1273, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "close-combat", + "type": "conditional-decorator", + "name": "近战攻击", + "position": { + "x": 350, + "y": 450 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "melee-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "isInMeleeRange", + "operator": "equal", + "compareValue": true + } + }, + "x": 2010, + "y": 815.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "isInMeleeRange", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "melee-sequence", + "type": "sequence", + "name": "近战攻击序列", + "position": { + "x": 350, + "y": 550 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "melee-cooldown-check", + "execute-melee", + "melee-log" + ], + "x": 2010, + "y": 1095, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "melee-cooldown-check", + "type": "conditional-decorator", + "name": "近战冷却检查", + "position": { + "x": 300, + "y": 650 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "melee-attack" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "canMeleeAttack", + "operator": "equal", + "compareValue": true + } + }, + "x": 1780, + "y": 1273, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "canMeleeAttack", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "melee-attack", + "type": "event-action", + "name": "近战攻击", + "position": { + "x": 300, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "melee-attack", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 1780, + "y": 1552.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "execute-melee", + "type": "set-blackboard-value", + "name": "更新近战冷却", + "position": { + "x": 350, + "y": 650 + }, + "properties": { + "variableName": { + "name": "变量名", + "type": "string", + "value": "lastMeleeTime", + "description": "要设置的黑板变量名", + "required": true + }, + "value": { + "name": "值", + "type": "string", + "value": "currentTime", + "description": "要设置的值", + "required": false + }, + "sourceVariable": { + "name": "源变量名", + "type": "string", + "value": "", + "description": "从另一个黑板变量复制值", + "required": false + }, + "force": { + "name": "强制设置", + "type": "boolean", + "value": false, + "description": "是否忽略只读限制", + "required": false + } + }, + "children": [], + "x": 2010, + "y": 1273, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "melee-log", + "type": "log-action", + "name": "近战攻击日志", + "position": { + "x": 400, + "y": 650 + }, + "properties": { + "message": { + "name": "日志消息", + "type": "string", + "value": "士兵执行近战攻击", + "description": "要记录的日志消息", + "required": true + }, + "logLevel": { + "name": "日志级别", + "type": "select", + "value": "info", + "description": "日志输出级别", + "options": [ + "debug", + "info", + "warn", + "error" + ], + "required": false + } + }, + "children": [], + "x": 2240, + "y": 1273, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "chase-enemy", + "type": "sequence", + "name": "追击敌人", + "position": { + "x": 450, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "set-chase-state", + "move-to-enemy" + ], + "x": 2585, + "y": 815.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "set-chase-state", + "type": "set-blackboard-value", + "name": "设置追击状态", + "position": { + "x": 400, + "y": 550 + }, + "properties": { + "variableName": { + "name": "变量名", + "type": "string", + "value": "currentState", + "description": "要设置的黑板变量名", + "required": true + }, + "value": { + "name": "值", + "type": "string", + "value": "chasing", + "description": "要设置的值", + "required": false + }, + "sourceVariable": { + "name": "源变量名", + "type": "string", + "value": "", + "description": "从另一个黑板变量复制值", + "required": false + }, + "force": { + "name": "强制设置", + "type": "boolean", + "value": false, + "description": "是否忽略只读限制", + "required": false + } + }, + "children": [], + "x": 2470, + "y": 993.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "move-to-enemy", + "type": "event-action", + "name": "移动到敌人", + "position": { + "x": 500, + "y": 550 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "move-to-target", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 2700, + "y": 993.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-behavior", + "type": "conditional-decorator", + "name": "巡逻行为", + "position": { + "x": 550, + "y": 250 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "children": [ + "patrol-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "patrol" + } + }, + "x": 3275, + "y": 358, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "patrol" + } + } + }, + { + "id": "patrol-sequence", + "type": "sequence", + "name": "巡逻序列", + "position": { + "x": 550, + "y": 350 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "set-patrol-state", + "patrol-move", + "patrol-scan", + "patrol-wait" + ], + "x": 3275, + "y": 637.5, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "set-patrol-state", + "type": "set-blackboard-value", + "name": "设置巡逻状态", + "position": { + "x": 450, + "y": 450 + }, + "properties": { + "variableName": { + "name": "变量名", + "type": "string", + "value": "currentState", + "description": "要设置的黑板变量名", + "required": true + }, + "value": { + "name": "值", + "type": "string", + "value": "patrolling", + "description": "要设置的值", + "required": false + }, + "sourceVariable": { + "name": "源变量名", + "type": "string", + "value": "", + "description": "从另一个黑板变量复制值", + "required": false + }, + "force": { + "name": "强制设置", + "type": "boolean", + "value": false, + "description": "是否忽略只读限制", + "required": false + } + }, + "children": [], + "x": 2930, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-move", + "type": "event-action", + "name": "巡逻移动", + "position": { + "x": 550, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "patrol-move", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 3160, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-scan", + "type": "event-action", + "name": "扫描敌人", + "position": { + "x": 650, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "scan-for-enemies", + "description": "要触发的事件名称", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + } + }, + "children": [], + "x": 3390, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-wait", + "type": "wait-action", + "name": "巡逻等待", + "position": { + "x": 750, + "y": 450 + }, + "properties": { + "waitTime": { + "name": "等待时间", + "type": "number", + "value": 2, + "description": "等待的时间(秒)", + "required": true + }, + "useExternalTime": { + "name": "使用外部时间", + "type": "boolean", + "value": false, + "description": "是否使用上下文提供的deltaTime,否则使用内部时间计算", + "required": false + } + }, + "children": [], + "x": 3620, + "y": 815.5, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "standby-behavior", + "type": "sequence", + "name": "待命行为", + "position": { + "x": 750, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + } + }, + "children": [ + "set-standby-state", + "standby-wait" + ], + "x": 3965, + "y": 358, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "set-standby-state", + "type": "set-blackboard-value", + "name": "设置待命状态", + "position": { + "x": 700, + "y": 350 + }, + "properties": { + "variableName": { + "name": "变量名", + "type": "string", + "value": "currentState", + "description": "要设置的黑板变量名", + "required": true + }, + "value": { + "name": "值", + "type": "string", + "value": "standby", + "description": "要设置的值", + "required": false + }, + "sourceVariable": { + "name": "源变量名", + "type": "string", + "value": "", + "description": "从另一个黑板变量复制值", + "required": false + }, + "force": { + "name": "强制设置", + "type": "boolean", + "value": false, + "description": "是否忽略只读限制", + "required": false + } + }, + "children": [], + "x": 3850, + "y": 536, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + }, + { + "id": "standby-wait", + "type": "wait-action", + "name": "待命等待", + "position": { + "x": 800, + "y": 350 + }, + "properties": { + "waitTime": { + "name": "等待时间", + "type": "number", + "value": 1, + "description": "等待的时间(秒)", + "required": true + }, + "useExternalTime": { + "name": "使用外部时间", + "type": "boolean", + "value": false, + "description": "是否使用上下文提供的deltaTime,否则使用内部时间计算", + "required": false + } + }, + "children": [], + "x": 4080, + "y": 536, + "canHaveChildren": false, + "canHaveParent": true, + "hasError": false + } + ], + "connections": [ + { + "id": "root-main-selector", + "sourceId": "root", + "targetId": "main-selector", + "path": "M 2310 128 C 2310 158 2320 152 2320 182", + "active": false + }, + { + "id": "main-selector-retreat-behavior", + "sourceId": "main-selector", + "targetId": "retreat-behavior", + "path": "M 2320 278 C 2320 319 740 319 740 360", + "active": false + }, + { + "id": "main-selector-combat-behavior", + "sourceId": "main-selector", + "targetId": "combat-behavior", + "path": "M 2320 278 C 2320 319 2005 319 2005 360", + "active": false + }, + { + "id": "main-selector-patrol-behavior", + "sourceId": "main-selector", + "targetId": "patrol-behavior", + "path": "M 2320 278 C 2320 319 3385 319 3385 360", + "active": false + }, + { + "id": "main-selector-standby-behavior", + "sourceId": "main-selector", + "targetId": "standby-behavior", + "path": "M 2320 278 C 2320 319 4045 319 4045 360", + "active": false + }, + { + "id": "retreat-behavior-retreat-sequence", + "sourceId": "retreat-behavior", + "targetId": "retreat-sequence", + "path": "M 740 543.78125 C 740 591.640625 710 591.640625 710 639.5", + "active": false + }, + { + "id": "retreat-sequence-set-retreat-state", + "sourceId": "retreat-sequence", + "targetId": "set-retreat-state", + "path": "M 710 735.5 C 710 776.5 480 776.5 480 817.5", + "active": false + }, + { + "id": "retreat-sequence-call-for-help", + "sourceId": "retreat-sequence", + "targetId": "call-for-help", + "path": "M 710 735.5 C 710 776.5 710 776.5 710 817.5", + "active": false + }, + { + "id": "retreat-sequence-retreat-move", + "sourceId": "retreat-sequence", + "targetId": "retreat-move", + "path": "M 710 735.5 C 710 775.7634887695312 940.4739379882812 775.7634887695312 940.4739379882812 816.0269775390625", + "active": false + }, + { + "id": "combat-behavior-combat-selector", + "sourceId": "combat-behavior", + "targetId": "combat-selector", + "path": "M 2005 543.78125 C 2005 591.640625 1975 591.640625 1975 639.5", + "active": false + }, + { + "id": "combat-selector-ranged-attack", + "sourceId": "combat-selector", + "targetId": "ranged-attack", + "path": "M 1975 735.5 C 1975 776.5 1430 776.5 1430 817.5", + "active": false + }, + { + "id": "combat-selector-close-combat", + "sourceId": "combat-selector", + "targetId": "close-combat", + "path": "M 1975 735.5 C 1975 776.5 2120 776.5 2120 817.5", + "active": false + }, + { + "id": "combat-selector-chase-enemy", + "sourceId": "combat-selector", + "targetId": "chase-enemy", + "path": "M 1975 735.5 C 1975 776.5 2665 776.5 2665 817.5", + "active": false + }, + { + "id": "ranged-attack-ranged-sequence", + "sourceId": "ranged-attack", + "targetId": "ranged-sequence", + "path": "M 1430 1001.28125 C 1430 1049.140625 1400 1049.140625 1400 1097", + "active": false + }, + { + "id": "ranged-sequence-aim-target", + "sourceId": "ranged-sequence", + "targetId": "aim-target", + "path": "M 1400 1193 C 1400 1234 1170 1234 1170 1275", + "active": false + }, + { + "id": "ranged-sequence-ranged-cooldown-check", + "sourceId": "ranged-sequence", + "targetId": "ranged-cooldown-check", + "path": "M 1400 1193 C 1400 1234 1430 1234 1430 1275", + "active": false + }, + { + "id": "ranged-sequence-fire-ranged", + "sourceId": "ranged-sequence", + "targetId": "fire-ranged", + "path": "M 1400 1193 C 1400 1234 1630 1234 1630 1275", + "active": false + }, + { + "id": "ranged-cooldown-check-execute-ranged", + "sourceId": "ranged-cooldown-check", + "targetId": "execute-ranged", + "path": "M 1430 1458.78125 C 1430 1506.640625 1400 1506.640625 1400 1554.5", + "active": false + }, + { + "id": "close-combat-melee-sequence", + "sourceId": "close-combat", + "targetId": "melee-sequence", + "path": "M 2120 1001.28125 C 2120 1049.140625 2090 1049.140625 2090 1097", + "active": false + }, + { + "id": "melee-sequence-melee-cooldown-check", + "sourceId": "melee-sequence", + "targetId": "melee-cooldown-check", + "path": "M 2090 1193 C 2090 1234 1890 1234 1890 1275", + "active": false + }, + { + "id": "melee-sequence-execute-melee", + "sourceId": "melee-sequence", + "targetId": "execute-melee", + "path": "M 2090 1193 C 2090 1234 2090 1234 2090 1275", + "active": false + }, + { + "id": "melee-sequence-melee-log", + "sourceId": "melee-sequence", + "targetId": "melee-log", + "path": "M 2090 1193 C 2090 1234 2320 1234 2320 1275", + "active": false + }, + { + "id": "melee-cooldown-check-melee-attack", + "sourceId": "melee-cooldown-check", + "targetId": "melee-attack", + "path": "M 1890 1458.78125 C 1890 1506.640625 1860 1506.640625 1860 1554.5", + "active": false + }, + { + "id": "chase-enemy-set-chase-state", + "sourceId": "chase-enemy", + "targetId": "set-chase-state", + "path": "M 2665 913.5 C 2665 954.5 2550 954.5 2550 995.5", + "active": false + }, + { + "id": "chase-enemy-move-to-enemy", + "sourceId": "chase-enemy", + "targetId": "move-to-enemy", + "path": "M 2665 913.5 C 2665 954.5 2780 954.5 2780 995.5", + "active": false + }, + { + "id": "patrol-behavior-patrol-sequence", + "sourceId": "patrol-behavior", + "targetId": "patrol-sequence", + "path": "M 3385 543.78125 C 3385 591.640625 3355 591.640625 3355 639.5", + "active": false + }, + { + "id": "patrol-sequence-set-patrol-state", + "sourceId": "patrol-sequence", + "targetId": "set-patrol-state", + "path": "M 3355 735.5 C 3355 776.5 3010 776.5 3010 817.5", + "active": false + }, + { + "id": "patrol-sequence-patrol-move", + "sourceId": "patrol-sequence", + "targetId": "patrol-move", + "path": "M 3355 735.5 C 3355 776.5 3240 776.5 3240 817.5", + "active": false + }, + { + "id": "patrol-sequence-patrol-scan", + "sourceId": "patrol-sequence", + "targetId": "patrol-scan", + "path": "M 3355 735.5 C 3355 776.5 3470 776.5 3470 817.5", + "active": false + }, + { + "id": "patrol-sequence-patrol-wait", + "sourceId": "patrol-sequence", + "targetId": "patrol-wait", + "path": "M 3355 735.5 C 3355 776.5 3700 776.5 3700 817.5", + "active": false + }, + { + "id": "standby-behavior-set-standby-state", + "sourceId": "standby-behavior", + "targetId": "set-standby-state", + "path": "M 4045 456 C 4045 497 3930 497 3930 538", + "active": false + }, + { + "id": "standby-behavior-standby-wait", + "sourceId": "standby-behavior", + "targetId": "standby-wait", + "path": "M 4045 456 C 4045 497 4160 497 4160 538", + "active": false + } + ], + "metadata": { + "name": "assets/resources/soldier-ai.btree", + "created": "2025-06-24T10:16:48.539Z", + "version": "1.0" + }, + "blackboard": [ + { + "name": "currentState", + "type": "string", + "value": "standby", + "description": "士兵当前状态(standby、patrolling、chasing、attacking、retreating)" + }, + { + "name": "currentCommand", + "type": "string", + "value": "patrol", + "description": "当前接收的命令(patrol、attack、defend、move、standby)" + }, + { + "name": "hasEnemy", + "type": "boolean", + "value": false, + "description": "是否发现敌人" + }, + { + "name": "enemyDistance", + "type": "number", + "value": 999, + "description": "与最近敌人的距离" + }, + { + "name": "isInMeleeRange", + "type": "boolean", + "value": false, + "description": "是否在近战攻击范围内" + }, + { + "name": "isInRangedRange", + "type": "boolean", + "value": false, + "description": "是否在远程攻击范围内" + }, + { + "name": "canMeleeAttack", + "type": "boolean", + "value": true, + "description": "是否可以进行近战攻击(冷却检查)" + }, + { + "name": "canRangedAttack", + "type": "boolean", + "value": true, + "description": "是否可以进行远程攻击(冷却检查)" + }, + { + "name": "lastMeleeTime", + "type": "number", + "value": 0, + "description": "上次近战攻击时间" + }, + { + "name": "lastRangedTime", + "type": "number", + "value": 0, + "description": "上次远程攻击时间" + }, + { + "name": "meleeCooldown", + "type": "number", + "value": 1, + "description": "近战攻击冷却时间" + }, + { + "name": "rangedCooldown", + "type": "number", + "value": 2, + "description": "远程攻击冷却时间" + }, + { + "name": "meleeRange", + "type": "number", + "value": 2, + "description": "近战攻击范围" + }, + { + "name": "rangedRange", + "type": "number", + "value": 8, + "description": "远程攻击范围" + }, + { + "name": "shouldRetreat", + "type": "boolean", + "value": false, + "description": "是否应该撤退(生命值低或寡不敌众)" + }, + { + "name": "currentHealth", + "type": "number", + "value": 100, + "description": "当前生命值" + }, + { + "name": "maxHealth", + "type": "number", + "value": 100, + "description": "最大生命值" + }, + { + "name": "armor", + "type": "number", + "value": 10, + "description": "护甲值" + }, + { + "name": "moveSpeed", + "type": "number", + "value": 4, + "description": "移动速度" + }, + { + "name": "patrolRadius", + "type": "number", + "value": 10, + "description": "巡逻半径" + } + ] +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree.meta b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree.meta new file mode 100644 index 00000000..ec9ef030 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/soldier-ai.btree.meta @@ -0,0 +1,12 @@ +{ + "ver": "1.0.0", + "importer": "*", + "imported": true, + "uuid": "843934be-5d8e-49b3-93e5-34999ca6f50e", + "files": [ + ".btree", + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json new file mode 100644 index 00000000..ed5b0956 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json @@ -0,0 +1,380 @@ +{ + "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单位行为模式,包括生存、工作、建造等多种行为的优先级管理和状态切换。" + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json.meta b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json.meta new file mode 100644 index 00000000..710894f8 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.bt.json.meta @@ -0,0 +1,11 @@ +{ + "ver": "2.0.1", + "importer": "json", + "imported": true, + "uuid": "59141420-59cc-425f-b519-1073df8b93f8", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree new file mode 100644 index 00000000..30c2d413 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree @@ -0,0 +1,2028 @@ +{ + "nodes": [ + { + "id": "root", + "type": "root", + "name": "工人AI根节点", + "position": { + "x": 400, + "y": 50 + }, + "properties": {}, + "children": [ + "main-selector" + ], + "x": 1540, + "y": 50, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "main-selector", + "type": "selector", + "name": "主选择器", + "position": { + "x": 400, + "y": 150 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "根据优先级选择行为:紧急情况 > 命令执行 > 空闲行为", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "emergency-sequence", + "command-sequence", + "idle-sequence" + ], + "x": 1550, + "y": 180, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "emergency-sequence", + "type": "sequence", + "name": "紧急情况处理", + "position": { + "x": 200, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "处理生命值过低等紧急情况", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "low-health-check" + ], + "x": 400, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "low-health-check", + "type": "conditional-decorator", + "name": "生命值检查", + "position": { + "x": 150, + "y": 350 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "检查生命值是否过低", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "isLowHealth", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "retreat-action" + ], + "x": 400, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "isLowHealth", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "retreat-action", + "type": "event-action", + "name": "撤退到安全位置", + "position": { + "x": 150, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "retreat-to-safety", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "撤退到最近的安全建筑", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 400, + "y": 874.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "command-sequence", + "type": "sequence", + "name": "命令执行", + "position": { + "x": 400, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行玩家发布的命令", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "has-command-check" + ], + "x": 1320, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "has-command-check", + "type": "conditional-decorator", + "name": "命令检查", + "position": { + "x": 350, + "y": 350 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "检查是否有待执行的命令", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasTarget", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "command-selector" + ], + "x": 1320, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasTarget", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "command-selector", + "type": "selector", + "name": "命令选择器", + "position": { + "x": 400, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "根据命令类型选择执行方式", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "move-command", + "gather-command", + "build-command", + "repair-command" + ], + "x": 1320, + "y": 874.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "move-command", + "type": "sequence", + "name": "移动命令", + "position": { + "x": 250, + "y": 550 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行移动到目标位置", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "is-move-command", + "move-to-target" + ], + "x": 745, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "is-move-command", + "type": "conditional-decorator", + "name": "移动命令检查", + "position": { + "x": 200, + "y": 650 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "move" + } + }, + "children": [ + "move-to-target" + ], + "x": 630, + "y": 1266.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "move" + } + } + }, + { + "id": "move-to-target", + "type": "event-action", + "name": "移动到目标", + "position": { + "x": 200, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "move-to-target", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "移动到指定的目标位置", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 860, + "y": 1266.9, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "gather-command", + "type": "conditional-decorator", + "name": "收集命令", + "position": { + "x": 350, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行资源收集", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "gather" + } + }, + "children": [ + "gather-sequence" + ], + "x": 1320, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "gather" + } + } + }, + { + "id": "gather-sequence", + "type": "sequence", + "name": "收集序列", + "position": { + "x": 350, + "y": 750 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "寻找资源并收集", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "find-resource", + "gather-resource", + "return-resource" + ], + "x": 1320, + "y": 1373.8000000000002, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "find-resource", + "type": "event-action", + "name": "寻找资源", + "position": { + "x": 250, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "find-nearest-resource", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "寻找最近的可收集资源", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1090, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "gather-resource", + "type": "event-action", + "name": "收集资源", + "position": { + "x": 350, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "gather-resource", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "从资源点收集资源", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1320, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "return-resource", + "type": "event-action", + "name": "运输资源", + "position": { + "x": 450, + "y": 850 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "return-to-base", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "将收集的资源运回基地", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1550, + "y": 1569.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "build-command", + "type": "conditional-decorator", + "name": "建造命令", + "position": { + "x": 450, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行建筑建造", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "build" + } + }, + "children": [ + "build-structure" + ], + "x": 1780, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "build" + } + } + }, + { + "id": "build-structure", + "type": "event-action", + "name": "建造建筑", + "position": { + "x": 450, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "build-structure", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "在指定位置建造建筑", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 1780, + "y": 1373.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "repair-command", + "type": "conditional-decorator", + "name": "修理命令", + "position": { + "x": 550, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "执行建筑修理", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "repair" + } + }, + "children": [ + "repair-structure" + ], + "x": 2010, + "y": 1070.9, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "icon": "⚖️", + "properties": { + "variableName": "currentCommand", + "operator": "equal", + "compareValue": "repair" + } + } + }, + { + "id": "repair-structure", + "type": "event-action", + "name": "修理建筑", + "position": { + "x": 550, + "y": 750 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "repair-structure", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "修理受损的建筑", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2010, + "y": 1373.8000000000002, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "idle-sequence", + "type": "sequence", + "name": "空闲行为", + "position": { + "x": 600, + "y": 250 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "没有命令时的默认行为", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "idle-selector" + ], + "x": 2470, + "y": 376, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "idle-selector", + "type": "selector", + "name": "空闲选择器", + "position": { + "x": 600, + "y": 350 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "选择空闲时的行为", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "auto-gather", + "patrol-area", + "wait-action" + ], + "x": 2470, + "y": 572, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "auto-gather", + "type": "sequence", + "name": "自动收集", + "position": { + "x": 550, + "y": 450 + }, + "properties": { + "abortType": { + "name": "中止类型", + "type": "select", + "value": "None", + "description": "决定节点在何种情况下会被中止", + "options": [ + "None", + "LowerPriority", + "Self", + "Both" + ], + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "自动寻找并收集附近资源", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "children": [ + "has-nearby-resource" + ], + "x": 2240, + "y": 768, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "has-nearby-resource", + "type": "conditional-decorator", + "name": "附近资源检查", + "position": { + "x": 500, + "y": 550 + }, + "properties": { + "conditionType": { + "name": "条件类型", + "type": "select", + "value": "custom", + "description": "装饰器使用的条件类型", + "options": [ + "custom", + "random", + "hasComponent", + "hasTag", + "isActive", + "numericCompare", + "propertyExists" + ], + "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 + } + }, + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasNearbyResource", + "operator": "equal", + "compareValue": true + } + }, + "children": [ + "auto-gather-action" + ], + "x": 2240, + "y": 964, + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false, + "attachedCondition": { + "type": "blackboard-value-comparison", + "name": "黑板值比较", + "properties": { + "variableName": "hasNearbyResource", + "operator": "equal", + "compareValue": true + } + } + }, + { + "id": "auto-gather-action", + "type": "event-action", + "name": "自动收集执行", + "position": { + "x": 550, + "y": 650 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "auto-gather-resource", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "自动收集附近的资源", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2240, + "y": 1243.5, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "patrol-area", + "type": "event-action", + "name": "区域巡逻", + "position": { + "x": 650, + "y": 450 + }, + "properties": { + "eventName": { + "name": "事件名称", + "type": "string", + "value": "patrol-area", + "description": "要执行的事件名称(如:enemy.attack, player.move)", + "required": true + }, + "parameters": { + "name": "事件参数", + "type": "string", + "value": "{}", + "description": "传递给事件处理函数的参数(JSON格式)", + "required": false + }, + "timeout": { + "name": "超时时间", + "type": "number", + "value": 0, + "description": "事件执行超时时间(秒),0表示无限制", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "在指定区域内巡逻", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2470, + "y": 768, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + }, + { + "id": "wait-action", + "type": "wait-action", + "name": "等待", + "position": { + "x": 750, + "y": 450 + }, + "properties": { + "waitTime": { + "name": "等待时间", + "type": "number", + "value": 2, + "description": "等待时间(秒),必须大于0", + "required": true + }, + "useExternalTime": { + "name": "使用外部时间", + "type": "boolean", + "value": false, + "description": "是否使用上下文提供的deltaTime,否则使用内部时间计算", + "required": false + }, + "description": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": { + "name": "description", + "type": "string", + "value": "等待新的命令或任务", + "description": "", + "required": false + }, + "description": "", + "required": false + }, + "description": "", + "required": false + } + }, + "x": 2700, + "y": 768, + "children": [], + "canHaveChildren": true, + "canHaveParent": true, + "hasError": false + } + ], + "connections": [ + { + "id": "root-main-selector", + "sourceId": "root", + "targetId": "main-selector", + "path": "M 1629.5000712076821 128.000005086263 C 1629.5000712076821 158.000005086263 1639.5000712076821 152.0000076293945 1639.5000712076821 182.0000076293945", + "active": false + }, + { + "id": "main-selector-emergency-sequence", + "sourceId": "main-selector", + "targetId": "emergency-sequence", + "path": "M 1639.5000712076821 278.00003051757807 C 1639.5000712076821 328.00003051757807 480.000025431315 328.00003051757807 480.000025431315 378.00003051757807", + "active": false + }, + { + "id": "main-selector-command-sequence", + "sourceId": "main-selector", + "targetId": "command-sequence", + "path": "M 1639.5000712076821 278.00003051757807 C 1639.5000712076821 328.00003051757807 1409.5000712076821 328.00003051757807 1409.5000712076821 378.00003051757807", + "active": false + }, + { + "id": "main-selector-idle-sequence", + "sourceId": "main-selector", + "targetId": "idle-sequence", + "path": "M 1639.5000712076821 278.00003051757807 C 1639.5000712076821 328.00003051757807 2569.0001424153643 328.00003051757807 2569.0001424153643 378.00003051757807", + "active": false + }, + { + "id": "emergency-sequence-low-health-check", + "sourceId": "emergency-sequence", + "targetId": "low-health-check", + "path": "M 480.000025431315 474.000015258789 C 480.000025431315 524.000015258789 510.000025431315 524.000015258789 510.000025431315 574.000015258789", + "active": false + }, + { + "id": "low-health-check-retreat-action", + "sourceId": "low-health-check", + "targetId": "retreat-action", + "path": "M 510.000025431315 757.781270345052 C 510.000025431315 817.335968017578 480.000025431315 817.335968017578 480.000025431315 876.890665690104", + "active": false + }, + { + "id": "command-sequence-has-command-check", + "sourceId": "command-sequence", + "targetId": "has-command-check", + "path": "M 1409.5000712076821 474.000015258789 C 1409.5000712076821 524.000015258789 1439.5000712076821 524.000015258789 1439.5000712076821 574.000015258789", + "active": false + }, + { + "id": "has-command-check-command-selector", + "sourceId": "has-command-check", + "targetId": "command-selector", + "path": "M 1439.5000712076821 757.781270345052 C 1439.5000712076821 817.335968017578 1409.5000712076821 817.335968017578 1409.5000712076821 876.890665690104", + "active": false + }, + { + "id": "command-selector-move-command", + "sourceId": "command-selector", + "targetId": "move-command", + "path": "M 1409.5000712076821 972.89067586263 C 1409.5000712076821 1022.8906758626301 825.000025431315 1022.8906758626301 825.000025431315 1072.8906758626301", + "active": false + }, + { + "id": "command-selector-gather-command", + "sourceId": "command-selector", + "targetId": "gather-command", + "path": "M 1409.5000712076821 972.89067586263 C 1409.5000712076821 1022.8906758626301 1435.687561035156 1022.8906758626301 1435.687561035156 1072.8906758626301", + "active": false + }, + { + "id": "command-selector-build-command", + "sourceId": "command-selector", + "targetId": "build-command", + "path": "M 1409.5000712076821 972.89067586263 C 1409.5000712076821 1022.8906758626301 1903.2969156901038 1022.8906758626301 1903.2969156901038 1072.8906758626301", + "active": false + }, + { + "id": "command-selector-repair-command", + "sourceId": "command-selector", + "targetId": "repair-command", + "path": "M 1409.5000712076821 972.89067586263 C 1409.5000712076821 1022.8906758626301 2137.093811035156 1022.8906758626301 2137.093811035156 1072.8906758626301", + "active": false + }, + { + "id": "move-command-is-move-command", + "sourceId": "move-command", + "targetId": "is-move-command", + "path": "M 825.000025431315 1168.890635172526 C 825.000025431315 1218.890635172526 740.000025431315 1218.890635172526 740.000025431315 1268.890635172526", + "active": false + }, + { + "id": "move-command-move-to-target", + "sourceId": "move-command", + "targetId": "move-to-target", + "path": "M 825.000025431315 1168.890635172526 C 825.000025431315 1218.890635172526 940.00005086263 1218.890635172526 940.00005086263 1268.890635172526", + "active": false + }, + { + "id": "is-move-command-move-to-target", + "sourceId": "is-move-command", + "targetId": "move-to-target", + "path": "M 740.000025431315 1452.6719665527341 C 740.000025431315 1532.6719665527341 940.00005086263 1188.890635172526 940.00005086263 1268.890635172526", + "active": false + }, + { + "id": "gather-command-gather-sequence", + "sourceId": "gather-command", + "targetId": "gather-sequence", + "path": "M 1435.687561035156 1256.671905517578 C 1435.687561035156 1315.35161336263 1411.390686035156 1315.35161336263 1411.390686035156 1374.0313212076821", + "active": false + }, + { + "id": "gather-sequence-find-resource", + "sourceId": "gather-sequence", + "targetId": "find-resource", + "path": "M 1411.390686035156 1470.031280517578 C 1411.390686035156 1520.0312550862627 1181.390635172526 1520.0312550862627 1181.390635172526 1570.0312296549478", + "active": false + }, + { + "id": "gather-sequence-gather-resource", + "sourceId": "gather-sequence", + "targetId": "gather-resource", + "path": "M 1411.390686035156 1470.031280517578 C 1411.390686035156 1520.0312550862627 1411.390686035156 1520.0312550862627 1411.390686035156 1570.0312296549478", + "active": false + }, + { + "id": "gather-sequence-return-resource", + "sourceId": "gather-sequence", + "targetId": "return-resource", + "path": "M 1411.390686035156 1470.031280517578 C 1411.390686035156 1520.0312550862627 1641.390686035156 1520.0312550862627 1641.390686035156 1570.0312296549478", + "active": false + }, + { + "id": "build-command-build-structure", + "sourceId": "build-command", + "targetId": "build-structure", + "path": "M 1903.2969156901038 1256.671905517578 C 1903.2969156901038 1315.35161336263 1875.187581380208 1315.35161336263 1875.187581380208 1374.0313212076821", + "active": false + }, + { + "id": "repair-command-repair-structure", + "sourceId": "repair-command", + "targetId": "repair-structure", + "path": "M 2137.093811035156 1256.671905517578 C 2137.093811035156 1315.35161336263 2109.000040690104 1315.35161336263 2109.000040690104 1374.0313212076821", + "active": false + }, + { + "id": "idle-sequence-idle-selector", + "sourceId": "idle-sequence", + "targetId": "idle-selector", + "path": "M 2569.0001424153643 474.000015258789 C 2569.0001424153643 524.000015258789 2569.0001424153643 524.000015258789 2569.0001424153643 574.000015258789", + "active": false + }, + { + "id": "idle-selector-auto-gather", + "sourceId": "idle-selector", + "targetId": "auto-gather", + "path": "M 2569.0001424153643 669.9999999999999 C 2569.0001424153643 719.9999999999999 2339.000040690104 719.9999999999999 2339.000040690104 769.9999999999999", + "active": false + }, + { + "id": "idle-selector-patrol-area", + "sourceId": "idle-selector", + "targetId": "patrol-area", + "path": "M 2569.0001424153643 669.9999999999999 C 2569.0001424153643 719.9999999999999 2569.0001424153643 719.9999999999999 2569.0001424153643 769.9999999999999", + "active": false + }, + { + "id": "idle-selector-wait-action", + "sourceId": "idle-selector", + "targetId": "wait-action", + "path": "M 2569.0001424153643 669.9999999999999 C 2569.0001424153643 719.9999999999999 2799.0001424153643 719.9999999999999 2799.0001424153643 769.9999999999999", + "active": false + }, + { + "id": "auto-gather-has-nearby-resource", + "sourceId": "auto-gather", + "targetId": "has-nearby-resource", + "path": "M 2339.000040690104 866.0000101725259 C 2339.000040690104 916.0000101725259 2369.000040690104 916.0000101725259 2369.000040690104 966.0000101725259", + "active": false + }, + { + "id": "has-nearby-resource-auto-gather-action", + "sourceId": "has-nearby-resource", + "targetId": "auto-gather-action", + "path": "M 2369.000040690104 1149.781290690104 C 2369.000040690104 1197.6406606038408 2339.000040690104 1197.6406606038408 2339.000040690104 1245.500030517578", + "active": false + } + ], + "metadata": { + "name": "assets/resources/worker-ai.btree", + "created": "2025-06-24T09:41:27.279Z", + "version": "1.0" + }, + "blackboard": [ + { + "name": "unitType", + "type": "string", + "value": "worker", + "description": "单位类型" + }, + { + "name": "currentHealth", + "type": "number", + "value": 100, + "description": "当前生命值" + }, + { + "name": "maxHealth", + "type": "number", + "value": 100, + "description": "最大生命值" + }, + { + "name": "isLowHealth", + "type": "boolean", + "value": false, + "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": "hasNearbyResource", + "type": "boolean", + "value": false, + "description": "附近是否有资源" + }, + { + "name": "carryingResource", + "type": "boolean", + "value": false, + "description": "是否携带资源" + }, + { + "name": "resourceAmount", + "type": "number", + "value": 0, + "description": "携带的资源数量" + }, + { + "name": "moveSpeed", + "type": "number", + "value": 3, + "description": "移动速度" + }, + { + "name": "workEfficiency", + "type": "number", + "value": 1, + "description": "工作效率" + } + ] +} diff --git a/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree.meta b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree.meta new file mode 100644 index 00000000..4cb14a51 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/resources/worker-ai.btree.meta @@ -0,0 +1,12 @@ +{ + "ver": "1.0.0", + "importer": "*", + "imported": true, + "uuid": "f7fcacf2-eab6-4bef-b7b4-55d13707c90c", + "files": [ + ".btree", + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scenes/scene.scene b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene index 9e744008..51798289 100644 --- a/extensions/cocos/cocos-ecs/assets/scenes/scene.scene +++ b/extensions/cocos/cocos-ecs/assets/scenes/scene.scene @@ -238,7 +238,7 @@ "_shutter": 7, "_iso": 0, "_screenScale": 1, - "_visibility": 1116733440, + "_visibility": 1822425087, "_targetTexture": null, "_postProcess": null, "_usePostProcess": false, diff --git a/extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts b/extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts new file mode 100644 index 00000000..f26c1d30 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts @@ -0,0 +1,236 @@ +import { _decorator, Component, Node, Vec3, instantiate, Prefab, Camera } from 'cc'; +import { UnitController } from './components/UnitController'; +import { RTSCameraController } from './controllers/RTSCameraController'; +import { UIController } from './controllers/UIController'; + +const { ccclass, property } = _decorator; + +/** + * RTS演示项目主控制器 + * 展示行为树在3D RTS游戏中的应用 + */ +@ccclass('RTSDemo') +export class RTSDemo extends Component { + + @property(Prefab) + unitPrefab: Prefab = null!; + + @property(Prefab) + buildingPrefab: Prefab = null!; + + @property(Prefab) + resourcePrefab: Prefab = null!; + + @property(Node) + gameWorld: Node = null!; + + @property(Camera) + mainCamera: Camera = null!; + + @property(Node) + 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() { + // 相机控制器 + this.cameraController = this.mainCamera.getComponent(RTSCameraController) || + this.mainCamera.addComponent(RTSCameraController); + + // 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() { + this.createUnits(); + this.createBuildings(); + this.createResources(); + + // 设置初始相机位置 + this.mainCamera.node.setPosition(0, 20, 15); + this.mainCamera.node.lookAt(Vec3.ZERO); + + console.log('场景设置完成'); + } + + /** + * 创建单位 + */ + private createUnits() { + const unitTypes = [ + { 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 < 3; i++) { + const unit = instantiate(this.unitPrefab); + unit.name = `${type.name}_${i + 1}`; + + // 设置位置 + const angle = (i / 3) * Math.PI * 2; + const radius = 3 + typeIndex * 2; + const x = Math.cos(angle) * radius; + const z = Math.sin(angle) * radius; + unit.setPosition(x, 0, z); + + // 添加到场景 + this.gameWorld.addChild(unit); + 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() { + const buildingPositions = [ + { 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) => { + const buildingNode = instantiate(this.buildingPrefab); + buildingNode.name = building.name; + buildingNode.setPosition(building.pos); + + this.gameWorld.addChild(buildingNode); + this.buildings.push(buildingNode); + + console.log(`创建建筑: ${building.name} at ${building.pos}`); + }); + } + + /** + * 创建资源 + */ + private createResources() { + const resourcePositions = [ + new Vec3(5, 0, -5), + new Vec3(-5, 0, 5), + new Vec3(8, 0, -8), + new Vec3(-8, 0, -5), + new Vec3(6, 0, 6) + ]; + + resourcePositions.forEach((pos, index) => { + const resource = instantiate(this.resourcePrefab); + resource.name = `Resource_${index + 1}`; + resource.setPosition(pos); + + this.gameWorld.addChild(resource); + this.resources.push(resource); + + console.log(`创建资源: ${resource.name} at ${pos}`); + }); + } + + /** + * 单位选择回调 + */ + private onUnitSelected(units: Node[]) { + // 取消之前的选择 + 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); + } + + /** + * 命令发布回调 + */ + private onCommandIssued(command: string, target?: Vec3 | Node) { + if (this.selectedUnits.length === 0) { + 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[] { + return [...this.units]; + } + + /** + * 获取所有建筑 + */ + getAllBuildings(): Node[] { + return [...this.buildings]; + } + + /** + * 获取所有资源 + */ + getAllResources(): Node[] { + return [...this.resources]; + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts.meta rename to extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts.meta index b651f070..5738781d 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/RTSDemo.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "0f20d48a-7b30-4081-a9de-709432b6737b", + "uuid": "c3386f4a-9bef-416f-b770-fcec91cedbc4", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components.meta b/extensions/cocos/cocos-ecs/assets/scripts/components.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs/components.meta rename to extensions/cocos/cocos-ecs/assets/scripts/components.meta index 12edcff9..a089ae9a 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/components.meta @@ -2,7 +2,7 @@ "ver": "1.2.0", "importer": "directory", "imported": true, - "uuid": "3d8cbc91-5bc5-4d17-b53a-01fda26e4660", + "uuid": "d946c8cb-cba5-46eb-8949-5a327bdd4367", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts new file mode 100644 index 00000000..9218b72f --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts @@ -0,0 +1,159 @@ +import { Node, resources, JsonAsset } from 'cc'; +import { BehaviorTree, BehaviorTreeBuilder, Blackboard, TaskStatus, BehaviorTreeJSONConfig } from '@esengine/ai'; +import { ECSComponent } from './UnitComponent'; + +/** + * 行为树组件 - ECS组件,管理单个实体的行为树 + */ +export class BehaviorTreeComponent extends ECSComponent { + public behaviorTreeFile: string = ''; + public cocosNode: Node | null = null; + + private behaviorTree: BehaviorTree | null = null; + private blackboard: Blackboard | null = null; + private context: any = null; + private isLoaded: boolean = false; + private isRunning: boolean = false; + private lastTickTime: number = 0; + private tickInterval: number = 0.1; // 行为树更新间隔(秒) + + /** + * 初始化行为树 + */ + async initialize() { + if (!this.behaviorTreeFile) { + console.error('行为树文件路径未设置'); + return; + } + + try { + await this.loadBehaviorTree(); + this.setupBlackboard(); + this.isLoaded = true; + this.isRunning = true; + console.log(`行为树组件初始化成功: ${this.behaviorTreeFile}`); + } catch (error) { + console.error(`行为树组件初始化失败: ${this.behaviorTreeFile}`, error); + } + } + + /** + * 加载行为树文件 + */ + private async loadBehaviorTree(): Promise { + return new Promise((resolve, reject) => { + // 移除.btree扩展名,使用.bt.json + const jsonPath = this.behaviorTreeFile.replace('.btree', '.bt.json'); + + resources.load(jsonPath, JsonAsset, (err, asset) => { + if (err) { + console.error(`加载行为树文件失败: ${jsonPath}`, err); + reject(err); + return; + } + + try { + const treeData = asset.json as BehaviorTreeJSONConfig; + this.buildBehaviorTree(treeData); + resolve(); + } catch (buildError) { + console.error(`构建行为树失败: ${jsonPath}`, buildError); + reject(buildError); + } + }); + }); + } + + /** + * 构建行为树 + */ + private buildBehaviorTree(treeData: BehaviorTreeJSONConfig) { + // 创建基础执行上下文 + const baseContext = { + cocosNode: this.cocosNode, + unitComponent: this + }; + + // 使用@esengine/ai的BehaviorTreeBuilder构建行为树 + // 这会自动创建黑板并设置所有配置 + const result = BehaviorTreeBuilder.fromBehaviorTreeConfig(treeData, baseContext); + this.behaviorTree = result.tree; + this.blackboard = result.blackboard; + this.context = result.context; + } + + /** + * 设置黑板 + */ + private setupBlackboard() { + if (!this.blackboard || !this.cocosNode) return; + + // 设置基础信息 + 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); + } + + /** + * 更新行为树 + */ + update(deltaTime: number) { + if (!this.isLoaded || !this.isRunning || !this.behaviorTree || !this.context) return; + + // 控制更新频率 + this.lastTickTime += deltaTime; + if (this.lastTickTime < this.tickInterval) return; + + this.lastTickTime = 0; + + // 更新黑板中的时间信息 + if (this.blackboard) { + this.blackboard.setValue('deltaTime', deltaTime); + this.blackboard.setValue('currentTime', Date.now() / 1000); + if (this.cocosNode) { + this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition); + } + } + + // 执行行为树 + try { + this.behaviorTree.tick(); + } catch (error) { + console.error(`行为树执行错误:`, error); + } + } + + /** + * 获取黑板 + */ + getBlackboard(): Blackboard | null { + return this.blackboard; + } + + /** + * 暂停行为树 + */ + pause() { + this.isRunning = false; + } + + /** + * 恢复行为树 + */ + resume() { + if (this.isLoaded) { + this.isRunning = true; + } + } + + /** + * 停止行为树 + */ + stop() { + this.isRunning = false; + if (this.behaviorTree) { + this.behaviorTree.reset(); + } + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts.meta rename to extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts.meta index 5bb5a1a1..61ff4919 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeComponent.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "0c14be41-df1d-4bdc-88fd-b2e504ecdee6", + "uuid": "8efd182b-9891-4903-bef2-eb07b5184263", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts new file mode 100644 index 00000000..755c788b --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts @@ -0,0 +1,258 @@ +import { _decorator, Component, resources, JsonAsset } from 'cc'; +import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig } from '@esengine/ai'; +import { UnitController } from './UnitController'; + +const { ccclass, property } = _decorator; + +/** + * 执行上下文接口 + */ +interface GameExecutionContext { + blackboard?: Blackboard; + unitController: UnitController; + gameObject: any; + [key: string]: any; +} + +/** + * 行为树管理器 - 使用@esengine/ai包管理行为树 + */ +@ccclass('BehaviorTreeManager') +export class BehaviorTreeManager extends Component { + + @property + debugMode: boolean = true; + + @property + tickInterval: number = 0.1; // 行为树更新间隔(秒) + + private behaviorTree: BehaviorTree | null = null; + private blackboard: Blackboard | null = null; + private context: GameExecutionContext | null = null; + private isLoaded: boolean = false; + private isRunning: boolean = false; + private lastTickTime: number = 0; + private unitController: UnitController | null = null; + private currentBehaviorTreeName: string = ''; + + /** + * 初始化行为树 + */ + async initializeBehaviorTree(behaviorTreeName: string, unitController: UnitController) { + this.currentBehaviorTreeName = behaviorTreeName; + this.unitController = unitController; + + try { + await this.loadBehaviorTree(behaviorTreeName); + this.setupBlackboard(); + this.isLoaded = true; + this.isRunning = true; + console.log(`行为树初始化成功: ${behaviorTreeName}`); + } catch (error) { + console.error(`行为树初始化失败: ${behaviorTreeName}`, error); + } + } + + /** + * 加载行为树文件 + */ + private async loadBehaviorTree(behaviorTreeName: string): Promise { + return new Promise((resolve, reject) => { + const jsonPath = `${behaviorTreeName}.bt`; + + resources.load(jsonPath, JsonAsset, (err, asset) => { + if (err) { + console.error(`加载行为树文件失败: ${jsonPath}`, err); + reject(err); + return; + } + + try { + const behaviorTreeData = asset.json as BehaviorTreeJSONConfig; + + // 创建执行上下文 + this.blackboard = new Blackboard(); + this.context = { + blackboard: this.blackboard, + unitController: this.unitController!, + gameObject: this.node + }; + + // 从JSON数据创建行为树 + const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig(behaviorTreeData, this.context); + this.behaviorTree = buildResult.tree as BehaviorTree; + this.blackboard = buildResult.blackboard; + + resolve(); + } catch (parseError) { + console.error(`创建行为树失败: ${jsonPath}`, parseError); + reject(parseError); + } + }); + }); + } + + /** + * 设置黑板基础信息 + */ + private setupBlackboard() { + if (!this.unitController || !this.blackboard) return; + + // 设置单位基础信息 + this.blackboard.setValue('entityName', this.node.name); + this.blackboard.setValue('unitType', this.unitController.unitType); + this.blackboard.setValue('maxHealth', this.unitController.maxHealth); + this.blackboard.setValue('currentHealth', this.unitController.currentHealth); + this.blackboard.setValue('moveSpeed', this.unitController.moveSpeed); + this.blackboard.setValue('attackRange', this.unitController.attackRange); + this.blackboard.setValue('attackDamage', this.unitController.attackDamage); + this.blackboard.setValue('attackCooldown', this.unitController.attackCooldown); + + // 设置时间信息 + this.blackboard.setValue('currentTime', Date.now() / 1000); + this.blackboard.setValue('deltaTime', 0.016); + this.blackboard.setValue('worldPosition', this.node.worldPosition); + + // 设置初始状态 + this.blackboard.setValue('currentCommand', 'idle'); + this.blackboard.setValue('hasTarget', false); + this.blackboard.setValue('isSelected', false); + + // 设置单位控制器引用,供行为树节点使用 + this.blackboard.setValue('unitController', this.unitController); + this.blackboard.setValue('gameObject', this.node); + } + + /** + * 更新黑板值 + */ + updateBlackboardValue(key: string, value: any) { + if (this.blackboard) { + this.blackboard.setValue(key, value); + } + } + + /** + * 获取黑板值 + */ + getBlackboardValue(key: string): any { + return this.blackboard?.getValue(key); + } + + /** + * 获取黑板 + */ + getBlackboard(): Blackboard | null { + return this.blackboard; + } + + /** + * 获取行为树 + */ + getBehaviorTree(): BehaviorTree | null { + return this.behaviorTree; + } + + /** + * 更新行为树 + */ + update(deltaTime: number) { + if (!this.isLoaded || !this.isRunning || !this.behaviorTree || !this.blackboard) return; + + // 控制更新频率 + this.lastTickTime += deltaTime; + if (this.lastTickTime < this.tickInterval) return; + + this.lastTickTime = 0; + + // 更新黑板中的时间信息 + this.blackboard.setValue('deltaTime', deltaTime); + this.blackboard.setValue('currentTime', Date.now() / 1000); + this.blackboard.setValue('worldPosition', this.node.worldPosition); + + // 更新单位状态信息 + if (this.unitController) { + this.blackboard.setValue('currentHealth', this.unitController.currentHealth); + this.blackboard.setValue('healthPercentage', this.unitController.currentHealth / this.unitController.maxHealth); + this.blackboard.setValue('isLowHealth', this.unitController.currentHealth < this.unitController.maxHealth * 0.3); + this.blackboard.setValue('currentCommand', this.unitController.currentCommand); + this.blackboard.setValue('isSelected', this.unitController.isSelected); + this.blackboard.setValue('targetPosition', this.unitController.targetPosition); + this.blackboard.setValue('targetNode', this.unitController.targetNode); + + // 更新距离信息 + if (this.unitController.targetPosition) { + const distance = this.node.worldPosition.subtract(this.unitController.targetPosition).length(); + this.blackboard.setValue('distanceToTarget', distance); + this.blackboard.setValue('isInAttackRange', distance <= this.unitController.attackRange); + this.blackboard.setValue('isCloseToTarget', distance <= 1.0); + } + + // 更新状态标志 + this.blackboard.setValue('isIdle', this.unitController.currentCommand === 'idle'); + this.blackboard.setValue('isMoving', this.unitController.currentCommand === 'move'); + this.blackboard.setValue('isAttacking', this.unitController.currentCommand === 'attack'); + this.blackboard.setValue('isGathering', this.unitController.currentCommand === 'gather'); + this.blackboard.setValue('isPatrolling', this.unitController.currentCommand === 'patrol'); + } + + // 执行行为树 + try { + this.behaviorTree.tick(deltaTime); + if (this.debugMode && Math.random() < 0.01) { // 1%的概率打印调试信息 + console.log(`行为树执行完成, 单位: ${this.node.name}`); + } + } catch (error) { + console.error(`行为树执行错误:`, error); + } + } + + /** + * 暂停行为树 + */ + pause() { + this.isRunning = false; + } + + /** + * 恢复行为树 + */ + resume() { + if (this.isLoaded) { + this.isRunning = true; + } + } + + /** + * 停止行为树 + */ + stop() { + this.isRunning = false; + } + + /** + * 重新加载行为树 + */ + async reloadBehaviorTree() { + if (this.currentBehaviorTreeName && this.unitController) { + this.stop(); + await this.initializeBehaviorTree(this.currentBehaviorTreeName, this.unitController); + } + } + + /** + * 重置行为树 + */ + reset() { + if (this.behaviorTree) { + this.behaviorTree.reset(); + } + } + + onDestroy() { + this.stop(); + this.behaviorTree = null; + this.blackboard = null; + this.context = null; + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts.meta rename to extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts.meta index cc0bb610..7242fdfc 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/BehaviorTreeManager.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "3c3bf485-e1ab-44a4-8758-6594edc4c575", + "uuid": "891c88fc-282d-4791-a961-8d85244bfee7", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts new file mode 100644 index 00000000..74006e36 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts @@ -0,0 +1,345 @@ +import { _decorator, Component, Node, Vec3, Material, MeshRenderer, Color, tween } from 'cc'; +import { BehaviorTreeComponent } from './BehaviorTreeComponent'; + +// 简化的ECS组件基类 +export class ECSComponent { + public entity: any = null; +} + +// 简化的Entity类 +export class Entity { + public name: string = ''; + private components: Map = new Map(); + + constructor(name: string) { + this.name = name; + } + + addComponent(component: any) { + this.components.set(component.constructor, component); + component.entity = this; + } + + getComponent(componentClass: any): T | null { + return this.components.get(componentClass) || null; + } + + hasComponent(componentClass: any): boolean { + return this.components.has(componentClass); + } +} + +// 简化的Core类 +export class Core { + static entityManager = { + entities: [] as Entity[], + createEntity: (name: string) => { + const entity = new Entity(name); + Core.entityManager.entities.push(entity); + return entity; + }, + destroyEntity: (entity: Entity) => { + const index = Core.entityManager.entities.indexOf(entity); + if (index !== -1) { + Core.entityManager.entities.splice(index, 1); + } + } + }; + + static create(config?: any) { + console.log('ECS Core initialized with config:', config); + } + + static update(deltaTime: number) { + // 简化的更新逻辑 + } +} + +const { ccclass, property } = _decorator; + +/** + * 单位配置接口 + */ +export interface UnitConfig { + unitType: string; + behaviorTreeFile: string; + maxHealth: number; + moveSpeed: number; + attackRange: number; + attackDamage: number; + color: string; +} + +/** + * 单位状态组件 + */ +export class UnitStateComponent extends ECSComponent { + public unitType: string = ''; + public maxHealth: number = 100; + public currentHealth: number = 100; + public moveSpeed: number = 3; + public attackRange: number = 2; + public attackDamage: number = 25; + public isSelected: boolean = false; + public currentCommand: string = 'idle'; + public targetPosition: Vec3 = Vec3.ZERO.clone(); + public targetNode: Node | null = null; + public lastAttackTime: number = 0; + public attackCooldown: number = 1.5; + public color: string = 'white'; +} + +/** + * 单位组件 - Cocos Creator组件,管理单位的可视化和ECS实体 + */ +@ccclass('UnitComponent') +export class UnitComponent extends Component { + + @property + showDebugInfo: boolean = true; + + private entity: Entity | null = null; + private unitState: UnitStateComponent | null = null; + private behaviorTreeComponent: BehaviorTreeComponent | null = null; + private meshRenderer: MeshRenderer | null = null; + private originalMaterial: Material | null = null; + private selectionMaterial: Material | null = null; + + onLoad() { + this.meshRenderer = this.getComponent(MeshRenderer); + if (this.meshRenderer && this.meshRenderer.material) { + this.originalMaterial = this.meshRenderer.material; + } + } + + /** + * 设置单位配置 + */ + setup(config: UnitConfig) { + // 创建ECS实体 + this.entity = Core.entityManager.createEntity(`Unit_${this.node.name}`); + + // 添加单位状态组件 + this.unitState = new UnitStateComponent(); + this.unitState.unitType = config.unitType; + this.unitState.maxHealth = config.maxHealth; + this.unitState.currentHealth = config.maxHealth; + this.unitState.moveSpeed = config.moveSpeed; + this.unitState.attackRange = config.attackRange; + this.unitState.attackDamage = config.attackDamage; + this.unitState.color = config.color; + this.entity.addComponent(this.unitState); + + // 添加行为树组件 + this.behaviorTreeComponent = new BehaviorTreeComponent(); + this.behaviorTreeComponent.behaviorTreeFile = config.behaviorTreeFile; + this.behaviorTreeComponent.cocosNode = this.node; + this.entity.addComponent(this.behaviorTreeComponent); + + // 设置材质颜色 + this.setUnitColor(config.color); + + console.log(`单位 ${this.node.name} 设置完成 - 类型: ${config.unitType}, 行为树: ${config.behaviorTreeFile}`); + } + + /** + * 设置单位颜色 + */ + private setUnitColor(colorName: string) { + if (!this.meshRenderer || !this.meshRenderer.material) return; + + const colorMap: { [key: string]: Color } = { + 'red': Color.RED, + 'green': Color.GREEN, + 'blue': Color.BLUE, + 'yellow': Color.YELLOW, + 'white': Color.WHITE, + 'cyan': Color.CYAN, + 'magenta': Color.MAGENTA + }; + + const color = colorMap[colorName] || Color.WHITE; + this.meshRenderer.material.setProperty('mainColor', color); + } + + /** + * 设置选择状态 + */ + setSelected(selected: boolean) { + if (!this.unitState) return; + + this.unitState.isSelected = selected; + + // 视觉效果 + if (selected) { + this.showSelectionEffect(); + } else { + this.hideSelectionEffect(); + } + } + + /** + * 显示选择效果 + */ + private showSelectionEffect() { + // 添加选择圈效果 + tween(this.node) + .to(0.3, { scale: new Vec3(1.1, 1.1, 1.1) }) + .to(0.3, { scale: Vec3.ONE }) + .union() + .repeatForever() + .start(); + } + + /** + * 隐藏选择效果 + */ + private hideSelectionEffect() { + // 停止所有缩放动画 + tween(this.node).stop(); + this.node.setScale(Vec3.ONE); + } + + /** + * 发布命令 + */ + issueCommand(command: string, target?: Vec3 | Node) { + if (!this.unitState || !this.behaviorTreeComponent) return; + + this.unitState.currentCommand = command; + + // 设置目标 + if (target instanceof Vec3) { + this.unitState.targetPosition = target.clone(); + this.unitState.targetNode = null; + } else if (target instanceof Node) { + this.unitState.targetPosition = target.worldPosition.clone(); + this.unitState.targetNode = target; + } + + // 通过黑板更新行为树状态 + const blackboard = this.behaviorTreeComponent.getBlackboard(); + if (blackboard) { + blackboard.setValue('currentCommand', command); + blackboard.setValue('hasTarget', target !== undefined); + blackboard.setValue('targetPosition', this.unitState.targetPosition); + + if (target instanceof Node) { + blackboard.setValue('targetType', target.name.includes('Resource') ? 'resource' : + target.name.includes('Building') ? 'building' : 'unit'); + } + } + + console.log(`单位 ${this.node.name} 接收命令: ${command}`, target); + } + + /** + * 获取单位状态 + */ + getUnitState(): UnitStateComponent | null { + return this.unitState; + } + + /** + * 获取行为树组件 + */ + getBehaviorTreeComponent(): BehaviorTreeComponent | null { + return this.behaviorTreeComponent; + } + + /** + * 受到伤害 + */ + takeDamage(damage: number) { + if (!this.unitState) return; + + this.unitState.currentHealth = Math.max(0, this.unitState.currentHealth - damage); + + // 更新黑板 + const blackboard = this.behaviorTreeComponent?.getBlackboard(); + if (blackboard) { + blackboard.setValue('currentHealth', this.unitState.currentHealth); + blackboard.setValue('healthPercentage', this.unitState.currentHealth / this.unitState.maxHealth); + blackboard.setValue('isLowHealth', this.unitState.currentHealth < this.unitState.maxHealth * 0.3); + } + + // 视觉效果 + this.showDamageEffect(); + + if (this.unitState.currentHealth <= 0) { + this.die(); + } + } + + /** + * 显示受伤效果 + */ + private showDamageEffect() { + if (!this.meshRenderer || !this.meshRenderer.material) return; + + // 闪红效果 + const originalColor = this.meshRenderer.material.getProperty('mainColor') as Color; + this.meshRenderer.material.setProperty('mainColor', Color.RED); + + this.scheduleOnce(() => { + if (this.meshRenderer && this.meshRenderer.material) { + this.meshRenderer.material.setProperty('mainColor', originalColor); + } + }, 0.2); + } + + /** + * 单位死亡 + */ + private die() { + console.log(`单位 ${this.node.name} 死亡`); + + // 从ECS系统中移除实体 + if (this.entity) { + Core.entityManager.destroyEntity(this.entity); + } + + // 播放死亡动画后销毁节点 + tween(this.node) + .to(0.5, { scale: Vec3.ZERO }) + .call(() => { + this.node.destroy(); + }) + .start(); + } + + update(deltaTime: number) { + if (!this.unitState || !this.behaviorTreeComponent) return; + + // 更新黑板中的时间相关变量 + const blackboard = this.behaviorTreeComponent.getBlackboard(); + if (blackboard) { + blackboard.setValue('deltaTime', deltaTime); + blackboard.setValue('currentTime', Date.now() / 1000); + blackboard.setValue('worldPosition', this.node.worldPosition); + } + + // 调试信息显示 + if (this.showDebugInfo) { + this.updateDebugInfo(); + } + } + + /** + * 更新调试信息 + */ + private updateDebugInfo() { + // 可以在这里添加调试信息的显示逻辑 + // 比如在单位上方显示状态文本等 + } + + onDestroy() { + // 清理ECS实体 + if (this.entity) { + Core.entityManager.destroyEntity(this.entity); + } + + // 停止所有动画 + tween(this.node).stop(); + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts.meta rename to extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts.meta index 05a99d4e..7fd57854 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitComponent.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "c82e7909-01e6-49ca-b68d-9ee98837e238", + "uuid": "61885e67-b7a2-4e51-857e-ccbea4fdea03", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts new file mode 100644 index 00000000..7da7ea57 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts @@ -0,0 +1,306 @@ +import { _decorator, Component, Node, Vec3, Material, MeshRenderer, Color, tween } from 'cc'; +import { BehaviorTreeManager } from './BehaviorTreeManager'; + +const { ccclass, property } = _decorator; + +/** + * 单位配置接口 + */ +export interface UnitConfig { + unitType: string; + behaviorTreeName: string; + maxHealth: number; + moveSpeed: number; + attackRange: number; + attackDamage: number; + color: string; +} + +/** + * 单位控制器 - 纯Cocos Creator组件,管理单位的行为和状态 + */ +@ccclass('UnitController') +export class UnitController extends Component { + + @property + showDebugInfo: boolean = true; + + // 单位属性 + public unitType: string = ''; + public maxHealth: number = 100; + public currentHealth: number = 100; + public moveSpeed: number = 3; + public attackRange: number = 2; + public attackDamage: number = 25; + public isSelected: boolean = false; + public currentCommand: string = 'idle'; + public targetPosition: Vec3 = Vec3.ZERO.clone(); + public targetNode: Node | null = null; + public lastAttackTime: number = 0; + public attackCooldown: number = 1.5; + public color: string = 'white'; + + private behaviorTreeManager: BehaviorTreeManager | null = null; + private meshRenderer: MeshRenderer | null = null; + + onLoad() { + this.meshRenderer = this.getComponent(MeshRenderer); + + // 创建行为树管理器 + this.behaviorTreeManager = this.addComponent(BehaviorTreeManager); + } + + /** + * 设置单位配置 + */ + setup(config: UnitConfig) { + this.unitType = config.unitType; + this.maxHealth = config.maxHealth; + this.currentHealth = config.maxHealth; + this.moveSpeed = config.moveSpeed; + this.attackRange = config.attackRange; + this.attackDamage = config.attackDamage; + this.color = config.color; + + // 设置材质颜色 + this.setUnitColor(config.color); + + // 初始化行为树 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.initializeBehaviorTree(config.behaviorTreeName, this); + } + + console.log(`单位 ${this.node.name} 设置完成 - 类型: ${config.unitType}, 行为树: ${config.behaviorTreeName}`); + } + + /** + * 设置单位颜色 + */ + private setUnitColor(colorName: string) { + if (!this.meshRenderer || !this.meshRenderer.material) return; + + const colorMap: { [key: string]: Color } = { + 'red': Color.RED, + 'green': Color.GREEN, + 'blue': Color.BLUE, + 'yellow': Color.YELLOW, + 'white': Color.WHITE, + 'cyan': Color.CYAN, + 'magenta': Color.MAGENTA + }; + + const color = colorMap[colorName] || Color.WHITE; + this.meshRenderer.material.setProperty('mainColor', color); + } + + /** + * 设置选择状态 + */ + setSelected(selected: boolean) { + this.isSelected = selected; + + // 视觉效果 + if (selected) { + this.showSelectionEffect(); + } else { + this.hideSelectionEffect(); + } + + // 更新行为树黑板 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.updateBlackboardValue('isSelected', selected); + } + } + + /** + * 显示选择效果 + */ + private showSelectionEffect() { + // 添加选择圈效果 + tween(this.node) + .to(0.3, { scale: new Vec3(1.1, 1.1, 1.1) }) + .to(0.3, { scale: Vec3.ONE }) + .union() + .repeatForever() + .start(); + } + + /** + * 隐藏选择效果 + */ + private hideSelectionEffect() { + // 停止所有缩放动画 + tween(this.node).stop(); + this.node.setScale(Vec3.ONE); + } + + /** + * 发布命令 + */ + issueCommand(command: string, target?: Vec3 | Node) { + this.currentCommand = command; + + // 设置目标 + if (target instanceof Vec3) { + this.targetPosition = target.clone(); + this.targetNode = null; + } else if (target instanceof Node) { + this.targetPosition = target.worldPosition.clone(); + this.targetNode = target; + } + + // 更新行为树黑板 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.updateBlackboardValue('currentCommand', command); + this.behaviorTreeManager.updateBlackboardValue('hasTarget', target !== undefined); + this.behaviorTreeManager.updateBlackboardValue('targetPosition', this.targetPosition); + + if (target instanceof Node) { + this.behaviorTreeManager.updateBlackboardValue('targetType', + target.name.includes('Resource') ? 'resource' : + target.name.includes('Building') ? 'building' : 'unit'); + } + } + + console.log(`单位 ${this.node.name} 接收命令: ${command}`, target); + } + + /** + * 受到伤害 + */ + takeDamage(damage: number) { + this.currentHealth = Math.max(0, this.currentHealth - damage); + + // 更新行为树黑板 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.updateBlackboardValue('currentHealth', this.currentHealth); + this.behaviorTreeManager.updateBlackboardValue('healthPercentage', this.currentHealth / this.maxHealth); + this.behaviorTreeManager.updateBlackboardValue('isLowHealth', this.currentHealth < this.maxHealth * 0.3); + } + + // 视觉效果 + this.showDamageEffect(); + + if (this.currentHealth <= 0) { + this.die(); + } + } + + /** + * 显示受伤效果 + */ + private showDamageEffect() { + if (!this.meshRenderer || !this.meshRenderer.material) return; + + // 闪红效果 + const originalColor = this.meshRenderer.material.getProperty('mainColor') as Color; + this.meshRenderer.material.setProperty('mainColor', Color.RED); + + this.scheduleOnce(() => { + if (this.meshRenderer && this.meshRenderer.material) { + this.meshRenderer.material.setProperty('mainColor', originalColor); + } + }, 0.2); + } + + /** + * 单位死亡 + */ + private die() { + console.log(`单位 ${this.node.name} 死亡`); + + // 播放死亡动画后销毁节点 + tween(this.node) + .to(0.5, { scale: Vec3.ZERO }) + .call(() => { + this.node.destroy(); + }) + .start(); + } + + /** + * 移动到目标位置 + */ + moveToTarget(targetPos: Vec3, speed?: number): boolean { + const currentPos = this.node.worldPosition; + const distance = currentPos.subtract(targetPos).length(); + + if (distance < 0.5) { + return true; // 已到达目标 + } + + // 简单的移动逻辑 + const direction = targetPos.subtract(currentPos).normalize(); + const moveSpeed = speed || this.moveSpeed; + const deltaTime = 1/60; // 假设60fps + + const newPosition = currentPos.add(direction.multiplyScalar(moveSpeed * deltaTime)); + this.node.setWorldPosition(newPosition); + + return false; // 还在移动中 + } + + /** + * 攻击目标 + */ + attackTarget(): boolean { + const currentTime = Date.now() / 1000; + + if (currentTime - this.lastAttackTime < this.attackCooldown) { + return false; // 冷却中 + } + + // 执行攻击 + console.log(`${this.node.name} 执行攻击`); + this.lastAttackTime = currentTime; + + // 更新行为树黑板 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.updateBlackboardValue('lastAttackTime', currentTime); + } + + return true; // 攻击成功 + } + + update(deltaTime: number) { + // 更新行为树黑板中的时间相关变量 + if (this.behaviorTreeManager) { + this.behaviorTreeManager.updateBlackboardValue('deltaTime', deltaTime); + this.behaviorTreeManager.updateBlackboardValue('currentTime', Date.now() / 1000); + this.behaviorTreeManager.updateBlackboardValue('worldPosition', this.node.worldPosition); + + // 更新距离信息 + if (this.targetPosition) { + const distance = this.node.worldPosition.subtract(this.targetPosition).length(); + this.behaviorTreeManager.updateBlackboardValue('distanceToTarget', distance); + this.behaviorTreeManager.updateBlackboardValue('isInAttackRange', distance <= this.attackRange); + this.behaviorTreeManager.updateBlackboardValue('isCloseToTarget', distance <= 1.0); + } + + // 更新状态标志 + this.behaviorTreeManager.updateBlackboardValue('isIdle', this.currentCommand === 'idle'); + this.behaviorTreeManager.updateBlackboardValue('isMoving', this.currentCommand === 'move'); + this.behaviorTreeManager.updateBlackboardValue('isAttacking', this.currentCommand === 'attack'); + this.behaviorTreeManager.updateBlackboardValue('isGathering', this.currentCommand === 'gather'); + this.behaviorTreeManager.updateBlackboardValue('isPatrolling', this.currentCommand === 'patrol'); + } + + // 调试信息显示 + if (this.showDebugInfo) { + this.updateDebugInfo(); + } + } + + /** + * 更新调试信息 + */ + private updateDebugInfo() { + // 可以在这里添加调试信息的显示逻辑 + // 比如在单位上方显示状态文本等 + } + + onDestroy() { + // 停止所有动画 + tween(this.node).stop(); + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts.meta new file mode 100644 index 00000000..fc3634a4 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "4ac64480-2d09-4de6-a22c-add022790676", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs.meta b/extensions/cocos/cocos-ecs/assets/scripts/controllers.meta similarity index 70% rename from extensions/cocos/cocos-ecs/assets/scripts/ecs.meta rename to extensions/cocos/cocos-ecs/assets/scripts/controllers.meta index 825c6bc0..34700c8d 100644 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs.meta +++ b/extensions/cocos/cocos-ecs/assets/scripts/controllers.meta @@ -2,7 +2,7 @@ "ver": "1.2.0", "importer": "directory", "imported": true, - "uuid": "6f9217a1-dff6-4460-b5da-eb01cf29c03c", + "uuid": "84a4754f-3fad-4031-8aeb-e699584cfb92", "files": [], "subMetas": {}, "userData": {} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts b/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts new file mode 100644 index 00000000..ec647b61 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts @@ -0,0 +1,203 @@ +import { _decorator, Component, Node, Camera, Vec3, input, Input, EventMouse, EventTouch, KeyCode, Quat } from 'cc'; + +const { ccclass, property } = _decorator; + +/** + * RTS相机控制器 + * 提供RTS游戏常用的相机控制功能 + */ +@ccclass('RTSCameraController') +export class RTSCameraController extends Component { + + @property + moveSpeed: number = 10; + + @property + rotateSpeed: number = 60; + + @property + zoomSpeed: number = 5; + + @property + minZoom: number = 5; + + @property + maxZoom: number = 30; + + @property + boundarySize: number = 50; + + private camera: Camera = null!; + private isMouseDown: boolean = false; + private lastMousePosition: Vec3 = Vec3.ZERO.clone(); + private currentZoom: number = 15; + + // 键盘输入状态 + private keyStates: { [key: string]: boolean } = {}; + + onLoad() { + this.camera = this.getComponent(Camera)!; + this.currentZoom = this.node.position.y; + + // 注册输入事件 + input.on(Input.EventType.MOUSE_DOWN, this.onMouseDown, this); + input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this); + input.on(Input.EventType.MOUSE_MOVE, this.onMouseMove, this); + input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this); + input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this); + input.on(Input.EventType.KEY_UP, this.onKeyUp, this); + } + + onDestroy() { + // 取消注册输入事件 + input.off(Input.EventType.MOUSE_DOWN, this.onMouseDown, this); + input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this); + input.off(Input.EventType.MOUSE_MOVE, this.onMouseMove, this); + input.off(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this); + input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this); + input.off(Input.EventType.KEY_UP, this.onKeyUp, this); + } + + /** + * 鼠标按下事件 + */ + private onMouseDown(event: EventMouse) { + if (event.getButton() === EventMouse.BUTTON_MIDDLE) { + this.isMouseDown = true; + this.lastMousePosition.set(event.getLocationX(), event.getLocationY(), 0); + } + } + + /** + * 鼠标抬起事件 + */ + private onMouseUp(event: EventMouse) { + if (event.getButton() === EventMouse.BUTTON_MIDDLE) { + this.isMouseDown = false; + } + } + + /** + * 鼠标移动事件 + */ + private onMouseMove(event: EventMouse) { + if (this.isMouseDown) { + const deltaX = event.getLocationX() - this.lastMousePosition.x; + const deltaY = event.getLocationY() - this.lastMousePosition.y; + + // 相机平移 + const moveVector = new Vec3(-deltaX * 0.01, 0, deltaY * 0.01); + this.node.translate(moveVector); + + this.lastMousePosition.set(event.getLocationX(), event.getLocationY(), 0); + + // 限制相机边界 + this.clampCameraBounds(); + } + } + + /** + * 鼠标滚轮事件 + */ + private onMouseWheel(event: EventMouse) { + const scrollY = event.getScrollY(); + this.currentZoom -= scrollY * this.zoomSpeed * 0.1; + this.currentZoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.currentZoom)); + + const pos = this.node.position; + this.node.setPosition(pos.x, this.currentZoom, pos.z); + } + + /** + * 键盘按下事件 + */ + private onKeyDown(event: any) { + this.keyStates[event.keyCode] = true; + } + + /** + * 键盘抬起事件 + */ + private onKeyUp(event: any) { + this.keyStates[event.keyCode] = false; + } + + /** + * 更新相机移动 + */ + update(deltaTime: number) { + this.handleKeyboardMovement(deltaTime); + } + + /** + * 处理键盘移动 + */ + private handleKeyboardMovement(deltaTime: number) { + const moveDistance = this.moveSpeed * deltaTime; + let moveVector = Vec3.ZERO.clone(); + + // WASD 移动 + if (this.keyStates[KeyCode.KEY_W] || this.keyStates[KeyCode.ARROW_UP]) { + moveVector.z -= moveDistance; + } + if (this.keyStates[KeyCode.KEY_S] || this.keyStates[KeyCode.ARROW_DOWN]) { + moveVector.z += moveDistance; + } + if (this.keyStates[KeyCode.KEY_A] || this.keyStates[KeyCode.ARROW_LEFT]) { + moveVector.x -= moveDistance; + } + if (this.keyStates[KeyCode.KEY_D] || this.keyStates[KeyCode.ARROW_RIGHT]) { + moveVector.x += moveDistance; + } + + // 应用移动 + if (!moveVector.equals(Vec3.ZERO)) { + this.node.translate(moveVector); + this.clampCameraBounds(); + } + + // QE 旋转 + if (this.keyStates[KeyCode.KEY_Q]) { + const rotateAngle = this.rotateSpeed * deltaTime * Math.PI / 180; + const currentRotation = this.node.rotation.clone(); + const yRotation = Quat.fromAxisAngle(new Quat(), Vec3.UP, rotateAngle); + Quat.multiply(currentRotation, currentRotation, yRotation); + this.node.rotation = currentRotation; + } + if (this.keyStates[KeyCode.KEY_E]) { + const rotateAngle = -this.rotateSpeed * deltaTime * Math.PI / 180; + const currentRotation = this.node.rotation.clone(); + const yRotation = Quat.fromAxisAngle(new Quat(), Vec3.UP, rotateAngle); + Quat.multiply(currentRotation, currentRotation, yRotation); + this.node.rotation = currentRotation; + } + } + + /** + * 限制相机边界 + */ + private clampCameraBounds() { + const pos = this.node.position; + const clampedX = Math.max(-this.boundarySize, Math.min(this.boundarySize, pos.x)); + const clampedZ = Math.max(-this.boundarySize, Math.min(this.boundarySize, pos.z)); + + this.node.setPosition(clampedX, pos.y, clampedZ); + } + + /** + * 设置相机位置 + */ + setCameraPosition(position: Vec3) { + this.node.setPosition(position); + this.clampCameraBounds(); + } + + /** + * 聚焦到目标位置 + */ + focusOnTarget(target: Vec3, duration: number = 1.0) { + const targetPos = new Vec3(target.x, this.currentZoom, target.z); + // 这里可以添加缓动动画 + this.setCameraPosition(targetPos); + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts.meta new file mode 100644 index 00000000..38a55d66 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/controllers/RTSCameraController.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "dabc6540-6e9f-450a-9d22-b9af94c20d6d", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts b/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts new file mode 100644 index 00000000..4136aece --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts @@ -0,0 +1,225 @@ +import { _decorator, Component, Node, Vec3, Label, Button, EventHandler } from 'cc'; + +const { ccclass, property } = _decorator; + +/** + * UI控制器 - 管理RTS演示的用户界面 + */ +@ccclass('UIController') +export class UIController extends Component { + + @property(Label) + selectedUnitsLabel: Label = null!; + + @property(Button) + moveButton: Button = null!; + + @property(Button) + attackButton: Button = null!; + + @property(Button) + gatherButton: Button = null!; + + @property(Button) + patrolButton: Button = null!; + + @property(Label) + infoLabel: Label = null!; + + // 回调函数 + public onUnitSelected: ((units: Node[]) => void) | null = null; + public onCommandIssued: ((command: string, target?: Vec3 | Node) => void) | null = null; + + private selectedUnitsCount: number = 0; + + onLoad() { + this.setupUI(); + this.updateSelectedUnitsDisplay(); + this.updateInfoDisplay('RTS 行为树演示 - 点击单位选择,然后发布命令'); + } + + /** + * 设置UI事件 + */ + private setupUI() { + // 移动命令按钮 + if (this.moveButton) { + const moveHandler = new EventHandler(); + moveHandler.target = this.node; + moveHandler.component = 'UIController'; + moveHandler.handler = 'onMoveCommand'; + this.moveButton.clickEvents.push(moveHandler); + } + + // 攻击命令按钮 + if (this.attackButton) { + const attackHandler = new EventHandler(); + attackHandler.target = this.node; + attackHandler.component = 'UIController'; + attackHandler.handler = 'onAttackCommand'; + this.attackButton.clickEvents.push(attackHandler); + } + + // 收集命令按钮 + if (this.gatherButton) { + const gatherHandler = new EventHandler(); + gatherHandler.target = this.node; + gatherHandler.component = 'UIController'; + gatherHandler.handler = 'onGatherCommand'; + this.gatherButton.clickEvents.push(gatherHandler); + } + + // 巡逻命令按钮 + if (this.patrolButton) { + const patrolHandler = new EventHandler(); + patrolHandler.target = this.node; + patrolHandler.component = 'UIController'; + patrolHandler.handler = 'onPatrolCommand'; + this.patrolButton.clickEvents.push(patrolHandler); + } + } + + /** + * 设置选中单位数量 + */ + setSelectedUnitsCount(count: number) { + this.selectedUnitsCount = count; + this.updateSelectedUnitsDisplay(); + this.updateButtonStates(); + } + + /** + * 更新选中单位显示 + */ + private updateSelectedUnitsDisplay() { + if (this.selectedUnitsLabel) { + this.selectedUnitsLabel.string = `选中单位: ${this.selectedUnitsCount}`; + } + } + + /** + * 更新按钮状态 + */ + private updateButtonStates() { + const hasSelection = this.selectedUnitsCount > 0; + + if (this.moveButton) { + this.moveButton.interactable = hasSelection; + } + if (this.attackButton) { + this.attackButton.interactable = hasSelection; + } + if (this.gatherButton) { + this.gatherButton.interactable = hasSelection; + } + if (this.patrolButton) { + this.patrolButton.interactable = hasSelection; + } + } + + /** + * 更新信息显示 + */ + updateInfoDisplay(message: string) { + if (this.infoLabel) { + this.infoLabel.string = message; + } + console.log(`[UI] ${message}`); + } + + /** + * 移动命令 + */ + onMoveCommand() { + if (this.selectedUnitsCount === 0) { + this.updateInfoDisplay('请先选择单位'); + return; + } + + // 生成随机目标位置 + const targetPos = new Vec3( + (Math.random() - 0.5) * 20, + 0, + (Math.random() - 0.5) * 20 + ); + + this.onCommandIssued?.('move', targetPos); + this.updateInfoDisplay(`发布移动命令到位置 (${targetPos.x.toFixed(1)}, ${targetPos.z.toFixed(1)})`); + } + + /** + * 攻击命令 + */ + onAttackCommand() { + if (this.selectedUnitsCount === 0) { + this.updateInfoDisplay('请先选择单位'); + return; + } + + // 生成随机攻击位置 + const targetPos = new Vec3( + (Math.random() - 0.5) * 15, + 0, + (Math.random() - 0.5) * 15 + ); + + this.onCommandIssued?.('attack', targetPos); + this.updateInfoDisplay(`发布攻击命令到位置 (${targetPos.x.toFixed(1)}, ${targetPos.z.toFixed(1)})`); + } + + /** + * 收集命令 + */ + onGatherCommand() { + if (this.selectedUnitsCount === 0) { + this.updateInfoDisplay('请先选择单位'); + return; + } + + this.onCommandIssued?.('gather'); + this.updateInfoDisplay('发布收集资源命令'); + } + + /** + * 巡逻命令 + */ + onPatrolCommand() { + if (this.selectedUnitsCount === 0) { + this.updateInfoDisplay('请先选择单位'); + return; + } + + this.onCommandIssued?.('patrol'); + this.updateInfoDisplay('发布巡逻命令'); + } + + /** + * 显示单位信息 + */ + showUnitInfo(unitName: string, unitType: string, health: number, maxHealth: number) { + const healthPercent = Math.round((health / maxHealth) * 100); + this.updateInfoDisplay(`${unitName} (${unitType}) - 生命值: ${health}/${maxHealth} (${healthPercent}%)`); + } + + /** + * 显示行为树状态 + */ + showBehaviorTreeStatus(unitName: string, currentBehavior: string) { + this.updateInfoDisplay(`${unitName} 当前行为: ${currentBehavior}`); + } + + /** + * 显示错误信息 + */ + showError(message: string) { + this.updateInfoDisplay(`错误: ${message}`); + console.error(`[UI Error] ${message}`); + } + + /** + * 显示成功信息 + */ + showSuccess(message: string) { + this.updateInfoDisplay(`成功: ${message}`); + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts.meta new file mode 100644 index 00000000..5ccc4c29 --- /dev/null +++ b/extensions/cocos/cocos-ecs/assets/scripts/controllers/UIController.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "00e982f3-dcf3-44b0-9b63-5e2877c1971e", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts deleted file mode 100644 index 08c7514d..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeExample.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { _decorator, Component, Node, Label, Button, resources, JsonAsset } from 'cc'; -import { - BehaviorTreeBuilder, - BehaviorTree, - Blackboard -} from '@esengine/ai'; -import type { BehaviorTreeJSONConfig } from '@esengine/ai'; - -const { ccclass, property } = _decorator; - -/** - * 行为树测试示例 - * 使用 @esengine/ai 包的 BehaviorTreeBuilder API 自动加载和初始化行为树 - * - * 特性: - * - 自动从JSON配置文件加载行为树 - * - 自动初始化黑板变量 - * - 支持行为树的启动、停止、暂停、恢复 - * - 实时显示黑板变量状态 - */ -@ccclass('BehaviorTreeExample') -export class BehaviorTreeExample extends Component { - - @property(Label) - statusLabel: Label = null; - - @property(Label) - logLabel: Label = null; - - @property(Button) - startButton: Button = null; - - @property(Button) - stopButton: Button = null; - - @property(Button) - pauseButton: Button = null; - - @property(Button) - resumeButton: Button = null; - - private behaviorTree: BehaviorTree = null; - private blackboard: Blackboard = null; - private isRunning: boolean = false; - private isPaused: boolean = false; - private logs: string[] = []; - private executionContext: any = null; - private updateTimer: number = 0; - - onLoad() { - this.setupUI(); - this.loadBehaviorTree(); - } - - private setupUI() { - if (this.startButton) { - this.startButton.node.on('click', this.startBehaviorTree, this); - } - if (this.stopButton) { - this.stopButton.node.on('click', this.stopBehaviorTree, this); - } - if (this.pauseButton) { - this.pauseButton.node.on('click', this.pauseBehaviorTree, this); - } - if (this.resumeButton) { - this.resumeButton.node.on('click', this.resumeBehaviorTree, this); - } - - this.updateStatus('初始化中...'); - this.updateLog('行为树测试组件已加载'); - } - - private async loadBehaviorTree() { - try { - this.updateStatus('加载行为树配置...'); - - // 从resources目录加载simple-example.bt.json文件 - resources.load('simple-example.bt', JsonAsset, (err, jsonAsset: JsonAsset) => { - if (err) { - console.error('加载行为树配置失败:', err); - this.updateStatus('加载失败: ' + err.message); - this.updateLog('❌ 加载simple-example.bt.json失败: ' + err.message); - return; - } - - try { - const config = jsonAsset.json as BehaviorTreeJSONConfig; - this.setupBehaviorTree(config); - } catch (error) { - console.error('解析行为树配置失败:', error); - this.updateStatus('解析失败: ' + error.message); - this.updateLog('❌ 解析行为树配置失败: ' + error.message); - } - }); - - } catch (error) { - console.error('行为树加载过程出错:', error); - this.updateStatus('加载出错: ' + error.message); - this.updateLog('❌ 行为树加载过程出错: ' + error.message); - } - } - - private setupBehaviorTree(config: BehaviorTreeJSONConfig) { - try { - // 创建执行上下文 - this.executionContext = { - node: this.node, - component: this, - // 添加日志方法供行为树节点使用 - log: (message: string, level: string = 'info') => { - this.updateLog(`🤖 [${level.toUpperCase()}] ${message}`); - } - }; - - // 🎯 使用 @esengine/ai 的 BehaviorTreeBuilder API - 一行代码完成所有初始化! - const result = BehaviorTreeBuilder.fromBehaviorTreeConfig(config, this.executionContext); - - this.behaviorTree = result.tree; - this.blackboard = result.blackboard; - this.executionContext = result.context; - - this.updateStatus('行为树加载完成,准备执行'); - this.updateLog('✅ 行为树创建成功(使用 @esengine/ai 包)'); - this.updateLog(`📊 节点总数: ${config.nodes ? config.nodes.length : 0}`); - this.updateLog(`📋 变量总数: ${config.blackboard ? config.blackboard.length : 0}`); - - // 显示黑板变量初始状态 - this.logBlackboardStatus(); - - // 启用开始按钮 - if (this.startButton) { - this.startButton.interactable = true; - } - - } catch (error) { - console.error('设置行为树失败:', error); - this.updateStatus('设置失败: ' + error.message); - this.updateLog('❌ 行为树设置失败: ' + error.message); - } - } - - private startBehaviorTree() { - if (!this.behaviorTree) { - this.updateLog('❌ 行为树未准备好'); - return; - } - - this.isRunning = true; - this.isPaused = false; - // 重置行为树状态 - this.behaviorTree.reset(); - this.updateStatus('执行中...'); - this.updateLog('🚀 开始执行行为树(自动初始化黑板)'); - - // 更新按钮状态 - if (this.startButton) this.startButton.interactable = false; - if (this.stopButton) this.stopButton.interactable = true; - if (this.pauseButton) this.pauseButton.interactable = true; - if (this.resumeButton) this.resumeButton.interactable = false; - } - - private stopBehaviorTree() { - this.isRunning = false; - this.isPaused = false; - this.updateStatus('已停止'); - this.updateLog('⏹️ 行为树执行已停止'); - - // 重置行为树状态 - if (this.behaviorTree) { - this.behaviorTree.reset(); - } - - // 更新按钮状态 - if (this.startButton) this.startButton.interactable = true; - if (this.stopButton) this.stopButton.interactable = false; - if (this.pauseButton) this.pauseButton.interactable = false; - if (this.resumeButton) this.resumeButton.interactable = false; - } - - private pauseBehaviorTree() { - this.isPaused = true; - this.updateStatus('已暂停'); - this.updateLog('⏸️ 行为树执行已暂停'); - - // 更新按钮状态 - if (this.pauseButton) this.pauseButton.interactable = false; - if (this.resumeButton) this.resumeButton.interactable = true; - } - - private resumeBehaviorTree() { - this.isPaused = false; - this.updateStatus('执行中...'); - this.updateLog('▶️ 行为树执行已恢复'); - - // 更新按钮状态 - if (this.pauseButton) this.pauseButton.interactable = true; - if (this.resumeButton) this.resumeButton.interactable = false; - } - - update(deltaTime: number) { - if (!this.isRunning || this.isPaused || !this.behaviorTree) { - return; - } - - this.updateTimer += deltaTime; - - // 每帧执行行为树 - try { - this.behaviorTree.tick(deltaTime); - - // 每2秒输出一次状态信息 - if (this.updateTimer >= 2.0) { - this.updateTimer = 0; - this.logBlackboardStatus(); - - // 检查行为树是否处于活动状态 - const isActive = this.behaviorTree.isActive(); - if (!isActive) { - this.updateLog('✅ 行为树执行完成'); - // 注意:这里只是演示,实际上行为树会持续运行 - // 如果需要检查完成状态,需要通过黑板变量或其他逻辑判断 - } - } - - } catch (error) { - console.error('行为树执行出错:', error); - this.updateLog('❌ 执行出错: ' + error.message); - this.stopBehaviorTree(); - } - } - - private logBlackboardStatus() { - if (!this.blackboard) return; - - // 获取所有黑板变量的当前值 - const variables = ['state', 'lastAction', 'defendActive', 'health', 'energy']; - const status = variables.map(name => { - const value = this.blackboard.getValue(name, 'undefined'); - return `${name}:${value}`; - }).join(', '); - - this.updateLog(`📊 状态: ${status}`); - } - - private updateStatus(status: string) { - if (this.statusLabel) { - this.statusLabel.string = status; - } - console.log('[BehaviorTree] 状态:', status); - } - - private updateLog(message: string) { - this.logs.push(`[${new Date().toLocaleTimeString()}] ${message}`); - - // 只保留最新的25条日志 - if (this.logs.length > 25) { - this.logs.shift(); - } - - if (this.logLabel) { - this.logLabel.string = this.logs.join('\n'); - } - - console.log('[BehaviorTree]', message); - } - - onDestroy() { - this.stopBehaviorTree(); - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts deleted file mode 100644 index d94223dd..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/BehaviorTreeTestScene.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { _decorator, Component, Node, Label, Button, Canvas, UITransform, Widget, Layout, Sprite, Color } from 'cc'; -import { BehaviorTreeExample } from './BehaviorTreeExample'; - -const { ccclass, property } = _decorator; - -/** - * 行为树测试场景 - * 自动创建UI界面用于测试行为树 - */ -@ccclass('BehaviorTreeTestScene') -export class BehaviorTreeTestScene extends Component { - - onLoad() { - this.createTestUI(); - } - - private createTestUI() { - // 创建Canvas - const canvasNode = new Node('BehaviorTreeTestCanvas'); - canvasNode.addComponent(Canvas); - canvasNode.addComponent(UITransform); - canvasNode.parent = this.node; - - // 创建背景 - const backgroundNode = new Node('Background'); - const backgroundTransform = backgroundNode.addComponent(UITransform); - backgroundTransform.setContentSize(1920, 1080); - const backgroundSprite = backgroundNode.addComponent(Sprite); - backgroundSprite.color = new Color(40, 40, 40, 255); - backgroundNode.parent = canvasNode; - - // 设置Widget组件使背景充满整个画布 - const backgroundWidget = backgroundNode.addComponent(Widget); - backgroundWidget.isAlignTop = true; - backgroundWidget.isAlignBottom = true; - backgroundWidget.isAlignLeft = true; - backgroundWidget.isAlignRight = true; - - // 创建主容器 - const mainContainer = new Node('MainContainer'); - const mainTransform = mainContainer.addComponent(UITransform); - mainTransform.setContentSize(1600, 900); - mainContainer.parent = canvasNode; - - // 设置主容器居中 - const mainWidget = mainContainer.addComponent(Widget); - mainWidget.isAlignHorizontalCenter = true; - mainWidget.isAlignVerticalCenter = true; - - // 设置主容器的Layout - const mainLayout = mainContainer.addComponent(Layout); - mainLayout.type = Layout.Type.VERTICAL; - mainLayout.spacingY = 20; - mainLayout.paddingTop = 50; - mainLayout.paddingBottom = 50; - mainLayout.paddingLeft = 50; - mainLayout.paddingRight = 50; - - // 创建标题 - const titleNode = this.createText('简化API行为树测试器', 48, Color.WHITE); - titleNode.parent = mainContainer; - - // 创建状态显示区域 - const statusContainer = new Node('StatusContainer'); - const statusTransform = statusContainer.addComponent(UITransform); - statusTransform.setContentSize(1500, 80); - statusContainer.parent = mainContainer; - - const statusLayout = statusContainer.addComponent(Layout); - statusLayout.type = Layout.Type.HORIZONTAL; - statusLayout.spacingX = 20; - - // 状态标签 - const statusLabelNode = this.createText('状态: 初始化中...', 24, Color.YELLOW); - statusLabelNode.parent = statusContainer; - - // 创建控制按钮区域 - const buttonContainer = new Node('ButtonContainer'); - const buttonTransform = buttonContainer.addComponent(UITransform); - buttonTransform.setContentSize(1500, 80); - buttonContainer.parent = mainContainer; - - const buttonLayout = buttonContainer.addComponent(Layout); - buttonLayout.type = Layout.Type.HORIZONTAL; - buttonLayout.spacingX = 20; - - // 创建控制按钮 - const startButton = this.createButton('开始执行', Color.GREEN); - const stopButton = this.createButton('停止', Color.RED); - const pauseButton = this.createButton('暂停', Color.YELLOW); - const resumeButton = this.createButton('恢复', Color.BLUE); - - startButton.parent = buttonContainer; - stopButton.parent = buttonContainer; - pauseButton.parent = buttonContainer; - resumeButton.parent = buttonContainer; - - // 创建说明区域 - const infoContainer = new Node('InfoContainer'); - const infoTransform = infoContainer.addComponent(UITransform); - infoTransform.setContentSize(1500, 60); - infoContainer.parent = mainContainer; - - const infoNode = this.createText('使用新的简化API - 一行代码完成所有初始化!', 18, Color.CYAN); - infoNode.parent = infoContainer; - - // 创建日志显示区域 - const logContainer = new Node('LogContainer'); - const logTransform = logContainer.addComponent(UITransform); - logTransform.setContentSize(1500, 600); - logContainer.parent = mainContainer; - - // 日志背景 - const logBackground = new Node('LogBackground'); - const logBgTransform = logBackground.addComponent(UITransform); - logBgTransform.setContentSize(1500, 600); - const logBgSprite = logBackground.addComponent(Sprite); - logBgSprite.color = new Color(20, 20, 20, 255); - logBackground.parent = logContainer; - - // 日志文本 - const logLabelNode = this.createText('等待行为树配置加载...', 16, Color.CYAN); - const logLabel = logLabelNode.getComponent(Label); - logLabel.overflow = Label.Overflow.RESIZE_HEIGHT; - logLabel.verticalAlign = Label.VerticalAlign.TOP; - logLabel.horizontalAlign = Label.HorizontalAlign.LEFT; - const logTransformComp = logLabelNode.getComponent(UITransform); - logTransformComp.setContentSize(1450, 550); - logLabelNode.parent = logContainer; - - // 设置日志文本位置 - const logWidget = logLabelNode.addComponent(Widget); - logWidget.isAlignTop = true; - logWidget.isAlignLeft = true; - logWidget.top = 25; - logWidget.left = 25; - - // 添加BehaviorTreeExample组件 - const behaviorTreeExample = this.node.addComponent(BehaviorTreeExample); - behaviorTreeExample.statusLabel = statusLabelNode.getComponent(Label); - behaviorTreeExample.logLabel = logLabel; - behaviorTreeExample.startButton = startButton.getComponent(Button); - behaviorTreeExample.stopButton = stopButton.getComponent(Button); - behaviorTreeExample.pauseButton = pauseButton.getComponent(Button); - behaviorTreeExample.resumeButton = resumeButton.getComponent(Button); - - // 初始化按钮状态 - stopButton.getComponent(Button).interactable = false; - pauseButton.getComponent(Button).interactable = false; - resumeButton.getComponent(Button).interactable = false; - startButton.getComponent(Button).interactable = false; // 等待行为树配置加载完成 - - console.log('行为树测试UI创建完成'); - } - - private createText(text: string, fontSize: number, color: Color): Node { - const textNode = new Node('Text'); - const textTransform = textNode.addComponent(UITransform); - - const label = textNode.addComponent(Label); - label.string = text; - label.fontSize = fontSize; - label.color = color; - label.lineHeight = fontSize + 4; - - // 根据文本内容调整大小 - const estimatedWidth = Math.max(200, text.length * fontSize * 0.6); - textTransform.setContentSize(estimatedWidth, fontSize + 10); - - return textNode; - } - - private createButton(text: string, color: Color): Node { - const buttonNode = new Node('Button'); - const buttonTransform = buttonNode.addComponent(UITransform); - buttonTransform.setContentSize(180, 60); - - // 按钮背景 - const buttonSprite = buttonNode.addComponent(Sprite); - buttonSprite.color = color; - - // 按钮组件 - const button = buttonNode.addComponent(Button); - button.target = buttonNode; - - // 按钮文本 - const labelNode = new Node('Label'); - const labelTransform = labelNode.addComponent(UITransform); - labelTransform.setContentSize(170, 50); - - const label = labelNode.addComponent(Label); - label.string = text; - label.fontSize = 20; - label.color = Color.WHITE; - label.horizontalAlign = Label.HorizontalAlign.CENTER; - label.verticalAlign = Label.VerticalAlign.CENTER; - - labelNode.parent = buttonNode; - - return buttonNode; - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts deleted file mode 100644 index 4e199542..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/ECSManager.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Core } from '@esengine/ecs-framework'; -import { Component, _decorator } from 'cc'; -import { ExampleGameScene } from './scenes/ExampleGameScene'; - -const { ccclass, property } = _decorator; - -/** - * ECS管理器 - Cocos Creator组件 - * 将此组件添加到场景中的任意节点上即可启动ECS框架 - * - * 使用说明: - * 1. 在Cocos Creator场景中创建一个空节点 - * 2. 将此ECSManager组件添加到该节点 - * 3. 运行场景即可自动启动ECS框架 - */ -@ccclass('ECSManager') -export class ECSManager extends Component { - - @property({ - tooltip: '是否启用调试模式(建议开发阶段开启)' - }) - public debugMode: boolean = true; - - private isInitialized: boolean = false; - - /** - * 组件启动时初始化ECS - */ - start() { - this.initializeECS(); - } - - /** - * 初始化ECS框架 - */ - private initializeECS(): void { - if (this.isInitialized) return; - - console.log('🎮 正在初始化ECS框架...'); - - try { - // 1. 创建Core实例,启用调试功能 - if (this.debugMode) { - Core.create({ - debugConfig: { - enabled: true, - websocketUrl: 'ws://localhost:8080/ecs-debug', - autoReconnect: true, - updateInterval: 1000, - channels: { - entities: true, - systems: true, - performance: true, - components: true, - scenes: true - } - } - }); - console.log('🔧 ECS调试模式已启用,可在Cocos Creator扩展面板中查看调试信息'); - } else { - Core.create(false); - } - - // 2. 创建游戏场景 - const gameScene = new ExampleGameScene(); - - // 3. 设置为当前场景(会自动调用scene.begin()) - Core.scene = gameScene; - - this.isInitialized = true; - console.log('✅ ECS框架初始化成功!'); - console.log('📖 请查看 assets/scripts/ecs/README.md 了解如何添加组件和系统'); - - } catch (error) { - console.error('❌ ECS框架初始化失败:', error); - } - } - - /** - * 每帧更新ECS框架 - */ - update(deltaTime: number) { - if (this.isInitialized) { - // 更新ECS核心系统 - Core.update(deltaTime); - } - } - - /** - * 组件销毁时清理ECS - */ - onDestroy() { - if (this.isInitialized) { - console.log('🧹 清理ECS框架...'); - // ECS框架会自动处理场景清理 - this.isInitialized = false; - } - } -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md b/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md deleted file mode 100644 index e259e0f8..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md +++ /dev/null @@ -1,153 +0,0 @@ -# ECS框架启动模板 - -欢迎使用ECS框架!这是一个最基础的启动模板,帮助您快速开始ECS项目开发。 - -## 📁 项目结构 - -``` -ecs/ -├── components/ # 组件目录(请在此添加您的组件) -├── systems/ # 系统目录(请在此添加您的系统) -├── scenes/ # 场景目录 -│ └── GameScene.ts # 主游戏场景 -├── ECSManager.ts # ECS管理器组件 -└── README.md # 本文档 -``` - -## 🚀 快速开始 - -### 1. 启动ECS框架 - -ECS框架已经配置完成!您只需要: - -1. 在Cocos Creator中打开您的场景 -2. 创建一个空节点(例如命名为"ECSManager") -3. 将 `ECSManager` 组件添加到该节点 -4. 运行场景,ECS框架将自动启动 - -### 2. 查看控制台输出 - -如果一切正常,您将在控制台看到: - -``` -🎮 正在初始化ECS框架... -🔧 ECS调试模式已启用,可在Cocos Creator扩展面板中查看调试信息 -🎯 游戏场景已创建 -✅ ECS框架初始化成功! -🚀 游戏场景已启动 -``` - -### 3. 使用调试面板 - -ECS框架已启用调试功能,您可以: - -1. 在Cocos Creator编辑器菜单中选择 "扩展" → "ECS Framework" → "调试面板" -2. 调试面板将显示实时的ECS运行状态: - - 实体数量和状态 - - 系统执行信息 - - 性能监控数据 - - 组件统计信息 - -**注意**:调试功能会消耗一定性能,正式发布时建议关闭调试模式。 - -## 📚 下一步开发 - -### 创建您的第一个组件 - -在 `components/` 目录下创建组件: - -```typescript -// components/PositionComponent.ts -import { Component } from '@esengine/ecs-framework'; -import { Vec3 } from 'cc'; - -export class PositionComponent extends Component { - public position: Vec3 = new Vec3(); - - constructor(x: number = 0, y: number = 0, z: number = 0) { - super(); - this.position.set(x, y, z); - } -} -``` - -### 创建您的第一个系统 - -在 `systems/` 目录下创建系统: - -```typescript -// systems/MovementSystem.ts -import { EntitySystem, Entity, Matcher } from '@esengine/ecs-framework'; -import { PositionComponent } from '../components/PositionComponent'; - -export class MovementSystem extends EntitySystem { - constructor() { - super(Matcher.empty().all(PositionComponent)); - } - - protected process(entities: Entity[]): void { - for (const entity of entities) { - const position = entity.getComponent(PositionComponent); - if (position) { - // TODO: 在这里编写移动逻辑 - console.log(`实体 ${entity.name} 位置: ${position.position}`); - } - } - } -} -``` - -### 在场景中注册系统 - -在 `scenes/GameScene.ts` 的 `initialize()` 方法中添加: - -```typescript -import { MovementSystem } from '../systems/MovementSystem'; - -public initialize(): void { - super.initialize(); - this.name = "MainGameScene"; - - // 添加系统 - this.addEntityProcessor(new MovementSystem()); - - // 创建测试实体 - const testEntity = this.createEntity("TestEntity"); - testEntity.addComponent(new PositionComponent(0, 0, 0)); -} -``` - -## 🔗 学习资源 - -- [ECS框架完整文档](https://github.com/esengine/ecs-framework) -- [ECS概念详解](https://github.com/esengine/ecs-framework/blob/master/docs/concepts-explained.md) -- [新手教程](https://github.com/esengine/ecs-framework/blob/master/docs/beginner-tutorials.md) -- [组件设计指南](https://github.com/esengine/ecs-framework/blob/master/docs/component-design-guide.md) -- [系统开发指南](https://github.com/esengine/ecs-framework/blob/master/docs/system-guide.md) - -## 💡 开发提示 - -1. **组件只存储数据**:避免在组件中编写复杂逻辑 -2. **系统处理逻辑**:所有业务逻辑应该在系统中实现 -3. **使用Matcher过滤实体**:系统通过Matcher指定需要处理的实体类型 -4. **性能优化**:大量实体时考虑使用位掩码查询和组件索引 - -## ❓ 常见问题 - -### Q: 如何创建实体? -A: 在场景中使用 `this.createEntity("实体名称")` - -### Q: 如何给实体添加组件? -A: 使用 `entity.addComponent(new YourComponent())` - -### Q: 如何获取实体的组件? -A: 使用 `entity.getComponent(YourComponent)` - -### Q: 如何删除实体? -A: 使用 `entity.destroy()` 或 `this.destroyEntity(entity)` - ---- - -🎮 **开始您的ECS开发之旅吧!** - -如有问题,请查阅官方文档或提交Issue。 diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md.meta deleted file mode 100644 index 36d492a6..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/README.md.meta +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ver": "1.0.1", - "importer": "text", - "imported": true, - "uuid": "0932496e-f7fe-4cb9-86e2-ebd7d2a3d047", - "files": [ - ".json" - ], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts deleted file mode 100644 index 0beea8d1..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/HealthComponent.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Component } from '@esengine/ecs-framework'; - -/** - * 生命值组件 - 管理实体的生命值和相关状态 - * - * 展示游戏逻辑组件的设计: - * 1. 包含生命值的核心数据 - * 2. 提供简单的查询方法 - * 3. 复杂的伤害处理逻辑留给系统处理 - */ -export class HealthComponent extends Component { - /** 最大生命值 */ - public maxHealth: number; - /** 当前生命值 */ - public currentHealth: number; - /** 生命值回复速度(每秒回复量) */ - public regenRate: number = 0; - /** 最后受到伤害的时间(用于延迟回血等机制) */ - public lastDamageTime: number = 0; - /** 是否无敌 */ - public invincible: boolean = false; - /** 无敌持续时间 */ - public invincibleDuration: number = 0; - - constructor(maxHealth: number = 100, regenRate: number = 0) { - super(); - this.maxHealth = maxHealth; - this.currentHealth = maxHealth; - this.regenRate = regenRate; - } - - /** - * 检查是否死亡 - */ - isDead(): boolean { - return this.currentHealth <= 0; - } - - /** - * 检查是否满血 - */ - isFullHealth(): boolean { - return this.currentHealth >= this.maxHealth; - } - - /** - * 获取生命值百分比(0-1) - */ - getHealthPercentage(): number { - return this.currentHealth / this.maxHealth; - } - - /** - * 检查生命值是否低于指定百分比 - */ - isHealthBelowPercentage(percentage: number): boolean { - return this.getHealthPercentage() < percentage; - } - - /** - * 设置生命值(不超过最大值) - */ - setHealth(health: number) { - this.currentHealth = Math.max(0, Math.min(health, this.maxHealth)); - } - - /** - * 增加生命值(治疗) - */ - heal(amount: number) { - this.currentHealth = Math.min(this.currentHealth + amount, this.maxHealth); - } - - /** - * 减少生命值(受伤) - * 注意:这里只修改数据,具体的伤害逻辑(如死亡处理)应该在系统中实现 - */ - takeDamage(damage: number) { - if (this.invincible) return; - - this.currentHealth = Math.max(0, this.currentHealth - damage); - this.lastDamageTime = Date.now(); - } - - /** - * 设置无敌状态 - */ - setInvincible(duration: number) { - this.invincible = true; - this.invincibleDuration = duration; - } - - /** - * 重置到满血状态 - */ - reset() { - this.currentHealth = this.maxHealth; - this.invincible = false; - this.invincibleDuration = 0; - this.lastDamageTime = 0; - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts deleted file mode 100644 index a1db37de..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { Component } from '@esengine/ecs-framework'; -import { Vec2 } from 'cc'; - -/** - * 玩家输入组件 - 存储玩家的输入状态 - * - * 标记组件示例: - * 1. 标识这是一个玩家控制的实体 - * 2. 存储输入状态数据 - * 3. 输入处理逻辑在InputSystem中实现 - */ -export class PlayerInputComponent extends Component { - /** 移动输入方向(-1到1) */ - public moveDirection: Vec2 = new Vec2(); - /** 按键状态 */ - public keys: { [key: string]: boolean } = {}; - /** 鼠标位置 */ - public mousePosition: Vec2 = new Vec2(); - /** 鼠标按键状态 */ - public mouseButtons: { left: boolean; right: boolean; middle: boolean } = { - left: false, - right: false, - middle: false - }; - - /** 是否启用输入 */ - public inputEnabled: boolean = true; - /** 输入敏感度 */ - public sensitivity: number = 1.0; - - constructor() { - super(); - } - - /** - * 设置移动方向 - */ - setMoveDirection(x: number, y: number) { - this.moveDirection.set(x, y); - // 标准化方向向量(对角线移动不应该更快) - if (this.moveDirection.lengthSqr() > 1) { - this.moveDirection.normalize(); - } - } - - /** - * 设置按键状态 - */ - setKey(key: string, pressed: boolean) { - this.keys[key] = pressed; - } - - /** - * 检查按键是否按下 - */ - isKeyPressed(key: string): boolean { - return this.keys[key] || false; - } - - /** - * 检查是否有移动输入 - */ - hasMovementInput(): boolean { - return this.moveDirection.lengthSqr() > 0.01; - } - - /** - * 获取标准化的移动方向 - */ - getNormalizedMoveDirection(): Vec2 { - const result = new Vec2(this.moveDirection); - if (result.lengthSqr() > 0) { - result.normalize(); - } - return result; - } - - /** - * 设置鼠标位置 - */ - setMousePosition(x: number, y: number) { - this.mousePosition.set(x, y); - } - - /** - * 设置鼠标按键状态 - */ - setMouseButton(button: 'left' | 'right' | 'middle', pressed: boolean) { - this.mouseButtons[button] = pressed; - } - - /** - * 检查鼠标按键是否按下 - */ - isMouseButtonPressed(button: 'left' | 'right' | 'middle'): boolean { - return this.mouseButtons[button]; - } - - /** - * 清除所有输入状态 - */ - clearInput() { - this.moveDirection.set(0, 0); - this.keys = {}; - this.mouseButtons.left = false; - this.mouseButtons.right = false; - this.mouseButtons.middle = false; - } - - /** - * 禁用输入 - */ - disableInput() { - this.inputEnabled = false; - this.clearInput(); - } - - /** - * 启用输入 - */ - enableInput() { - this.inputEnabled = true; - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts.meta deleted file mode 100644 index fdb48542..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PlayerInputComponent.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "ab10dc4c-c8a3-4fd2-83d6-433d4195966b", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts deleted file mode 100644 index c8ca710a..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Component } from '@esengine/ecs-framework'; -import { Vec3 } from 'cc'; - -/** - * 位置组件 - 存储实体的空间位置信息 - * - * 这是最基础的组件示例,展示了ECS组件的设计原则: - * 1. 主要存储数据,少量辅助方法 - * 2. 单一职责:只负责位置相关的数据 - * 3. 可复用:任何需要位置信息的实体都可以使用 - */ -export class PositionComponent extends Component { - /** 3D位置坐标 */ - public position: Vec3 = new Vec3(); - /** 上一帧的位置(用于计算移动距离) */ - public lastPosition: Vec3 = new Vec3(); - - constructor(x: number = 0, y: number = 0, z: number = 0) { - super(); - this.position.set(x, y, z); - this.lastPosition.set(x, y, z); - } - - /** - * 设置位置 - */ - setPosition(x: number, y: number, z: number = 0) { - this.lastPosition.set(this.position); - this.position.set(x, y, z); - } - - /** - * 移动位置 - */ - move(deltaX: number, deltaY: number, deltaZ: number = 0) { - this.lastPosition.set(this.position); - this.position.x += deltaX; - this.position.y += deltaY; - this.position.z += deltaZ; - } - - /** - * 计算到另一个位置的距离 - */ - distanceTo(other: PositionComponent): number { - return Vec3.distance(this.position, other.position); - } - - /** - * 获取本帧移动的距离 - */ - getMovementDistance(): number { - return Vec3.distance(this.position, this.lastPosition); - } - - /** - * 检查是否在指定范围内 - */ - isWithinRange(target: PositionComponent, range: number): boolean { - return this.distanceTo(target) <= range; - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts.meta deleted file mode 100644 index 373a89fa..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/PositionComponent.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "e6ee57d6-d0eb-43f2-a601-9b7a2812de66", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts deleted file mode 100644 index 0f6cff65..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Component } from '@esengine/ecs-framework'; -import { Vec3 } from 'cc'; - -/** - * 速度组件 - 存储实体的运动速度信息 - * - * 设计原则展示: - * 1. 与PositionComponent分离:遵循单一职责原则 - * 2. 包含速度限制:避免无限加速 - * 3. 提供常用的速度操作方法 - */ -export class VelocityComponent extends Component { - /** 当前速度向量 */ - public velocity: Vec3 = new Vec3(); - /** 最大速度限制 */ - public maxSpeed: number = 100; - /** 阻尼系数(0-1,1为无阻尼) */ - public damping: number = 1.0; - - constructor(x: number = 0, y: number = 0, z: number = 0, maxSpeed: number = 100) { - super(); - this.velocity.set(x, y, z); - this.maxSpeed = maxSpeed; - } - - /** - * 设置速度 - */ - setVelocity(x: number, y: number, z: number = 0) { - this.velocity.set(x, y, z); - this.clampToMaxSpeed(); - } - - /** - * 添加速度(加速度效果) - */ - addVelocity(x: number, y: number, z: number = 0) { - this.velocity.x += x; - this.velocity.y += y; - this.velocity.z += z; - this.clampToMaxSpeed(); - } - - /** - * 应用阻尼 - */ - applyDamping(deltaTime: number) { - if (this.damping < 1.0) { - const dampingFactor = Math.pow(this.damping, deltaTime); - this.velocity.multiplyScalar(dampingFactor); - } - } - - /** - * 限制速度不超过最大值 - */ - private clampToMaxSpeed() { - const speed = this.velocity.length(); - if (speed > this.maxSpeed) { - this.velocity.normalize(); - this.velocity.multiplyScalar(this.maxSpeed); - } - } - - /** - * 获取当前速度大小 - */ - getSpeed(): number { - return this.velocity.length(); - } - - /** - * 获取速度方向(单位向量) - */ - getDirection(): Vec3 { - const result = new Vec3(); - Vec3.normalize(result, this.velocity); - return result; - } - - /** - * 停止移动 - */ - stop() { - this.velocity.set(0, 0, 0); - } - - /** - * 检查是否在移动 - */ - isMoving(): boolean { - return this.velocity.lengthSqr() > 0.01; // 避免浮点数精度问题 - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts.meta deleted file mode 100644 index f6b15dfc..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/VelocityComponent.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "784d7c28-2b72-427c-8b04-da0fcf775acf", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/examples.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/examples.meta deleted file mode 100644 index 7a446087..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/examples.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.2.0", - "importer": "directory", - "imported": true, - "uuid": "6a2d6231-acf9-47b8-a020-d45a7433a95d", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/factories.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/factories.meta deleted file mode 100644 index 8d4aa6b2..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/factories.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.2.0", - "importer": "directory", - "imported": true, - "uuid": "80dcbaf5-21f7-4bb1-aff4-2cdbb0b5d364", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes.meta deleted file mode 100644 index 6960de88..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.2.0", - "importer": "directory", - "imported": true, - "uuid": "879b4e07-dd6b-4445-adb2-a970b97c6d6f", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts deleted file mode 100644 index 2f2fa464..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts +++ /dev/null @@ -1,316 +0,0 @@ -import { Scene } from '@esengine/ecs-framework'; -import { Entity } from '@esengine/ecs-framework'; - -// 导入组件 -import { PositionComponent } from '../components/PositionComponent'; -import { VelocityComponent } from '../components/VelocityComponent'; -import { HealthComponent } from '../components/HealthComponent'; -import { PlayerInputComponent } from '../components/PlayerInputComponent'; - -// 导入系统 -import { MovementSystem } from '../systems/MovementSystem'; -import { PlayerInputSystem } from '../systems/PlayerInputSystem'; -import { HealthSystem } from '../systems/HealthSystem'; - -/** - * 示例游戏场景 - 完整的ECS应用示例 - * - * 这个场景展示了: - * 1. 如何创建和配置各种实体 - * 2. 如何添加和组织系统 - * 3. 如何实现完整的游戏逻辑 - * 4. 如何进行调试和监控 - */ -export class ExampleGameScene extends Scene { - // 场景中的重要实体引用 - private player: Entity | null; - private enemies: Entity[]; - private gameConfig: { - maxEnemies: number; - enemySpawnInterval: number; - gameArea: { width: number; height: number }; - }; - - constructor() { - super(); - // 在构造函数中初始化属性 - this.player = null; - this.enemies = []; - this.gameConfig = { - maxEnemies: 5, - enemySpawnInterval: 3000, // 3秒生成一个敌人 - gameArea: { width: 800, height: 600 } - }; - } - - /** - * 场景初始化(构造时调用) - */ - public initialize(): void { - super.initialize(); - this.name = "ExampleGameScene"; - console.log("📋 ExampleGameScene 构造完成"); - } - - /** - * 场景开始时的回调(所有构造函数执行完毕后调用) - */ - public onStart(): void { - super.onStart(); - - console.log("🎮 开始初始化示例游戏场景..."); - - // 1. 添加系统(注意顺序很重要) - this.setupSystems(); - - // 2. 创建游戏实体 - this.createGameEntities(); - - // 3. 设置定时器和事件 - this.setupGameLogic(); - - console.log("✅ 示例游戏场景初始化完成!"); - this.printSceneInfo(); - } - - /** - * 设置游戏系统 - */ - private setupSystems(): void { - console.log("🔧 添加游戏系统..."); - - // 输入系统(最先处理输入) - this.addEntityProcessor(new PlayerInputSystem()); - - // 移动系统(处理所有移动逻辑) - this.addEntityProcessor(new MovementSystem()); - - // 生命值系统(处理生命值、死亡等) - this.addEntityProcessor(new HealthSystem()); - - console.log("✅ 系统添加完成"); - } - - /** - * 创建游戏实体 - */ - private createGameEntities(): void { - console.log("🏗️ 创建游戏实体..."); - - // 创建玩家 - this.createPlayer(); - - // 创建初始敌人 - this.createInitialEnemies(); - - // 创建环境实体(可选) - this.createEnvironmentEntities(); - - console.log("✅ 实体创建完成"); - } - - /** - * 创建玩家实体 - */ - private createPlayer(): void { - this.player = this.createEntity("Player"); - - // 添加玩家组件 - this.player.addComponent(new PositionComponent(0, 0, 0)); - this.player.addComponent(new VelocityComponent(0, 0, 0, 250)); // 最大速度250 - this.player.addComponent(new HealthComponent(100, 5)); // 100血,每秒回5血 - this.player.addComponent(new PlayerInputComponent()); - - console.log("🎯 玩家创建完成 - 使用WASD或方向键移动,空格键攻击"); - } - - /** - * 创建初始敌人 - */ - private createInitialEnemies(): void { - for (let i = 0; i < 3; i++) { - this.createEnemy(i); - } - } - - /** - * 创建单个敌人 - */ - private createEnemy(index: number): Entity { - const enemy = this.createEntity(`Enemy_${index}`); - - // 随机位置 - const x = (Math.random() - 0.5) * this.gameConfig.gameArea.width; - const y = (Math.random() - 0.5) * this.gameConfig.gameArea.height; - - // 随机速度 - const velocityX = (Math.random() - 0.5) * 100; - const velocityY = (Math.random() - 0.5) * 100; - - // 添加敌人组件 - enemy.addComponent(new PositionComponent(x, y, 0)); - enemy.addComponent(new VelocityComponent(velocityX, velocityY, 0, 150)); - enemy.addComponent(new HealthComponent(50, 0)); // 50血,不回血 - - // 添加到敌人列表 - this.enemies.push(enemy); - - return enemy; - } - - /** - * 创建环境实体(演示不同类型的实体) - */ - private createEnvironmentEntities(): void { - // 创建一些静态的环境对象 - for (let i = 0; i < 5; i++) { - const obstacle = this.createEntity(`Obstacle_${i}`); - - const x = (Math.random() - 0.5) * this.gameConfig.gameArea.width * 0.8; - const y = (Math.random() - 0.5) * this.gameConfig.gameArea.height * 0.8; - - // 只有位置,没有速度和生命值 - obstacle.addComponent(new PositionComponent(x, y, 0)); - } - - console.log("🌲 环境实体创建完成"); - } - - /** - * 设置游戏逻辑和定时器 - */ - private setupGameLogic(): void { - console.log("⚙️ 设置游戏逻辑..."); - - // 敌人生成定时器 - this.setupEnemySpawner(); - - // 游戏状态监控 - this.setupGameMonitoring(); - - console.log("✅ 游戏逻辑设置完成"); - } - - /** - * 设置敌人生成器 - */ - private setupEnemySpawner(): void { - setInterval(() => { - if (this.enemies.length < this.gameConfig.maxEnemies) { - const newEnemy = this.createEnemy(this.enemies.length); - } - }, this.gameConfig.enemySpawnInterval); - } - - /** - * 设置游戏监控 - */ - private setupGameMonitoring(): void { - // 每10秒清理已死亡的敌人引用 - setInterval(() => { - this.cleanupDeadEnemies(); - }, 10000); - } - - /** - * 打印游戏状态(按需调用) - */ - private printGameStatus(): void { - const totalEntities = this.entities.count; - const aliveEnemies = this.enemies.filter(e => !e.isDestroyed).length; - - console.log("📊 游戏状态报告:"); - console.log(` - 总实体数: ${totalEntities}`); - console.log(` - 存活敌人: ${aliveEnemies}`); - - if (this.player && !this.player.isDestroyed) { - const playerHealth = this.player.getComponent(HealthComponent); - const playerPos = this.player.getComponent(PositionComponent); - console.log(` - 玩家生命值: ${playerHealth?.currentHealth}/${playerHealth?.maxHealth}`); - console.log(` - 玩家位置: (${playerPos?.position.x.toFixed(1)}, ${playerPos?.position.y.toFixed(1)})`); - } - } - - /** - * 清理已死亡的敌人引用 - */ - private cleanupDeadEnemies(): void { - const initialCount = this.enemies.length; - this.enemies = this.enemies.filter(enemy => !enemy.isDestroyed); - const removedCount = initialCount - this.enemies.length; - - if (removedCount > 0) { - console.log(`🧹 清理了 ${removedCount} 个已死亡的敌人引用`); - } - } - - /** - * 打印场景信息 - */ - private printSceneInfo(): void { - console.log("\n📋 场景信息:"); - console.log(` 场景名: ${this.name}`); - console.log(` 实体数: ${this.entities.count}`); - console.log(` 系统数: ${this.entityProcessors.count}`); - console.log(` 玩家: ${this.player?.name || '未创建'}`); - console.log(` 敌人: ${this.enemies.length} 个`); - console.log("\n🎮 控制说明:"); - console.log(" - WASD 或 方向键: 移动"); - console.log(" - 空格: 攻击/行动"); - console.log(" - ESC: 暂停"); - console.log("\n💡 学习要点:"); - console.log(" 1. 观察控制台输出,了解ECS运行过程"); - console.log(" 2. 打开调试面板查看性能数据"); - console.log(" 3. 尝试修改组件参数观察变化"); - console.log(" 4. 查看代码学习ECS设计模式\n"); - } - - /** - * 获取玩家实体(供其他系统使用) - */ - public getPlayer(): Entity | null { - return this.player; - } - - /** - * 获取所有敌人(供其他系统使用) - */ - public getEnemies(): Entity[] { - return this.enemies.filter(enemy => !enemy.isDestroyed); - } - - /** - * 游戏重置方法 - */ - public resetGame(): void { - console.log("🔄 重置游戏..."); - - // 销毁所有实体 - if (this.player) { - this.player.destroy(); - this.player = null; - } - - this.enemies.forEach(enemy => enemy.destroy()); - this.enemies = []; - - // 重新创建实体 - this.createGameEntities(); - - console.log("✅ 游戏重置完成"); - } - - /** - * 场景卸载时调用 - */ - public unload(): void { - console.log("🧹 清理示例游戏场景..."); - - // 清理引用 - this.player = null; - this.enemies = []; - - super.unload(); - console.log("✅ 场景清理完成"); - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts.meta deleted file mode 100644 index 954166d9..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/ExampleGameScene.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "da87facc-89a0-47da-a0ef-423255200a51", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts deleted file mode 100644 index a44cd0d7..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Scene } from '@esengine/ecs-framework'; - -/** - * 游戏场景 - * - * 这是您的主游戏场景。在这里可以: - * - 添加游戏系统 - * - 创建初始实体 - * - 设置场景参数 - */ -export class GameScene extends Scene { - - /** - * 场景初始化 - * 在场景创建时调用,用于设置基础配置 - */ - public initialize(): void { - super.initialize(); - - // 设置场景名称 - this.name = "MainGameScene"; - - console.log('🎯 游戏场景已创建'); - - // TODO: 在这里添加您的游戏系统 - // 例如:this.addEntityProcessor(new MovementSystem()); - - // TODO: 在这里创建初始实体 - // 例如:this.createEntity("Player"); - } - - /** - * 场景开始运行 - * 在场景开始时调用,用于执行启动逻辑 - */ - public onStart(): void { - super.onStart(); - - console.log('🚀 游戏场景已启动'); - - // TODO: 在这里添加场景启动逻辑 - // 例如:创建UI、播放音乐、初始化游戏状态等 - } - - /** - * 场景卸载 - * 在场景结束时调用,用于清理资源 - */ - public unload(): void { - console.log('🛑 游戏场景已结束'); - - // TODO: 在这里添加清理逻辑 - // 例如:清理缓存、释放资源等 - - super.unload(); - } -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts.meta deleted file mode 100644 index 31597f38..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/scenes/GameScene.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "8fee85be-2224-4200-a898-d3ae2406fb1d", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems.meta deleted file mode 100644 index e6b95132..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.2.0", - "importer": "directory", - "imported": true, - "uuid": "a5e3a8c9-3d0b-4a36-9d20-6f70f1380131", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts deleted file mode 100644 index 462df23f..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { EntitySystem, Entity, Matcher, Time } from '@esengine/ecs-framework'; -import { HealthComponent } from '../components/HealthComponent'; - -/** - * 生命值系统 - 处理生命值相关的逻辑 - * - * 展示生命值管理: - * 1. 自动回血 - * 2. 无敌状态管理 - * 3. 死亡处理 - * 4. 事件触发 - */ -export class HealthSystem extends EntitySystem { - /** 回血延迟时间(受伤后多久开始回血,毫秒) */ - private regenDelay: number = 3000; - - constructor() { - // 只处理拥有HealthComponent的实体 - super(Matcher.empty().all(HealthComponent)); - } - - public initialize(): void { - super.initialize(); - console.log("HealthSystem 已初始化 - 开始处理生命值逻辑"); - } - - /** - * 每帧处理:更新生命值相关逻辑 - */ - protected process(entities: Entity[]): void { - for (const entity of entities) { - const health = entity.getComponent(HealthComponent); - - // 处理无敌状态 - this.processInvincibility(health); - - // 处理生命值回复 - this.processHealthRegeneration(entity, health); - - // 检查死亡状态 - this.checkDeathStatus(entity, health); - } - } - - /** - * 处理无敌状态 - */ - private processInvincibility(health: HealthComponent): void { - if (health.invincible && health.invincibleDuration > 0) { - health.invincibleDuration -= Time.deltaTime; - - // 无敌时间结束 - if (health.invincibleDuration <= 0) { - health.invincible = false; - health.invincibleDuration = 0; - console.log("无敌状态结束"); - } - } - } - - /** - * 处理生命值回复 - */ - private processHealthRegeneration(entity: Entity, health: HealthComponent): void { - // 如果已经满血或者没有回复速度,则不处理 - if (health.isFullHealth() || health.regenRate <= 0) { - return; - } - - // 检查是否超过了回血延迟时间 - const currentTime = Date.now(); - if (currentTime - health.lastDamageTime < this.regenDelay) { - return; - } - - // 计算回血量 - const regenAmount = health.regenRate * Time.deltaTime; - const oldHealth = health.currentHealth; - - // 执行回血 - health.heal(regenAmount); - - // 如果实际回了血,输出日志 - if (health.currentHealth > oldHealth) { - console.log(`${entity.name} 回血: ${oldHealth.toFixed(1)} -> ${health.currentHealth.toFixed(1)} (${health.getHealthPercentage() * 100}%)`); - } - } - - /** - * 检查死亡状态 - */ - private checkDeathStatus(entity: Entity, health: HealthComponent): void { - if (health.isDead()) { - this.handleEntityDeath(entity, health); - } - } - - /** - * 处理实体死亡 - */ - private handleEntityDeath(entity: Entity, health: HealthComponent): void { - console.log(`💀 ${entity.name} 已死亡!`); - - // 触发死亡事件(如果有事件系统) - this.triggerDeathEvent(entity); - - // 可以在这里添加死亡效果、掉落物品等逻辑 - this.createDeathEffect(entity); - - // 标记实体为死亡状态(而不是立即销毁) - // 这样其他系统可以处理死亡相关的逻辑 - entity.addComponent(new DeadMarkerComponent()); - - // 可选:延迟销毁实体 - setTimeout(() => { - if (entity && !entity.isDestroyed) { - entity.destroy(); - console.log(`${entity.name} 已被销毁`); - } - }, 1000); // 1秒后销毁 - } - - /** - * 触发死亡事件 - */ - private triggerDeathEvent(entity: Entity): void { - // 如果项目中有事件系统,可以在这里发送死亡事件 - console.log(`触发死亡事件: ${entity.name}`); - - // 示例事件数据 - const deathEventData = { - entityId: entity.id, - entityName: entity.name, - deathTime: Date.now(), - position: this.getEntityPosition(entity) - }; - - // 这里可以调用事件系统发送事件 - // eventBus.emit('entity:died', deathEventData); - } - - /** - * 创建死亡效果 - */ - private createDeathEffect(entity: Entity): void { - console.log(`💥 为 ${entity.name} 创建死亡效果`); - - // 在实际游戏中,这里可能会: - // 1. 播放死亡动画 - // 2. 播放死亡音效 - // 3. 创建粒子效果 - // 4. 掉落物品 - } - - /** - * 获取实体位置(辅助方法) - */ - private getEntityPosition(entity: Entity): { x: number; y: number; z: number } { - // 尝试获取位置组件 - const position = entity.getComponent(PositionComponent); - if (position) { - return { - x: position.position.x, - y: position.position.y, - z: position.position.z - }; - } - - return { x: 0, y: 0, z: 0 }; - } - - /** - * 公共方法:对实体造成伤害 - * 这个方法可以被其他系统调用 - */ - public damageEntity(entity: Entity, damage: number, source?: Entity): boolean { - const health = entity.getComponent(HealthComponent); - if (!health || health.invincible) { - return false; // 无生命值组件或处于无敌状态 - } - - const oldHealth = health.currentHealth; - health.takeDamage(damage); - - console.log(`⚔️ ${entity.name} 受到 ${damage} 点伤害: ${oldHealth.toFixed(1)} -> ${health.currentHealth.toFixed(1)}`); - - // 如果有伤害来源,可以记录或处理 - if (source) { - console.log(`伤害来源: ${source.name}`); - } - - return true; - } - - /** - * 公共方法:治疗实体 - */ - public healEntity(entity: Entity, healAmount: number): boolean { - const health = entity.getComponent(HealthComponent); - if (!health || health.isFullHealth()) { - return false; - } - - const oldHealth = health.currentHealth; - health.heal(healAmount); - - console.log(`💚 ${entity.name} 恢复 ${healAmount} 点生命值: ${oldHealth.toFixed(1)} -> ${health.currentHealth.toFixed(1)}`); - - return true; - } -} - -/** - * 死亡标记组件 - 标记已死亡的实体 - * 这是一个简单的标记组件,用于标识死亡状态 - */ -class DeadMarkerComponent extends Component { - public deathTime: number; - - constructor() { - super(); - this.deathTime = Date.now(); - } -} - -// 导入位置组件(用于获取实体位置) -import { PositionComponent } from '../components/PositionComponent'; -import { Component } from '@esengine/ecs-framework'; \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts.meta deleted file mode 100644 index b00f7c32..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/HealthSystem.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "455c12d1-52a8-41ac-b1b5-0d2b93c079aa", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts deleted file mode 100644 index 4b82cd61..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { EntitySystem, Entity, Matcher, Time } from '@esengine/ecs-framework'; -import { PositionComponent } from '../components/PositionComponent'; -import { VelocityComponent } from '../components/VelocityComponent'; - -/** - * 移动系统 - 处理实体的移动逻辑 - * - * EntitySystem示例: - * 1. 使用Matcher指定需要的组件(Position + Velocity) - * 2. 每帧更新所有移动实体的位置 - * 3. 展示组件间的协作 - */ -export class MovementSystem extends EntitySystem { - constructor() { - // 只处理同时拥有PositionComponent和VelocityComponent的实体 - super(Matcher.empty().all(PositionComponent, VelocityComponent)); - } - - /** - * 每帧执行:更新所有移动实体的位置 - */ - protected process(entities: Entity[]): void { - for (const entity of entities) { - const position = entity.getComponent(PositionComponent); - const velocity = entity.getComponent(VelocityComponent); - - // 基本移动:位置 = 当前位置 + 速度 * 时间 - position.move( - velocity.velocity.x * Time.deltaTime, - velocity.velocity.y * Time.deltaTime, - velocity.velocity.z * Time.deltaTime - ); - - // 应用阻尼(摩擦力) - velocity.applyDamping(Time.deltaTime); - - // 可选:添加边界检查 - this.checkBoundaries(position, velocity); - } - } - - /** - * 边界检查(可选功能) - * 这个方法演示了如何在系统中实现额外的游戏逻辑 - */ - private checkBoundaries(position: PositionComponent, velocity: VelocityComponent) { - const bounds = { - left: -400, - right: 400, - top: 300, - bottom: -300 - }; - - // 检查X轴边界 - if (position.position.x < bounds.left) { - position.position.x = bounds.left; - velocity.velocity.x = Math.abs(velocity.velocity.x); // 反弹 - } else if (position.position.x > bounds.right) { - position.position.x = bounds.right; - velocity.velocity.x = -Math.abs(velocity.velocity.x); // 反弹 - } - - // 检查Y轴边界 - if (position.position.y < bounds.bottom) { - position.position.y = bounds.bottom; - velocity.velocity.y = Math.abs(velocity.velocity.y); // 反弹 - } else if (position.position.y > bounds.top) { - position.position.y = bounds.top; - velocity.velocity.y = -Math.abs(velocity.velocity.y); // 反弹 - } - } - - /** - * 系统初始化时调用 - * 可以在这里设置系统级别的配置 - */ - public initialize(): void { - super.initialize(); - console.log("MovementSystem 已初始化 - 开始处理实体移动"); - } - - /** - * 获取系统统计信息(用于调试) - */ - public getStats(): { processedEntities: number; totalMovement: number } { - let totalMovement = 0; - const entities = this.entities; - - for (const entity of entities) { - const position = entity.getComponent(PositionComponent); - totalMovement += position.getMovementDistance(); - } - - return { - processedEntities: entities.length, - totalMovement: totalMovement - }; - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts.meta deleted file mode 100644 index 9114e24e..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/MovementSystem.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "a8712467-efe0-46ec-a246-a9fa07d203d9", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts deleted file mode 100644 index 859ed609..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { EntitySystem, Entity, Matcher } from '@esengine/ecs-framework'; -import { PlayerInputComponent } from '../components/PlayerInputComponent'; -import { VelocityComponent } from '../components/VelocityComponent'; -import { input, Input, EventKeyboard, KeyCode } from 'cc'; - -/** - * 玩家输入系统 - 处理玩家输入并转换为游戏行为 - * - * 展示系统的职责: - * 1. 收集输入事件 - * 2. 更新输入组件状态 - * 3. 根据输入修改其他组件(如速度) - */ -export class PlayerInputSystem extends EntitySystem { - private moveSpeed: number = 200; // 移动速度 - - constructor() { - // 只处理拥有PlayerInputComponent的实体 - super(Matcher.empty().all(PlayerInputComponent)); - } - - public initialize(): void { - super.initialize(); - console.log("PlayerInputSystem 已初始化 - 开始监听玩家输入"); - - // 注册键盘事件监听器 - this.setupInputListeners(); - } - - /** - * 设置输入事件监听器 - */ - private setupInputListeners(): void { - // 键盘按下事件 - input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this); - // 键盘抬起事件 - input.on(Input.EventType.KEY_UP, this.onKeyUp, this); - } - - /** - * 键盘按下处理 - */ - private onKeyDown(event: EventKeyboard): void { - const keyCode = event.keyCode; - const keyName = this.getKeyName(keyCode); - - // 更新所有玩家实体的输入状态 - for (const entity of this.entities) { - const playerInput = entity.getComponent(PlayerInputComponent); - if (playerInput && playerInput.inputEnabled) { - playerInput.setKey(keyName, true); - } - } - } - - /** - * 键盘抬起处理 - */ - private onKeyUp(event: EventKeyboard): void { - const keyCode = event.keyCode; - const keyName = this.getKeyName(keyCode); - - // 更新所有玩家实体的输入状态 - for (const entity of this.entities) { - const playerInput = entity.getComponent(PlayerInputComponent); - if (playerInput && playerInput.inputEnabled) { - playerInput.setKey(keyName, false); - } - } - } - - /** - * 每帧处理:根据输入状态更新实体行为 - */ - protected process(entities: Entity[]): void { - for (const entity of entities) { - const playerInput = entity.getComponent(PlayerInputComponent); - - if (!playerInput || !playerInput.inputEnabled) { - continue; - } - - // 处理移动输入 - this.processMovementInput(entity, playerInput); - - // 处理其他输入(如攻击、跳跃等) - this.processActionInput(entity, playerInput); - } - } - - /** - * 处理移动输入 - */ - private processMovementInput(entity: Entity, playerInput: PlayerInputComponent): void { - const velocity = entity.getComponent(VelocityComponent); - if (!velocity) return; - - // 根据按键状态计算移动方向 - let moveX = 0; - let moveY = 0; - - if (playerInput.isKeyPressed('A') || playerInput.isKeyPressed('ArrowLeft')) { - moveX -= 1; - } - if (playerInput.isKeyPressed('D') || playerInput.isKeyPressed('ArrowRight')) { - moveX += 1; - } - if (playerInput.isKeyPressed('W') || playerInput.isKeyPressed('ArrowUp')) { - moveY += 1; - } - if (playerInput.isKeyPressed('S') || playerInput.isKeyPressed('ArrowDown')) { - moveY -= 1; - } - - // 更新输入组件的移动方向 - playerInput.setMoveDirection(moveX, moveY); - - // 将输入转换为速度 - const normalizedDirection = playerInput.getNormalizedMoveDirection(); - velocity.setVelocity( - normalizedDirection.x * this.moveSpeed * playerInput.sensitivity, - normalizedDirection.y * this.moveSpeed * playerInput.sensitivity, - 0 - ); - } - - /** - * 处理动作输入(攻击、技能等) - */ - private processActionInput(entity: Entity, playerInput: PlayerInputComponent): void { - // 空格键 - 跳跃或攻击 - if (playerInput.isKeyPressed('Space')) { - console.log(`玩家 ${entity.name} 执行动作:攻击/跳跃`); - // 这里可以触发攻击组件或添加跳跃效果 - } - - // ESC键 - 暂停游戏 - if (playerInput.isKeyPressed('Escape')) { - console.log("玩家请求暂停游戏"); - // 可以发送暂停事件给游戏管理系统 - } - } - - /** - * 将键码转换为字符串 - */ - private getKeyName(keyCode: KeyCode): string { - const keyMap: { [key: number]: string } = { - [KeyCode.KEY_A]: 'A', - [KeyCode.KEY_D]: 'D', - [KeyCode.KEY_S]: 'S', - [KeyCode.KEY_W]: 'W', - [KeyCode.ARROW_LEFT]: 'ArrowLeft', - [KeyCode.ARROW_RIGHT]: 'ArrowRight', - [KeyCode.ARROW_UP]: 'ArrowUp', - [KeyCode.ARROW_DOWN]: 'ArrowDown', - [KeyCode.SPACE]: 'Space', - [KeyCode.ESCAPE]: 'Escape' - }; - - return keyMap[keyCode] || `Key_${keyCode}`; - } - - /** - * 系统清理 - */ - public onDestroy(): void { - // 移除事件监听器 - input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this); - input.off(Input.EventType.KEY_UP, this.onKeyUp, this); - console.log("PlayerInputSystem 已清理"); - } -} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts.meta b/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts.meta deleted file mode 100644 index 967ac043..00000000 --- a/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/PlayerInputSystem.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "4.0.24", - "importer": "typescript", - "imported": true, - "uuid": "7b69a39f-926a-4260-94ba-e15e31b324b5", - "files": [], - "subMetas": {}, - "userData": {} -} diff --git a/extensions/cocos/cocos-ecs/enemy-ai.bt.json b/extensions/cocos/cocos-ecs/enemy-ai.bt.json new file mode 100644 index 00000000..c4fd48d0 --- /dev/null +++ b/extensions/cocos/cocos-ecs/enemy-ai.bt.json @@ -0,0 +1,214 @@ +{ + "nodes": [ + { + "id": "root", + "type": "root", + "name": "敌人AI根节点", + "description": "敌人AI行为树的根节点,控制敌人的所有行为逻辑。包含攻击、追击和巡逻三种主要行为模式。", + "children": [ + "main-selector" + ] + }, + { + "id": "main-selector", + "type": "selector", + "name": "主要行为选择器", + "description": "选择器节点:按优先级执行子节点(攻击>追击>巡逻)。这确保敌人在有目标时优先战斗,没有目标时进行巡逻。", + "children": [ + "attack-behavior", + "chase-behavior", + "patrol-behavior" + ] + }, + { + "id": "attack-behavior", + "type": "conditional-decorator", + "name": "攻击行为", + "description": "条件装饰器:只有当发现目标且距离足够近时才进行攻击。这确保敌人只在有效攻击范围内战斗。", + "children": [ + "attack-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasTarget", + "compareOperator": "equals", + "compareValue": true + } + } + }, + { + "id": "attack-sequence", + "type": "sequence", + "name": "攻击序列", + "description": "序列节点:按顺序执行攻击相关的所有步骤,确保攻击逻辑的完整性。", + "children": [ + "set-attack-state", + "attack-cooldown-check", + "perform-attack", + "reset-attack-cooldown" + ] + }, + { + "id": "set-attack-state", + "type": "set-blackboard-value", + "name": "设置攻击状态", + "description": "黑板赋值节点:将敌人状态设置为'attacking',便于其他系统了解敌人当前行为。" + }, + { + "id": "attack-cooldown-check", + "type": "conditional-decorator", + "name": "攻击冷却检查", + "description": "条件装饰器:检查攻击冷却是否结束。只有冷却时间为0时才能执行攻击,防止过于频繁的攻击。", + "children": [ + "attack-action" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "attackCooldown", + "compareOperator": "lessEqual", + "compareValue": 0 + } + } + }, + { + "id": "attack-action", + "type": "event-action", + "name": "执行攻击", + "description": "事件动作节点:触发实际的攻击事件,造成伤害并播放攻击动画和音效。" + }, + { + "id": "perform-attack", + "type": "log-action", + "name": "攻击日志", + "description": "日志动作节点:记录攻击行为,用于调试和监控敌人AI的行为表现。" + }, + { + "id": "reset-attack-cooldown", + "type": "set-blackboard-value", + "name": "重置攻击冷却", + "description": "黑板赋值节点:设置攻击冷却时间为1.5秒,控制攻击频率,避免过于频繁的攻击。" + }, + { + "id": "chase-behavior", + "type": "conditional-decorator", + "name": "追击行为", + "description": "条件装饰器:当发现目标但距离较远时进行追击。这是攻击和巡逻之间的中间状态。", + "children": [ + "chase-sequence" + ], + "condition": { + "type": "blackboard-value-comparison", + "properties": { + "variableName": "hasTarget", + "compareOperator": "equals", + "compareValue": true + } + } + }, + { + "id": "chase-sequence", + "type": "sequence", + "name": "追击序列", + "description": "序列节点:执行追击相关的行为,包括状态设置、移动和冷却更新。", + "children": [ + "set-chase-state", + "move-to-target", + "update-attack-cooldown" + ] + }, + { + "id": "set-chase-state", + "type": "set-blackboard-value", + "name": "设置追击状态", + "description": "黑板赋值节点:将敌人状态设置为'chasing',表示正在追击目标。" + }, + { + "id": "move-to-target", + "type": "event-action", + "name": "向目标移动", + "description": "事件动作节点:触发移动事件,让敌人朝目标方向移动。移动速度比巡逻时更快。" + }, + { + "id": "update-attack-cooldown", + "type": "math-blackboard-operation", + "name": "更新攻击冷却", + "description": "数学运算节点:减少攻击冷却时间,让敌人在追击过程中为下次攻击做准备。" + }, + { + "id": "patrol-behavior", + "type": "sequence", + "name": "巡逻行为", + "description": "序列节点:当没有目标时执行巡逻行为。这是敌人的默认行为,确保敌人始终在活动。", + "children": [ + "patrol-sequence" + ] + }, + { + "id": "patrol-sequence", + "type": "sequence", + "name": "巡逻序列", + "description": "序列节点:执行完整的巡逻循环,包括状态设置、移动和等待。", + "children": [ + "set-patrol-state", + "patrol-move", + "patrol-wait" + ] + }, + { + "id": "set-patrol-state", + "type": "set-blackboard-value", + "name": "设置巡逻状态", + "description": "黑板赋值节点:将敌人状态设置为'patrolling',表示正在巡逻。" + }, + { + "id": "patrol-move", + "type": "event-action", + "name": "巡逻移动", + "description": "事件动作节点:触发巡逻移动事件,让敌人在预设的巡逻路径上移动。" + }, + { + "id": "patrol-wait", + "type": "wait-action", + "name": "巡逻等待", + "description": "等待动作节点:在巡逻点停留2秒,模拟敌人观察周围环境。这让巡逻看起来更自然。" + } + ], + "blackboard": [ + { + "name": "currentState", + "type": "string", + "value": "idle", + "description": "敌人的当前状态(idle、attacking、chasing、patrolling),用于状态跟踪和AI调试", + "group": "状态" + }, + { + "name": "hasTarget", + "type": "boolean", + "value": "false", + "description": "是否发现了有效目标,决定敌人是否应该从巡逻切换到追击模式", + "group": "目标" + }, + { + "name": "attackCooldown", + "type": "number", + "value": "0", + "description": "攻击冷却倒计时(秒),控制攻击频率,0表示可以攻击,大于0表示正在冷却", + "group": "战斗" + }, + { + "name": "lastKnownTargetPosition", + "type": "string", + "value": "0,0", + "description": "最后已知的目标位置,用于敌人在失去目标后继续搜索一段时间", + "group": "目标" + } + ], + "metadata": { + "name": "behavior-tree", + "created": "2025-06-24T03:38:29.653Z", + "version": "1.0", + "exportType": "clean" + } +} \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/behaviour-tree b/extensions/cocos/cocos-ecs/extensions/behaviour-tree index 65757638..714a3ab9 160000 --- a/extensions/cocos/cocos-ecs/extensions/behaviour-tree +++ b/extensions/cocos/cocos-ecs/extensions/behaviour-tree @@ -1 +1 @@ -Subproject commit 65757638360d95f3d13fe51b33a7908b1b7314f8 +Subproject commit 714a3ab9ee14609d7cd94066b0cd025d724c85bf diff --git a/extensions/cocos/cocos-ecs/package-lock.json b/extensions/cocos/cocos-ecs/package-lock.json index 6cce4ab2..e775be23 100644 --- a/extensions/cocos/cocos-ecs/package-lock.json +++ b/extensions/cocos/cocos-ecs/package-lock.json @@ -6,15 +6,14 @@ "": { "name": "cocos-ecs", "dependencies": { - "@esengine/ai": "^2.0.7", + "@esengine/ai": "^2.0.10", "@esengine/ecs-framework": "^2.1.22" } }, "node_modules/@esengine/ai": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@esengine/ai/-/ai-2.0.7.tgz", - "integrity": "sha512-Otlgq/1Mn71o9rnRR87+SHmZGCNkFsbJMxhkBjumWQsb9ZD716RilXqRX9psYSMLcFLge9EEVeqExSOIq688sQ==", - "license": "MIT", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@esengine/ai/-/ai-2.0.10.tgz", + "integrity": "sha512-L0jWaYHDe8fw/XMpVniFqMIFDVzP9wib+HZKKq+NOXV3zWj+F3XpOgNrb7+4ZN5yR8rK9wjEh+PNkVdTkLOl8g==", "dependencies": { "@esengine/ecs-framework": "^2.1.20" }, diff --git a/extensions/cocos/cocos-ecs/package.json b/extensions/cocos/cocos-ecs/package.json index c980d38b..f1df228a 100644 --- a/extensions/cocos/cocos-ecs/package.json +++ b/extensions/cocos/cocos-ecs/package.json @@ -6,6 +6,6 @@ }, "dependencies": { "@esengine/ecs-framework": "^2.1.22", - "@esengine/ai": "^2.0.7" + "@esengine/ai": "^2.0.10" } } \ No newline at end of file diff --git a/thirdparty/BehaviourTree-ai b/thirdparty/BehaviourTree-ai index d4babd9a..a849240f 160000 --- a/thirdparty/BehaviourTree-ai +++ b/thirdparty/BehaviourTree-ai @@ -1 +1 @@ -Subproject commit d4babd9aa2cd2f0a65f2930716575db0113f406e +Subproject commit a849240fdd2227d10f7b4c1e8f392ce40724c604