This commit is contained in:
YHH
2025-06-24 19:34:37 +08:00
parent 68a615bc7b
commit 0f18a1979e
62 changed files with 10606 additions and 2113 deletions

View File

@@ -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<any> | 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<void> {
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();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "8efd182b-9891-4903-bef2-eb07b5184263",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -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<GameExecutionContext> | 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<void> {
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<GameExecutionContext>;
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<GameExecutionContext> | 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;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "891c88fc-282d-4791-a961-8d85244bfee7",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -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<any, any> = new Map();
constructor(name: string) {
this.name = name;
}
addComponent(component: any) {
this.components.set(component.constructor, component);
component.entity = this;
}
getComponent<T>(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();
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "61885e67-b7a2-4e51-857e-ccbea4fdea03",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "4ac64480-2d09-4de6-a22c-add022790676",
"files": [],
"subMetas": {},
"userData": {}
}