Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/components/UnitController.ts
2025-06-24 19:34:37 +08:00

306 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}