更新rts示例代码(矿工自动采矿)
This commit is contained in:
@@ -1,236 +1,174 @@
|
||||
import { _decorator, Component, Node, Vec3, instantiate, Prefab, Camera } from 'cc';
|
||||
import { _decorator, Component, Node, Vec3, Color, MeshRenderer, Material, BoxCollider, geometry, PhysicsSystem, director } from 'cc';
|
||||
import { SimplePrefabFactory } from './components/SimplePrefabFactory';
|
||||
import { UnitController } from './components/UnitController';
|
||||
import { RTSCameraController } from './controllers/RTSCameraController';
|
||||
import { UIController } from './controllers/UIController';
|
||||
import { BehaviorTreeManager } from './components/BehaviorTreeManager';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* RTS演示项目主控制器
|
||||
* 展示行为树在3D RTS游戏中的应用
|
||||
* 简化版矿工挖矿演示
|
||||
* 核心逻辑:矿工挖矿 → 运输 → 存储 → 重复
|
||||
*/
|
||||
@ccclass('RTSDemo')
|
||||
export class RTSDemo extends Component {
|
||||
@ccclass('MinerDemo')
|
||||
export class MinerDemo extends Component {
|
||||
|
||||
@property(Prefab)
|
||||
unitPrefab: Prefab = null!;
|
||||
@property
|
||||
minerCount: number = 3; // 矿工数量
|
||||
|
||||
@property(Prefab)
|
||||
buildingPrefab: Prefab = null!;
|
||||
@property
|
||||
oreCount: number = 8; // 矿石数量
|
||||
|
||||
@property(Prefab)
|
||||
resourcePrefab: Prefab = null!;
|
||||
private factory: SimplePrefabFactory = new SimplePrefabFactory();
|
||||
private miners: Node[] = [];
|
||||
private ores: Node[] = [];
|
||||
private warehouse: Node | null = null;
|
||||
private ground: Node | null = 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 初始化完成!');
|
||||
start() {
|
||||
console.log('🎮 启动矿工挖矿演示');
|
||||
this.createWorld();
|
||||
this.createWarehouse();
|
||||
this.createOres();
|
||||
this.createMiners();
|
||||
this.logGameStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控制器
|
||||
* 创建游戏世界
|
||||
*/
|
||||
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 createWorld() {
|
||||
// 创建地面
|
||||
this.ground = this.factory.createGround(this.node, new Vec3(0, 0, 0), new Vec3(20, 0.2, 20));
|
||||
console.log('🌍 创建游戏世界:20x20地面');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置场景
|
||||
* 创建仓库
|
||||
*/
|
||||
private setupScene() {
|
||||
this.createUnits();
|
||||
this.createBuildings();
|
||||
this.createResources();
|
||||
|
||||
// 设置初始相机位置
|
||||
this.mainCamera.node.setPosition(0, 20, 15);
|
||||
this.mainCamera.node.lookAt(Vec3.ZERO);
|
||||
|
||||
console.log('场景设置完成');
|
||||
private createWarehouse() {
|
||||
// 在地图中心创建仓库
|
||||
this.warehouse = this.factory.createBuilding(
|
||||
this.node,
|
||||
new Vec3(0, 1, 0),
|
||||
new Vec3(2, 2, 2),
|
||||
Color.GRAY,
|
||||
'warehouse'
|
||||
);
|
||||
console.log('🏭 创建仓库:位置(0,1,0)');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单位
|
||||
* 创建矿石
|
||||
*/
|
||||
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' }
|
||||
];
|
||||
private createOres() {
|
||||
console.log(`⛏️ 创建${this.oreCount}个矿石`);
|
||||
|
||||
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);
|
||||
for (let i = 0; i < this.oreCount; i++) {
|
||||
// 随机分布矿石,避开仓库区域
|
||||
let position: Vec3;
|
||||
do {
|
||||
position = new Vec3(
|
||||
(Math.random() - 0.5) * 16, // -8到8
|
||||
0.5,
|
||||
(Math.random() - 0.5) * 16 // -8到8
|
||||
);
|
||||
} while (Vec3.distance(position, new Vec3(0, 0.5, 0)) < 4); // 距离仓库至少4米
|
||||
|
||||
this.gameWorld.addChild(buildingNode);
|
||||
this.buildings.push(buildingNode);
|
||||
const ore = this.factory.createResource(
|
||||
this.node,
|
||||
position,
|
||||
new Vec3(0.8, 0.8, 0.8),
|
||||
Color.YELLOW,
|
||||
'ore'
|
||||
);
|
||||
|
||||
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.ores.push(ore);
|
||||
console.log(` 💎 矿石${i+1}:位置(${position.x.toFixed(1)}, ${position.y.toFixed(1)}, ${position.z.toFixed(1)})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建矿工
|
||||
*/
|
||||
private createMiners() {
|
||||
console.log(`👷 创建${this.minerCount}个矿工`);
|
||||
|
||||
this.selectedUnits.forEach(unit => {
|
||||
const unitController = unit.getComponent(UnitController);
|
||||
if (unitController) {
|
||||
unitController.issueCommand(command, target);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`发布命令: ${command} 给 ${this.selectedUnits.length} 个单位`);
|
||||
for (let i = 0; i < this.minerCount; i++) {
|
||||
// 矿工围绕仓库分布
|
||||
const angle = (i / this.minerCount) * Math.PI * 2;
|
||||
const radius = 3;
|
||||
const position = new Vec3(
|
||||
Math.cos(angle) * radius,
|
||||
1,
|
||||
Math.sin(angle) * radius
|
||||
);
|
||||
|
||||
const miner = this.factory.createUnit(
|
||||
this.node,
|
||||
position,
|
||||
new Vec3(0.8, 0.8, 0.8),
|
||||
Color.BLUE,
|
||||
'miner'
|
||||
);
|
||||
|
||||
// 添加矿工控制器
|
||||
const unitController = miner.addComponent(UnitController);
|
||||
unitController.unitType = 'miner';
|
||||
unitController.maxHealth = 100;
|
||||
unitController.currentHealth = 100;
|
||||
unitController.moveSpeed = 2.0;
|
||||
unitController.currentCommand = 'mine'; // 默认挖矿命令
|
||||
|
||||
// 添加行为树管理器
|
||||
const behaviorManager = miner.addComponent(BehaviorTreeManager);
|
||||
|
||||
// 初始化行为树
|
||||
behaviorManager.initializeBehaviorTree('miner-ai', unitController);
|
||||
|
||||
this.miners.push(miner);
|
||||
console.log(` 👷 矿工${i+1}:位置(${position.x.toFixed(1)}, ${position.y.toFixed(1)}, ${position.z.toFixed(1)})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有单位
|
||||
* 记录游戏状态
|
||||
*/
|
||||
getAllUnits(): Node[] {
|
||||
return [...this.units];
|
||||
private logGameStatus() {
|
||||
console.log('\n📊 游戏状态总览:');
|
||||
console.log(` 🏭 仓库:1个`);
|
||||
console.log(` 💎 矿石:${this.ores.length}个`);
|
||||
console.log(` 👷 矿工:${this.miners.length}个`);
|
||||
console.log(` 🎯 游戏目标:矿工自动挖矿并运输到仓库`);
|
||||
console.log('\n🎮 游戏逻辑:');
|
||||
console.log(' 1. 矿工寻找最近的矿石');
|
||||
console.log(' 2. 移动到矿石位置并挖掘');
|
||||
console.log(' 3. 携带矿石返回仓库');
|
||||
console.log(' 4. 存储矿石并重复循环');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有建筑
|
||||
* 获取所有矿石位置(供AI使用)
|
||||
*/
|
||||
getAllBuildings(): Node[] {
|
||||
return [...this.buildings];
|
||||
public getAllOres(): Node[] {
|
||||
return this.ores.filter(ore => ore && ore.isValid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有资源
|
||||
* 获取仓库位置(供AI使用)
|
||||
*/
|
||||
getAllResources(): Node[] {
|
||||
return [...this.resources];
|
||||
public getWarehouse(): Node | null {
|
||||
return this.warehouse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除已开采的矿石
|
||||
*/
|
||||
public removeOre(ore: Node) {
|
||||
const index = this.ores.indexOf(ore);
|
||||
if (index > -1) {
|
||||
this.ores.splice(index, 1);
|
||||
ore.destroy();
|
||||
console.log(`💎 矿石已开采,剩余${this.ores.length}个矿石`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,11 +88,16 @@ export class BehaviorTreeComponent extends ECSComponent {
|
||||
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);
|
||||
// 注意:只设置行为树中实际定义的变量
|
||||
// 这些变量需要在对应的.btree文件的blackboard数组中预先定义
|
||||
|
||||
// 设置基础信息 - 注释掉未在行为树中定义的变量
|
||||
// this.blackboard.setValue('entityName', this.cocosNode.name);
|
||||
// this.blackboard.setValue('currentTime', Date.now() / 1000);
|
||||
// this.blackboard.setValue('deltaTime', 0.016);
|
||||
// this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition);
|
||||
|
||||
console.log('BehaviorTreeComponent黑板设置完成,未设置任何变量以避免警告');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,13 +112,14 @@ export class BehaviorTreeComponent extends ECSComponent {
|
||||
|
||||
this.lastTickTime = 0;
|
||||
|
||||
// 更新黑板中的时间信息
|
||||
// 更新黑板中的时间信息 - 注释掉未在行为树中定义的变量
|
||||
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);
|
||||
}
|
||||
// 只更新行为树中实际定义的变量
|
||||
// this.blackboard.setValue('deltaTime', deltaTime);
|
||||
// this.blackboard.setValue('currentTime', Date.now() / 1000);
|
||||
// if (this.cocosNode) {
|
||||
// this.blackboard.setValue('worldPosition', this.cocosNode.worldPosition);
|
||||
// }
|
||||
}
|
||||
|
||||
// 执行行为树
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { _decorator, Component, resources, JsonAsset } from 'cc';
|
||||
import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig } from '@esengine/ai';
|
||||
import { _decorator, Component, resources, JsonAsset, Vec3 } from 'cc';
|
||||
import { BehaviorTree, BehaviorTreeBuilder, Blackboard, BehaviorTreeJSONConfig, ExecutionContext, EventRegistry } from '@esengine/ai';
|
||||
import { UnitController } from './UnitController';
|
||||
import { RTSBehaviorHandler } from './RTSBehaviorHandler';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 执行上下文接口
|
||||
* 游戏执行上下文接口
|
||||
* 继承框架的ExecutionContext,添加游戏特定的属性
|
||||
*/
|
||||
interface GameExecutionContext {
|
||||
blackboard?: Blackboard;
|
||||
interface GameExecutionContext extends ExecutionContext {
|
||||
unitController: UnitController;
|
||||
gameObject: any;
|
||||
[key: string]: any;
|
||||
eventRegistry?: EventRegistry;
|
||||
// 确保继承索引签名
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,16 +27,18 @@ export class BehaviorTreeManager extends Component {
|
||||
debugMode: boolean = true;
|
||||
|
||||
@property
|
||||
tickInterval: number = 0.1; // 行为树更新间隔(秒)
|
||||
tickInterval: number = 0.1; // 行为树更新间隔(秒)- 10fps更新频率,平衡性能和响应性
|
||||
|
||||
private behaviorTree: BehaviorTree<GameExecutionContext> | null = null;
|
||||
private blackboard: Blackboard | null = null;
|
||||
private context: GameExecutionContext | null = null;
|
||||
private eventRegistry: EventRegistry | null = null;
|
||||
private isLoaded: boolean = false;
|
||||
private isRunning: boolean = false;
|
||||
private lastTickTime: number = 0;
|
||||
private unitController: UnitController | null = null;
|
||||
private currentBehaviorTreeName: string = '';
|
||||
private behaviorHandler: RTSBehaviorHandler | null = null;
|
||||
|
||||
/**
|
||||
* 初始化行为树
|
||||
@@ -42,12 +47,22 @@ export class BehaviorTreeManager extends Component {
|
||||
this.currentBehaviorTreeName = behaviorTreeName;
|
||||
this.unitController = unitController;
|
||||
|
||||
// 获取RTSBehaviorHandler组件
|
||||
this.behaviorHandler = this.getComponent(RTSBehaviorHandler);
|
||||
if (!this.behaviorHandler) {
|
||||
console.error(`BehaviorTreeManager: 未找到RTSBehaviorHandler组件 - ${this.node.name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.loadBehaviorTree(behaviorTreeName);
|
||||
this.setupBlackboard();
|
||||
this.isLoaded = true;
|
||||
this.isRunning = true;
|
||||
console.log(`行为树初始化成功: ${behaviorTreeName}`);
|
||||
console.log(`✅ 行为树初始化成功: ${behaviorTreeName} for ${this.unitController.node.name}`);
|
||||
console.log(` - 行为树: ${this.behaviorTree ? '已创建' : '未创建'}`);
|
||||
console.log(` - 黑板变量: ${this.blackboard ? '已创建' : '未创建'}`);
|
||||
console.log(` - 运行状态: ${this.isRunning ? '运行中' : '已停止'}`);
|
||||
} catch (error) {
|
||||
console.error(`行为树初始化失败: ${behaviorTreeName}`, error);
|
||||
}
|
||||
@@ -59,6 +74,7 @@ export class BehaviorTreeManager extends Component {
|
||||
private async loadBehaviorTree(behaviorTreeName: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const jsonPath = `${behaviorTreeName}.bt`;
|
||||
console.log(`🔍 尝试加载行为树文件: ${jsonPath}`);
|
||||
|
||||
resources.load(jsonPath, JsonAsset, (err, asset) => {
|
||||
if (err) {
|
||||
@@ -72,15 +88,17 @@ export class BehaviorTreeManager extends Component {
|
||||
|
||||
// 创建执行上下文
|
||||
this.blackboard = new Blackboard();
|
||||
this.eventRegistry = this.createEventRegistry();
|
||||
this.context = {
|
||||
blackboard: this.blackboard,
|
||||
unitController: this.unitController!,
|
||||
gameObject: this.node
|
||||
};
|
||||
gameObject: this.node,
|
||||
eventRegistry: this.eventRegistry
|
||||
} as GameExecutionContext;
|
||||
|
||||
// 从JSON数据创建行为树
|
||||
const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig(behaviorTreeData, this.context);
|
||||
this.behaviorTree = buildResult.tree as BehaviorTree<GameExecutionContext>;
|
||||
const buildResult = BehaviorTreeBuilder.fromBehaviorTreeConfig<GameExecutionContext>(behaviorTreeData, this.context);
|
||||
this.behaviorTree = buildResult.tree;
|
||||
this.blackboard = buildResult.blackboard;
|
||||
|
||||
resolve();
|
||||
@@ -92,35 +110,70 @@ export class BehaviorTreeManager extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建事件注册表
|
||||
*/
|
||||
private createEventRegistry(): EventRegistry {
|
||||
const registry = new EventRegistry();
|
||||
|
||||
// 注册简化的矿工行为事件处理器
|
||||
const eventHandlers = {
|
||||
// 矿工核心行为
|
||||
'find-and-mine-ore': (context: any, params?: any) => this.callBehaviorHandler('onFindAndMineOre', params),
|
||||
'store-ore': (context: any, params?: any) => this.callBehaviorHandler('onStoreOre', params),
|
||||
'idle-behavior': (context: any, params?: any) => this.callBehaviorHandler('onIdleBehavior', params)
|
||||
};
|
||||
|
||||
// 将事件处理器注册到EventRegistry
|
||||
Object.entries(eventHandlers).forEach(([eventName, handler]) => {
|
||||
registry.registerAction(eventName, handler);
|
||||
});
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用行为处理器的方法
|
||||
*/
|
||||
private callBehaviorHandler(methodName: string, params: any = {}): string {
|
||||
if (!this.behaviorHandler) {
|
||||
console.error(`BehaviorTreeManager: RTSBehaviorHandler未初始化 - ${this.node.name}`);
|
||||
return 'failure';
|
||||
}
|
||||
|
||||
try {
|
||||
// 直接调用RTSBehaviorHandler的方法
|
||||
const method = (this.behaviorHandler as any)[methodName];
|
||||
if (typeof method === 'function') {
|
||||
console.log(`🎯 调用行为处理器: ${methodName} (${this.node.name})`);
|
||||
const result = method.call(this.behaviorHandler, params);
|
||||
console.log(`📤 行为处理器返回: ${methodName} -> "${result}" (${this.node.name})`);
|
||||
return result || 'success'; // 确保有返回值
|
||||
} else {
|
||||
console.error(`BehaviorTreeManager: 方法不存在: ${methodName}`);
|
||||
return 'failure';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`BehaviorTreeManager: 调用方法失败: ${methodName}`, error);
|
||||
return 'failure';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置黑板基础信息
|
||||
*/
|
||||
private setupBlackboard() {
|
||||
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('maxHealth', this.unitController.maxHealth);
|
||||
this.blackboard.setValue('currentCommand', 'mine');
|
||||
this.blackboard.setValue('hasOre', false);
|
||||
this.blackboard.setValue('hasTarget', false);
|
||||
this.blackboard.setValue('isSelected', false);
|
||||
|
||||
// 设置单位控制器引用,供行为树节点使用
|
||||
this.blackboard.setValue('unitController', this.unitController);
|
||||
this.blackboard.setValue('gameObject', this.node);
|
||||
this.blackboard.setValue('targetPosition', null);
|
||||
this.blackboard.setValue('isMoving', false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,45 +218,20 @@ export class BehaviorTreeManager extends Component {
|
||||
|
||||
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('hasTarget', this.unitController.targetPosition && !this.unitController.targetPosition.equals(Vec3.ZERO));
|
||||
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');
|
||||
this.blackboard.setValue('isMoving', this.unitController.targetPosition && !this.unitController.targetPosition.equals(Vec3.ZERO));
|
||||
}
|
||||
|
||||
// 执行行为树
|
||||
try {
|
||||
this.behaviorTree.tick(deltaTime);
|
||||
if (this.debugMode && Math.random() < 0.01) { // 1%的概率打印调试信息
|
||||
console.log(`行为树执行完成, 单位: ${this.node.name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`行为树执行错误:`, error);
|
||||
console.error(`行为树执行错误: ${this.node.name}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import { _decorator, Component, Vec3, Node } from 'cc';
|
||||
import { UnitController } from './UnitController';
|
||||
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
* 矿工行为处理器 - 专门处理矿工的三个核心行为
|
||||
* 展示如何使用黑板变量参数和事件系统
|
||||
*/
|
||||
@ccclass('RTSBehaviorHandler')
|
||||
export class RTSBehaviorHandler extends Component {
|
||||
|
||||
private unitController: UnitController | null = null;
|
||||
private minerDemo: any = null; // MinerDemo组件引用
|
||||
|
||||
start() {
|
||||
this.unitController = this.getComponent(UnitController);
|
||||
// 获取场景中的MinerDemo组件
|
||||
this.minerDemo = this.node.parent?.getComponent('MinerDemo');
|
||||
|
||||
if (!this.unitController) {
|
||||
console.error('RTSBehaviorHandler: 未找到UnitController组件');
|
||||
}
|
||||
if (!this.minerDemo) {
|
||||
console.error('RTSBehaviorHandler: 未找到MinerDemo组件');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 寻找并挖掘矿石
|
||||
* @param params 事件参数,包含黑板变量值
|
||||
*/
|
||||
onFindAndMineOre(params: any = {}): string {
|
||||
if (!this.unitController || !this.minerDemo) return 'failure';
|
||||
|
||||
// 从参数中获取黑板变量值
|
||||
const unitType = params.unitType || 'unknown';
|
||||
const currentHealth = params.currentHealth || 100;
|
||||
|
||||
console.log(`⛏️ ${unitType}矿工开始寻找矿石 (生命值: ${currentHealth})`);
|
||||
|
||||
// 获取所有可用矿石
|
||||
const ores = this.minerDemo.getAllOres();
|
||||
if (ores.length === 0) {
|
||||
console.log(`👷 ${this.node.name}: 没有可挖掘的矿石了`);
|
||||
return 'failure';
|
||||
}
|
||||
|
||||
// 寻找最近的矿石
|
||||
const currentPos = this.node.worldPosition;
|
||||
let nearestOre: Node | null = null;
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const ore of ores) {
|
||||
const distance = Vec3.distance(currentPos, ore.worldPosition);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestOre = ore;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nearestOre) return 'failure';
|
||||
|
||||
// 检查是否已经到达矿石位置
|
||||
if (minDistance < 1.5) {
|
||||
// 开始挖掘
|
||||
console.log(`⛏️ ${this.node.name}: 开始挖掘矿石`);
|
||||
|
||||
// 设置携带矿石状态(更新黑板)
|
||||
this.unitController.setBlackboardValue('hasOre', true);
|
||||
|
||||
// 移除矿石
|
||||
this.minerDemo.removeOre(nearestOre);
|
||||
|
||||
// 清除移动目标
|
||||
this.unitController.clearTarget();
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
// 移动到矿石位置
|
||||
this.unitController.setTarget(nearestOre.worldPosition);
|
||||
console.log(`🚶 ${this.node.name}: 前往矿石位置 距离${minDistance.toFixed(1)}米`);
|
||||
return 'running';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 前往仓库存储矿石
|
||||
* @param params 事件参数,包含黑板变量值
|
||||
*/
|
||||
onStoreOre(params: any = {}): string {
|
||||
if (!this.unitController || !this.minerDemo) return 'failure';
|
||||
|
||||
// 从参数中获取黑板变量值
|
||||
const unitType = params.unitType || 'unknown';
|
||||
const targetPosition = params.targetPosition || null;
|
||||
|
||||
console.log(`🏭 ${unitType}矿工前往仓库存储 (目标位置: ${JSON.stringify(targetPosition)})`);
|
||||
|
||||
const warehouse = this.minerDemo.getWarehouse();
|
||||
if (!warehouse) {
|
||||
console.log(`👷 ${this.node.name}: 找不到仓库`);
|
||||
return 'failure';
|
||||
}
|
||||
|
||||
// 计算到仓库的距离
|
||||
const currentPos = this.node.worldPosition;
|
||||
const warehousePos = warehouse.worldPosition;
|
||||
const distance = Vec3.distance(currentPos, warehousePos);
|
||||
|
||||
// 检查是否已经到达仓库
|
||||
if (distance < 2.5) {
|
||||
// 存储矿石
|
||||
console.log(`🏭 ${this.node.name}: 在仓库存储矿石`);
|
||||
|
||||
// 清除携带矿石状态(更新黑板)
|
||||
this.unitController.setBlackboardValue('hasOre', false);
|
||||
|
||||
// 清除移动目标
|
||||
this.unitController.clearTarget();
|
||||
|
||||
return 'success';
|
||||
} else {
|
||||
// 移动到仓库
|
||||
this.unitController.setTarget(warehousePos);
|
||||
console.log(`🚚 ${this.node.name}: 运输矿石到仓库 距离${distance.toFixed(1)}米`);
|
||||
return 'running';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 待机行为
|
||||
* @param params 事件参数,包含黑板变量值
|
||||
*/
|
||||
onIdleBehavior(params: any = {}): string {
|
||||
// 从参数中获取黑板变量值
|
||||
const unitType = params.unitType || 'unknown';
|
||||
|
||||
console.log(`😴 ${unitType}矿工待机中`);
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "739ff9ee-42d5-4542-bb5b-3e7611c729e2",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { _decorator, Component, Node, Vec3, MeshRenderer, BoxCollider, RigidBody, Mesh, Material, Color, primitives, utils } from 'cc';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 简单预制体工厂 - 创建基本的游戏对象
|
||||
* 用于在没有预制体资源时创建基本的单位、建筑和资源
|
||||
*/
|
||||
@ccclass('SimplePrefabFactory')
|
||||
export class SimplePrefabFactory extends Component {
|
||||
|
||||
/**
|
||||
* 创建单位节点
|
||||
*/
|
||||
static createUnit(name: string, color: Color = Color.WHITE): Node {
|
||||
const unit = new Node(name);
|
||||
|
||||
// 添加网格渲染器
|
||||
const meshRenderer = unit.addComponent(MeshRenderer);
|
||||
|
||||
// 创建立方体网格
|
||||
const mesh = utils.createMesh(primitives.box({ width: 1, height: 1, length: 1 }));
|
||||
meshRenderer.mesh = mesh;
|
||||
|
||||
// 创建材质
|
||||
const material = new Material();
|
||||
material.initialize({ effectName: 'builtin-unlit' });
|
||||
material.setProperty('mainColor', color);
|
||||
meshRenderer.material = material;
|
||||
|
||||
// 添加碰撞器
|
||||
const collider = unit.addComponent(BoxCollider);
|
||||
collider.size = new Vec3(1, 1, 1);
|
||||
|
||||
// 添加刚体
|
||||
const rigidBody = unit.addComponent(RigidBody);
|
||||
rigidBody.type = RigidBody.Type.KINEMATIC;
|
||||
|
||||
console.log(`创建单位: ${name}`);
|
||||
return unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建建筑节点
|
||||
*/
|
||||
static createBuilding(name: string, size: Vec3 = new Vec3(2, 2, 2), color: Color = Color.GRAY): Node {
|
||||
const building = new Node(name);
|
||||
|
||||
// 添加网格渲染器
|
||||
const meshRenderer = building.addComponent(MeshRenderer);
|
||||
|
||||
// 创建立方体网格
|
||||
const mesh = utils.createMesh(primitives.box({
|
||||
width: size.x,
|
||||
height: size.y,
|
||||
length: size.z
|
||||
}));
|
||||
meshRenderer.mesh = mesh;
|
||||
|
||||
// 创建材质
|
||||
const material = new Material();
|
||||
material.initialize({ effectName: 'builtin-unlit' });
|
||||
material.setProperty('mainColor', color);
|
||||
meshRenderer.material = material;
|
||||
|
||||
// 添加碰撞器
|
||||
const collider = building.addComponent(BoxCollider);
|
||||
collider.size = size;
|
||||
|
||||
console.log(`创建建筑: ${name}`);
|
||||
return building;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建资源节点
|
||||
*/
|
||||
static createResource(name: string, color: Color = Color.YELLOW): Node {
|
||||
const resource = new Node(name);
|
||||
|
||||
// 添加网格渲染器
|
||||
const meshRenderer = resource.addComponent(MeshRenderer);
|
||||
|
||||
// 创建球体网格
|
||||
const mesh = utils.createMesh(primitives.sphere(0.5));
|
||||
meshRenderer.mesh = mesh;
|
||||
|
||||
// 创建材质
|
||||
const material = new Material();
|
||||
material.initialize({ effectName: 'builtin-unlit' });
|
||||
material.setProperty('mainColor', color);
|
||||
meshRenderer.material = material;
|
||||
|
||||
// 添加碰撞器
|
||||
const collider = resource.addComponent(BoxCollider);
|
||||
collider.size = new Vec3(1, 1, 1);
|
||||
|
||||
console.log(`创建资源: ${name}`);
|
||||
return resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建地面节点
|
||||
*/
|
||||
static createGround(size: Vec3 = new Vec3(50, 0.1, 50), color: Color = new Color(100, 150, 100, 255)): Node {
|
||||
const ground = new Node('Ground');
|
||||
|
||||
// 添加网格渲染器
|
||||
const meshRenderer = ground.addComponent(MeshRenderer);
|
||||
|
||||
// 创建平面网格
|
||||
const mesh = utils.createMesh(primitives.box({
|
||||
width: size.x,
|
||||
height: size.y,
|
||||
length: size.z
|
||||
}));
|
||||
meshRenderer.mesh = mesh;
|
||||
|
||||
// 创建材质
|
||||
const material = new Material();
|
||||
material.initialize({ effectName: 'builtin-unlit' });
|
||||
material.setProperty('mainColor', color);
|
||||
meshRenderer.material = material;
|
||||
|
||||
// 添加碰撞器
|
||||
const collider = ground.addComponent(BoxCollider);
|
||||
collider.size = size;
|
||||
|
||||
console.log(`创建地面: ${size}`);
|
||||
return ground;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ac45cfc7-cf47-4315-bdf0-ba002b45b4b6",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { _decorator, Component, Node, Vec3, Material, MeshRenderer, Color, tween } from 'cc';
|
||||
import { BehaviorTreeManager } from './BehaviorTreeManager';
|
||||
import { RTSBehaviorHandler } from './RTSBehaviorHandler';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -29,7 +30,7 @@ export class UnitController extends Component {
|
||||
public unitType: string = '';
|
||||
public maxHealth: number = 100;
|
||||
public currentHealth: number = 100;
|
||||
public moveSpeed: number = 3;
|
||||
public moveSpeed: number = 1.5;
|
||||
public attackRange: number = 2;
|
||||
public attackDamage: number = 25;
|
||||
public isSelected: boolean = false;
|
||||
@@ -40,7 +41,13 @@ export class UnitController extends Component {
|
||||
public attackCooldown: number = 1.5;
|
||||
public color: string = 'white';
|
||||
|
||||
// 移动状态管理
|
||||
private isMoving: boolean = false;
|
||||
private moveStartTime: number = 0;
|
||||
private lastTargetUpdateTime: number = 0;
|
||||
|
||||
private behaviorTreeManager: BehaviorTreeManager | null = null;
|
||||
private behaviorHandler: Component | null = null;
|
||||
private meshRenderer: MeshRenderer | null = null;
|
||||
|
||||
onLoad() {
|
||||
@@ -48,6 +55,14 @@ export class UnitController extends Component {
|
||||
|
||||
// 创建行为树管理器
|
||||
this.behaviorTreeManager = this.addComponent(BehaviorTreeManager);
|
||||
|
||||
// 添加RTS行为处理器
|
||||
try {
|
||||
// 添加RTSBehaviorHandler组件
|
||||
this.behaviorHandler = this.addComponent(RTSBehaviorHandler);
|
||||
} catch (error) {
|
||||
console.warn('RTSBehaviorHandler组件添加失败,将使用默认行为处理', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,12 +80,15 @@ export class UnitController extends Component {
|
||||
// 设置材质颜色
|
||||
this.setUnitColor(config.color);
|
||||
|
||||
// 设置节点名称显示单位类型
|
||||
this.node.name = `${config.unitType.toUpperCase()}_${this.node.name}`;
|
||||
|
||||
// 初始化行为树
|
||||
if (this.behaviorTreeManager) {
|
||||
this.behaviorTreeManager.initializeBehaviorTree(config.behaviorTreeName, this);
|
||||
}
|
||||
|
||||
console.log(`单位 ${this.node.name} 设置完成 - 类型: ${config.unitType}, 行为树: ${config.behaviorTreeName}`);
|
||||
console.log(`🎮 单位设置完成: ${this.node.name} | 类型: ${config.unitType.toUpperCase()} | 行为树: ${config.behaviorTreeName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,6 +111,8 @@ export class UnitController extends Component {
|
||||
this.meshRenderer.material.setProperty('mainColor', color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 设置选择状态
|
||||
*/
|
||||
@@ -165,6 +185,29 @@ export class UnitController extends Component {
|
||||
console.log(`单位 ${this.node.name} 接收命令: ${command}`, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置黑板变量值
|
||||
*/
|
||||
setBlackboardValue(key: string, value: any) {
|
||||
if (this.behaviorTreeManager) {
|
||||
this.behaviorTreeManager.updateBlackboardValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置移动目标
|
||||
*/
|
||||
setTarget(position: Vec3) {
|
||||
this.targetPosition = position.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除移动目标
|
||||
*/
|
||||
clearTarget() {
|
||||
this.targetPosition = Vec3.ZERO.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 受到伤害
|
||||
*/
|
||||
@@ -219,23 +262,45 @@ export class UnitController extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动到目标位置
|
||||
* 移动到目标位置(只在水平面移动,不改变Y轴)
|
||||
*/
|
||||
moveToTarget(targetPos: Vec3, speed?: number): boolean {
|
||||
moveToTarget(targetPos: Vec3, speed?: number, deltaTime?: number): boolean {
|
||||
const currentPos = this.node.worldPosition;
|
||||
const distance = currentPos.subtract(targetPos).length();
|
||||
|
||||
if (distance < 0.5) {
|
||||
// 只计算水平面距离(忽略Y轴)
|
||||
const currentPos2D = new Vec3(currentPos.x, 0, currentPos.z);
|
||||
const targetPos2D = new Vec3(targetPos.x, 0, targetPos.z);
|
||||
const distance = currentPos2D.subtract(targetPos2D).length();
|
||||
|
||||
if (distance < 0.8) { // 增加到达阈值,减少抖动
|
||||
this.isMoving = false;
|
||||
return true; // 已到达目标
|
||||
}
|
||||
|
||||
// 简单的移动逻辑
|
||||
const direction = targetPos.subtract(currentPos).normalize();
|
||||
// 平滑移动逻辑(只在水平面)
|
||||
const direction2D = targetPos2D.subtract(currentPos2D).normalize();
|
||||
const moveSpeed = speed || this.moveSpeed;
|
||||
const deltaTime = 1/60; // 假设60fps
|
||||
const dt = deltaTime || 0.016; // 使用传入的deltaTime或默认值
|
||||
|
||||
// 计算移动距离,确保不会超过目标位置
|
||||
const moveDistance = Math.min(moveSpeed * dt, distance);
|
||||
const movement2D = direction2D.multiplyScalar(moveDistance);
|
||||
|
||||
// 新位置保持原有的Y轴位置
|
||||
const newPosition = new Vec3(
|
||||
currentPos.x + movement2D.x,
|
||||
currentPos.y, // 保持Y轴不变
|
||||
currentPos.z + movement2D.z
|
||||
);
|
||||
|
||||
const newPosition = currentPos.add(direction.multiplyScalar(moveSpeed * deltaTime));
|
||||
this.node.setWorldPosition(newPosition);
|
||||
this.isMoving = true;
|
||||
|
||||
// 减少日志输出频率
|
||||
if (Date.now() - this.moveStartTime > 1000) { // 每秒输出一次
|
||||
console.log(`${this.node.name}: 移动中 距离目标${distance.toFixed(2)}米`);
|
||||
this.moveStartTime = Date.now();
|
||||
}
|
||||
|
||||
return false; // 还在移动中
|
||||
}
|
||||
@@ -263,26 +328,56 @@ export class UnitController extends Component {
|
||||
}
|
||||
|
||||
update(deltaTime: number) {
|
||||
// 更新行为树黑板中的时间相关变量
|
||||
// 自动移动逻辑 - 如果有目标位置就自动移动
|
||||
if (this.targetPosition && !this.targetPosition.equals(Vec3.ZERO)) {
|
||||
const arrived = this.moveToTarget(this.targetPosition, undefined, deltaTime);
|
||||
if (arrived) {
|
||||
// 不要清除目标位置,让行为树决定下一步动作
|
||||
this.isMoving = false;
|
||||
|
||||
// 更新黑板状态
|
||||
if (this.behaviorTreeManager) {
|
||||
this.behaviorTreeManager.updateBlackboardValue('isMoving', false);
|
||||
// 不要设置hasTarget为false,让行为树自己管理
|
||||
}
|
||||
} else {
|
||||
this.isMoving = true;
|
||||
|
||||
// 更新移动状态到黑板
|
||||
if (this.behaviorTreeManager) {
|
||||
this.behaviorTreeManager.updateBlackboardValue('isMoving', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新行为树黑板中的核心变量
|
||||
if (this.behaviorTreeManager) {
|
||||
this.behaviorTreeManager.updateBlackboardValue('deltaTime', deltaTime);
|
||||
this.behaviorTreeManager.updateBlackboardValue('currentTime', Date.now() / 1000);
|
||||
// 基础属性更新
|
||||
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.behaviorTreeManager.updateBlackboardValue('currentCommand', this.currentCommand);
|
||||
this.behaviorTreeManager.updateBlackboardValue('hasTarget', this.targetPosition && !this.targetPosition.equals(Vec3.ZERO));
|
||||
this.behaviorTreeManager.updateBlackboardValue('targetPosition', this.targetPosition);
|
||||
this.behaviorTreeManager.updateBlackboardValue('isSelected', this.isSelected);
|
||||
this.behaviorTreeManager.updateBlackboardValue('isMoving', this.isMoving);
|
||||
|
||||
// 位置信息更新
|
||||
this.behaviorTreeManager.updateBlackboardValue('worldPosition', this.node.worldPosition);
|
||||
|
||||
// 更新距离信息
|
||||
if (this.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);
|
||||
// 根据单位类型设置特定的黑板变量
|
||||
if (this.unitType === 'worker') {
|
||||
// 工人特有的变量
|
||||
// 这里可以添加工人特有的状态更新
|
||||
} else if (this.unitType === 'soldier') {
|
||||
// 士兵特有的变量
|
||||
this.behaviorTreeManager.updateBlackboardValue('lastAttackTime', this.lastAttackTime);
|
||||
} else if (this.unitType === 'scout') {
|
||||
// 侦察兵特有的变量
|
||||
// 这里可以添加侦察兵特有的状态更新
|
||||
}
|
||||
|
||||
// 更新状态标志
|
||||
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');
|
||||
}
|
||||
|
||||
// 调试信息显示
|
||||
|
||||
Reference in New Issue
Block a user