Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/ecs/systems/AISystem.ts

317 lines
11 KiB
TypeScript
Raw Normal View History

import { EntitySystem, Entity, Matcher, Time } from '@esengine/ecs-framework';
import { AIComponent, Transform, Health } from '../components';
/**
* AI系统 - AI行为和状态机
*/
export class AISystem extends EntitySystem {
/** 系统处理的实体计数器 */
private processedEntityCount: number = 0;
/** 状态转换计数器 */
private stateTransitionCount: number = 0;
constructor() {
// 处理具有AI组件的实体
super(Matcher.empty().all(AIComponent));
}
/**
*
*/
protected process(entities: Entity[]): void {
const deltaTime = Time.deltaTime;
const currentTime = Time.totalTime;
this.processedEntityCount = entities.length;
for (const entity of entities) {
this.processEntity(entity, deltaTime, currentTime);
}
// 批量处理AI间的交互
this.processAIInteractions(entities);
}
/**
*
*/
private processEntity(entity: Entity, deltaTime: number, currentTime: number): void {
const ai = entity.getComponent(AIComponent);
const transform = entity.getComponent(Transform);
const health = entity.getComponent(Health);
if (!ai) return;
// 更新感知系统
ai.updatePerception(deltaTime);
// 处理状态机
this.updateStateMachine(ai, deltaTime);
// 更新行为树
this.updateBehaviorTree(ai, deltaTime);
// 处理AI能力如果有Transform和Health组件
if (transform && health) {
this.updateAICapabilities(ai, transform, health, deltaTime);
}
// 处理记忆衰减
this.updateMemory(ai, deltaTime);
}
/**
*
*/
private updateStateMachine(ai: AIComponent, deltaTime: number): void {
const currentStateName = ai.currentState;
const transitions = ai.stateMachine.transitions.get(currentStateName);
if (transitions) {
// 按优先级排序转换条件
const sortedTransitions = transitions.sort((a, b) => b.priority - a.priority);
for (const transition of sortedTransitions) {
if (transition.condition()) {
// 执行状态转换
const currentState = ai.stateMachine.states.get(currentStateName);
const newState = ai.stateMachine.states.get(transition.targetState);
if (currentState && newState) {
currentState.exit();
ai.currentState = transition.targetState as any;
newState.enter();
this.stateTransitionCount++;
break;
}
}
}
}
}
/**
*
*/
private updateBehaviorTree(ai: AIComponent, deltaTime: number): void {
const behaviorTree = ai.config.behaviorTree;
const blackboard = behaviorTree.blackboard;
// 更新黑板数据
blackboard.set('deltaTime', deltaTime);
blackboard.set('currentTime', Date.now());
// 模拟行为树执行
const executionResult = this.executeBehaviorNode(behaviorTree.rootNode, ai);
// 记录执行历史
behaviorTree.executionHistory.push({
nodeName: behaviorTree.rootNode.name,
startTime: Date.now(),
endTime: Date.now() + Math.random() * 10,
result: executionResult,
data: { deltaTime }
});
// 保持历史记录在合理范围内
if (behaviorTree.executionHistory.length > 50) {
behaviorTree.executionHistory.shift();
}
}
/**
*
*/
private executeBehaviorNode(node: any, ai: AIComponent): 'success' | 'failure' | 'running' {
// 简单的行为树执行模拟
switch (node.name) {
case 'root':
case 'selector':
// 选择器节点:尝试执行子节点直到一个成功
for (const child of node.children) {
const result = this.executeBehaviorNode(child, ai);
if (result === 'success' || result === 'running') {
return result;
}
}
return 'failure';
case 'sequence':
// 序列节点:按顺序执行所有子节点
for (const child of node.children) {
const result = this.executeBehaviorNode(child, ai);
if (result === 'failure' || result === 'running') {
return result;
}
}
return 'success';
case 'condition':
// 条件节点检查AI状态
return ai.config.personality.intelligence > 0.5 ? 'success' : 'failure';
case 'action':
// 动作节点执行AI行为
return Math.random() > 0.3 ? 'success' : 'running';
default:
return 'failure';
}
}
/**
* AI能力
*/
private updateAICapabilities(ai: AIComponent, transform: Transform, health: Health, deltaTime: number): void {
const capabilities = ai.config.capabilities;
// 根据健康状况调整能力
const healthRatio = health.currentHealth / health.maxHealth;
const effectiveSpeed = capabilities.movementSpeed * healthRatio;
// 更新移动速度
transform.speed = effectiveSpeed;
// 根据个性调整行为
if (ai.config.personality.aggression > 0.7 && healthRatio > 0.5) {
// 高攻击性且健康状况良好时更主动
ai.currentState = 'chase';
} else if (healthRatio < 0.3) {
// 生命值低时逃跑
ai.currentState = 'flee';
}
}
/**
*
*/
private updateMemory(ai: AIComponent, deltaTime: number): void {
const memory = ai.config.memory;
const currentTime = Date.now();
// 衰减已知位置的可信度
memory.knownLocations.forEach(location => {
const timeSinceVisit = currentTime - location.lastVisited;
const decayFactor = Math.exp(-timeSinceVisit / 30000); // 30秒衰减率
location.confidence *= decayFactor;
});
// 移除可信度过低的位置
memory.knownLocations = memory.knownLocations.filter(location => location.confidence > 0.1);
// 衰减关系信任度
memory.relationships.forEach(relation => {
const timeSinceInteraction = currentTime - relation.lastInteraction;
if (timeSinceInteraction > 60000) { // 60秒没有交互
relation.trustLevel *= 0.99; // 缓慢衰减
}
});
}
/**
* AI间的交互
*/
private processAIInteractions(entities: Entity[]): void {
const aiEntities = entities.filter(e => e.getComponent(AIComponent));
for (let i = 0; i < aiEntities.length; i++) {
for (let j = i + 1; j < aiEntities.length; j++) {
this.processAIPair(aiEntities[i], aiEntities[j]);
}
}
}
/**
* AI实体间的交互
*/
private processAIPair(entity1: Entity, entity2: Entity): void {
const ai1 = entity1.getComponent(AIComponent);
const ai2 = entity2.getComponent(AIComponent);
const transform1 = entity1.getComponent(Transform);
const transform2 = entity2.getComponent(Transform);
if (!ai1 || !ai2 || !transform1 || !transform2) return;
// 计算距离
const distance = Math.sqrt(
Math.pow(transform1.position.x - transform2.position.x, 2) +
Math.pow(transform1.position.y - transform2.position.y, 2)
);
// 视线范围内的交互
if (distance <= ai1.config.capabilities.sightRange) {
this.handleVisualContact(ai1, ai2, entity1, entity2, distance);
}
// 听力范围内的交互
if (distance <= ai1.config.capabilities.hearingRange) {
this.handleAudioContact(ai1, ai2, distance);
}
// 创建盟友关系(随机)
if (Math.random() < 0.001 && !ai1.allyIds.includes(entity2.id)) { // 0.1%概率每帧
ai1.addAlly(entity2.id);
}
}
/**
*
*/
private handleVisualContact(ai1: AIComponent, ai2: AIComponent, entity1: Entity, entity2: Entity, distance: number): void {
const currentTime = Date.now();
// 添加到可见实体列表
const existingEntry = ai1.perception.visibleEntities.find(e => e.entityId === entity2.id);
if (existingEntry) {
existingEntry.distance = distance;
existingEntry.lastSeen = currentTime;
existingEntry.componentId = ai2.id; // 使用组件ID避免循环引用
} else {
ai1.perception.visibleEntities.push({
entityId: entity2.id,
position: entity2.getComponent(Transform)!.position.clone(),
distance: distance,
angle: Math.atan2(
entity2.getComponent(Transform)!.position.y - entity1.getComponent(Transform)!.position.y,
entity2.getComponent(Transform)!.position.x - entity1.getComponent(Transform)!.position.x
),
lastSeen: currentTime,
componentId: ai2.id
});
}
}
/**
*
*/
private handleAudioContact(ai1: AIComponent, ai2: AIComponent, distance: number): void {
const soundVolume = 1.0 - (distance / ai1.config.capabilities.hearingRange);
ai1.perception.audibleSounds.push({
source: ai2.entity.getComponent(Transform)!.position.clone(),
volume: soundVolume,
type: 'movement',
timestamp: Date.now()
});
}
/**
*
*/
public initialize(): void {
super.initialize();
console.log('🤖 AI系统已启动');
}
/**
*
*/
public getSystemStats(): any {
return {
processedEntities: this.processedEntityCount,
stateTransitions: this.stateTransitionCount,
systemName: 'AISystem'
};
}
}