Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/AIComponent.ts
YHH bb19f752a1 优化性能结构/延迟加载
新增测试代码用于测试性能
2025-07-02 00:13:29 +08:00

328 lines
9.7 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 { Component } from '@esengine/ecs-framework';
import { Vec3 } from 'cc';
/**
* AI组件 - 复杂的AI行为和状态管理
*/
export class AIComponent extends Component {
/** AI状态 */
public currentState: 'idle' | 'patrol' | 'chase' | 'attack' | 'flee' | 'dead' = 'idle';
/** 目标ID避免循环引用 */
public targetId: number | null = null;
/** AI伙伴ID列表避免循环引用 */
public allyIds: number[] = [];
/** 敌人ID列表 */
public enemyIds: number[] = [];
/** 复杂的AI配置 */
public config: {
personality: {
aggression: number; // 攻击性 0-1
curiosity: number; // 好奇心 0-1
loyalty: number; // 忠诚度 0-1
intelligence: number; // 智力 0-1
};
capabilities: {
sightRange: number;
hearingRange: number;
movementSpeed: number;
attackDamage: number;
health: number;
};
behaviorTree: {
rootNode: BehaviorNode;
blackboard: Map<string, any>;
executionHistory: BehaviorExecution[];
};
memory: {
lastSeenEnemyPosition: Vec3 | null;
lastSeenEnemyTime: number;
knownLocations: Array<{
position: Vec3;
type: 'safe' | 'danger' | 'resource' | 'patrol';
confidence: number;
lastVisited: number;
}>;
relationships: Map<number, {
entityId: number;
relationship: 'ally' | 'enemy' | 'neutral';
trustLevel: number;
lastInteraction: number;
interactionHistory: Array<{
type: 'friendly' | 'hostile' | 'neutral';
timestamp: number;
impact: number;
}>;
}>;
};
};
/** 状态机 */
public stateMachine: {
states: Map<string, AIState>;
transitions: Map<string, Array<{
targetState: string;
condition: () => boolean;
priority: number;
}>>;
stateHistory: Array<{
state: string;
enterTime: number;
exitTime: number;
data: any;
}>;
};
/** 感知系统 */
public perception: {
visibleEntities: Array<{
entityId: number;
position: Vec3;
distance: number;
angle: number;
lastSeen: number;
componentId?: number; // 使用组件ID避免循环引用
}>;
audibleSounds: Array<{
source: Vec3;
volume: number;
type: string;
timestamp: number;
}>;
tacticleInfo: Array<{
entityId: number;
contactPoint: Vec3;
force: number;
timestamp: number;
}>;
};
constructor() {
super();
// 初始化AI配置
this.config = {
personality: {
aggression: Math.random(),
curiosity: Math.random(),
loyalty: Math.random(),
intelligence: Math.random()
},
capabilities: {
sightRange: 100 + Math.random() * 100,
hearingRange: 50 + Math.random() * 50,
movementSpeed: 80 + Math.random() * 40,
attackDamage: 10 + Math.random() * 20,
health: 80 + Math.random() * 40
},
behaviorTree: {
rootNode: new BehaviorNode('root'),
blackboard: new Map(),
executionHistory: []
},
memory: {
lastSeenEnemyPosition: null,
lastSeenEnemyTime: 0,
knownLocations: [],
relationships: new Map()
}
};
// 初始化状态机
this.stateMachine = {
states: new Map(),
transitions: new Map(),
stateHistory: []
};
// 初始化感知系统
this.perception = {
visibleEntities: [],
audibleSounds: [],
tacticleInfo: []
};
this.initializeStateMachine();
this.initializeBehaviorTree();
}
/**
* 初始化状态机
*/
private initializeStateMachine(): void {
// 添加基本状态
this.stateMachine.states.set('idle', new AIState('idle', this));
this.stateMachine.states.set('patrol', new AIState('patrol', this));
this.stateMachine.states.set('chase', new AIState('chase', this));
this.stateMachine.states.set('attack', new AIState('attack', this));
this.stateMachine.states.set('flee', new AIState('flee', this));
// 设置状态转换
this.stateMachine.transitions.set('idle', [
{ targetState: 'patrol', condition: () => Math.random() > 0.8, priority: 1 },
{ targetState: 'chase', condition: () => this.perception.visibleEntities.length > 0, priority: 3 }
]);
this.stateMachine.transitions.set('patrol', [
{ targetState: 'idle', condition: () => Math.random() > 0.9, priority: 1 },
{ targetState: 'chase', condition: () => this.hasVisibleEnemies(), priority: 3 }
]);
}
/**
* 初始化行为树
*/
private initializeBehaviorTree(): void {
const root = this.config.behaviorTree.rootNode;
// 构建简单的行为树结构
const selectorNode = new BehaviorNode('selector');
const sequenceNode = new BehaviorNode('sequence');
const conditionNode = new BehaviorNode('condition');
const actionNode = new BehaviorNode('action');
root.addChild(selectorNode);
selectorNode.addChild(sequenceNode);
sequenceNode.addChild(conditionNode);
sequenceNode.addChild(actionNode);
// 设置黑板数据
this.config.behaviorTree.blackboard.set('lastPatrolPoint', new Vec3());
this.config.behaviorTree.blackboard.set('alertLevel', 0);
this.config.behaviorTree.blackboard.set('energy', 100);
}
/**
* 添加盟友(避免循环引用)
*/
public addAlly(allyEntityId: number): void {
if (!this.allyIds.includes(allyEntityId)) {
this.allyIds.push(allyEntityId);
// 更新关系记录
this.config.memory.relationships.set(allyEntityId, {
entityId: allyEntityId,
relationship: 'ally',
trustLevel: 0.8,
lastInteraction: Date.now(),
interactionHistory: []
});
}
}
/**
* 设置目标(避免循环引用)
*/
public setTarget(targetEntityId: number): void {
this.targetId = targetEntityId;
// 不再需要双向引用
}
/**
* 更新感知信息
*/
public updatePerception(deltaTime: number): void {
// 清理过期的感知信息
const currentTime = Date.now();
this.perception.visibleEntities = this.perception.visibleEntities.filter(
entity => currentTime - entity.lastSeen < 5000
);
this.perception.audibleSounds = this.perception.audibleSounds.filter(
sound => currentTime - sound.timestamp < 2000
);
// 更新记忆中的位置信息
this.config.memory.knownLocations.forEach(location => {
location.confidence *= 0.999; // 随时间衰减可信度
});
}
/**
* 检查是否有可见敌人
*/
private hasVisibleEnemies(): boolean {
return this.perception.visibleEntities.some(entity =>
this.config.memory.relationships.get(entity.entityId)?.relationship === 'enemy'
);
}
/**
* 重置组件
*/
public reset(): void {
// 清理ID数组不再需要处理循环引用
this.allyIds = [];
this.enemyIds = [];
this.targetId = null;
this.currentState = 'idle';
this.config.behaviorTree.blackboard.clear();
this.config.memory.relationships.clear();
this.perception.visibleEntities = [];
this.perception.audibleSounds = [];
this.perception.tacticleInfo = [];
}
}
/**
* 行为树节点
*/
class BehaviorNode {
public name: string;
public children: BehaviorNode[] = [];
public parent: BehaviorNode | null = null;
public data: Map<string, any> = new Map();
constructor(name: string) {
this.name = name;
}
public addChild(child: BehaviorNode): void {
this.children.push(child);
child.parent = this;
}
}
/**
* 行为执行记录
*/
interface BehaviorExecution {
nodeName: string;
startTime: number;
endTime: number;
result: 'success' | 'failure' | 'running';
data: any;
}
/**
* AI状态
*/
class AIState {
public name: string;
public owner: AIComponent;
public enterTime: number = 0;
public data: Map<string, any> = new Map();
constructor(name: string, owner: AIComponent) {
this.name = name;
this.owner = owner;
}
public enter(): void {
this.enterTime = Date.now();
}
public exit(): void {
// 记录状态历史
this.owner.stateMachine.stateHistory.push({
state: this.name,
enterTime: this.enterTime,
exitTime: Date.now(),
data: Object.fromEntries(this.data)
});
}
}