EG/plugins/user/swarm_intelligence/swarm_manager.py
2025-12-12 16:16:15 +08:00

732 lines
28 KiB
Python
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.

"""
群体管理器
负责创建和管理群体成员
"""
from panda3d.core import Vec3, Point3, LVector3f
import random
import math
import time
class SwarmManager:
"""
群体管理器
负责创建和管理群体成员,实现完整的群体智能行为
"""
def __init__(self, world):
self.world = world
self.members = []
self.obstacles = []
self.predators = []
self.paused = False
self.task = None
self.swarm_type = "鸟类"
self.target = None
self.path = []
self.bounds = {
'min_x': -50, 'max_x': 50,
'min_y': -50, 'max_y': 50,
'min_z': 0, 'max_z': 30
}
# 多群体支持
self.swarms = [] # 存储多个群体
self.swarm_id_counter = 0
# 性能统计
self.frame_count = 0
self.last_update_time = time.time()
self.fps = 0
# 群体参数
self.cohesion_weight = 1.0
self.separation_weight = 1.5
self.alignment_weight = 1.0
self.max_speed = 5.0
self.perception_radius = 10.0
self.member_count = 20
# 初始化高级Boids算法
from .advanced_boids import AdvancedBoidsAlgorithm
from .config import Config
from .interaction_manager import InteractionManager
from .learning_manager import LearningManager
from .environment_manager import EnvironmentManager
self.config = Config()
self.boids_algorithm = AdvancedBoidsAlgorithm(self.config)
self.interaction_manager = InteractionManager(self.config)
self.learning_manager = LearningManager(self.config)
self.environment_manager = EnvironmentManager(self.config)
# 启动更新任务
self.task = self.world.taskMgr.add(self._update_task, "swarm_update_task")
def create_example_swarm(self, swarm_type=None, member_count=None, position_offset=Vec3(0, 0, 0)):
"""
创建示例群体
根据群体类型创建不同类型的群体成员
"""
# 如果是创建新的独立群体,不清理现有群体
if swarm_type is None and member_count is None:
# 清理现有群体
self.cleanup()
# 获取群体类型和数量
swarm_type = swarm_type or self.swarm_type
count = member_count or self.config.get("member_count", self.member_count)
# 创建指定数量的群体成员
new_members = []
for i in range(count):
# 根据群体类型设置随机位置范围,并应用位置偏移
if swarm_type == "鸟类":
pos = Vec3(
random.uniform(-20, 20),
random.uniform(-20, 20),
random.uniform(5, 25)
) + position_offset
elif swarm_type == "鱼类":
pos = Vec3(
random.uniform(-15, 15),
random.uniform(-15, 15),
random.uniform(2, 15)
) + position_offset
elif swarm_type == "昆虫":
pos = Vec3(
random.uniform(-10, 10),
random.uniform(-10, 10),
random.uniform(1, 10)
) + position_offset
else: # 自定义
pos = Vec3(
random.uniform(self.bounds['min_x'], self.bounds['max_x']),
random.uniform(self.bounds['min_y'], self.bounds['min_y']),
random.uniform(self.bounds['min_z'], self.bounds['max_z'])
) + position_offset
# 根据群体类型加载不同的模型
if swarm_type == "鸟类":
member_model = "models/misc/sphere" # 实际应用中应使用鸟类模型
scale = 0.5
elif swarm_type == "鱼类":
member_model = "models/misc/sphere" # 实际应用中应使用鱼类模型
scale = 0.3
elif swarm_type == "昆虫":
member_model = "models/misc/sphere" # 实际应用中应使用昆虫模型
scale = 0.2
else:
member_model = "models/misc/sphere"
scale = 0.5
# 加载模型
try:
member_node = self.world.loader.loadModel(member_model)
except:
# 如果模型加载失败,使用默认球体
member_node = self.world.loader.loadModel("models/misc/sphere")
member_node.reparentTo(self.world.render)
member_node.setPos(pos)
member_node.setScale(scale)
# 随机初始速度
velocity = Vec3(
random.uniform(-1, 1),
random.uniform(-1, 1),
random.uniform(-1, 1)
)
# 添加到群体成员列表
member = {
'node': member_node,
'position': pos,
'velocity': velocity,
'index': i, # 成员索引,用于队形计算
'type': swarm_type, # 成员类型
'swarm_id': self.swarm_id_counter # 群体ID
}
new_members.append(member)
# 为成员添加环境传感器
if hasattr(self, 'environment_manager'):
self.environment_manager.add_sensor(id(member))
# 如果是创建新的独立群体
if swarm_type is not None or member_count is not None:
# 创建新的群体对象
swarm = {
'id': self.swarm_id_counter,
'type': swarm_type,
'members': new_members,
'position_offset': position_offset
}
self.swarms.append(swarm)
self.swarm_id_counter += 1
# 将新成员添加到主成员列表
self.members.extend(new_members)
print(f"已创建包含{len(new_members)}个成员的{swarm_type}群体 (ID: {swarm['id']})")
return swarm
else:
# 更新主成员列表
self.members = new_members
print(f"已创建包含{len(self.members)}个成员的{swarm_type}群体")
def create_multiple_swarms(self, swarm_configs: List[Dict]):
"""
创建多个群体
:param swarm_configs: 群体配置列表每个配置包含type, count, position_offset
"""
self.cleanup() # 清理现有群体
self.swarms.clear() # 清理群体列表
self.swarm_id_counter = 0 # 重置ID计数器
for config in swarm_configs:
swarm_type = config.get('type', '鸟类')
member_count = config.get('count', 20)
position_offset = config.get('position_offset', Vec3(0, 0, 0))
self.create_example_swarm(swarm_type, member_count, position_offset)
print(f"已创建{len(self.swarms)}个群体")
def get_swarm_by_id(self, swarm_id: int):
"""
根据ID获取群体
"""
for swarm in self.swarms:
if swarm['id'] == swarm_id:
return swarm
return None
def get_swarm_by_type(self, swarm_type: str):
"""
根据类型获取群体
"""
return [swarm for swarm in self.swarms if swarm['type'] == swarm_type]
def create_obstacle(self, position, radius):
"""
创建障碍物
"""
obstacle = {
'position': position,
'radius': radius
}
self.obstacles.append(obstacle)
return obstacle
def create_predator(self, position):
"""
创建捕食者
"""
# 创建捕食者模型
try:
predator_node = self.world.loader.loadModel("models/misc/sphere") # 实际应用中应使用捕食者模型
except:
predator_node = self.world.loader.loadModel("models/misc/sphere")
predator_node.reparentTo(self.world.render)
predator_node.setPos(position)
predator_node.setScale(1.0)
predator_node.setColor(1, 0, 0, 1) # 红色表示捕食者
# 创建捕食者对象
predator = {
'node': predator_node,
'position': position,
'velocity': Vec3(0, 0, 0),
'target_index': 0 # 目标群体成员索引
}
self.predators.append(predator)
return predator
def set_target(self, target):
"""
设置群体目标位置
"""
self.target = target
def set_path(self, path):
"""
设置群体移动路径
"""
self.path = path
def _update_task(self, task):
"""
更新任务
"""
if not self.paused:
self._update_swarm()
# 更新性能统计
self.frame_count += 1
current_time = time.time()
if current_time - self.last_update_time >= 1.0:
self.fps = self.frame_count
self.frame_count = 0
self.last_update_time = current_time
return task.cont
def _update_swarm(self):
"""
更新群体行为
"""
# 更新捕食者行为(如果存在)
self._update_predators()
# 更新群体间交互
interaction_forces = {}
if hasattr(self, 'interaction_manager'):
# 为每个成员计算交互力
for member in self.members:
interaction_forces[id(member)] = {}
# 应用合作力
if 'cooperative_force' in member:
interaction_forces[id(member)]['cooperative_force'] = member['cooperative_force']
del member['cooperative_force']
# 应用竞争力
if 'competition_force' in member:
interaction_forces[id(member)]['competition_force'] = member['competition_force']
del member['competition_force']
# 应用捕食力
if 'predation_force' in member:
interaction_forces[id(member)]['predation_force'] = member['predation_force']
del member['predation_force']
# 应用逃避力
if 'escape_force' in member:
interaction_forces[id(member)]['escape_force'] = member['escape_force']
del member['escape_force']
# 更新环境状态
if hasattr(self, 'environment_manager'):
self.environment_manager.update_environment_state(
self.obstacles, self.swarms, self.predators,
getattr(self, 'resources', []), getattr(self, 'hazards', [])
)
# 更新学习和适应
if hasattr(self, 'learning_manager') and self.config.get("learning_enabled", False):
# 计算环境状态
environment_state = self._calculate_environment_state()
# 更新环境模型
self.learning_manager.update_environment_model(environment_state)
# 适应环境
self.learning_manager.adapt_to_environment(environment_state)
# 获取适应后的参数
adapted_params = self.learning_manager.get_adapted_parameters()
# 更新Boids算法参数
self._update_boids_parameters(adapted_params)
# 检查是否启用并行计算
if self.config.get("parallel_computation", False) and len(self.members) > 50:
# 使用并行计算更新群体成员
self._update_swarm_parallel()
else:
# 使用串行计算更新群体成员
for i, member in enumerate(self.members):
# 计算邻居
neighbors = self._find_neighbors(member, i)
# 获取扩展参数
obstacles = self.obstacles if self.config.get("obstacle_avoidance_enabled", True) else []
bounds = self.bounds if self.config.get("boundary_enabled", True) else None
predators = self.predators if self.config.get("predator_avoid_enabled", False) else []
target = self.target if self.config.get("seek_enabled", False) else None
path = self.path if self.config.get("path_following_enabled", False) else None
interactions = interaction_forces.get(id(member), {}) if interaction_forces else {}
# 计算奖励(如果启用学习)
if hasattr(self, 'learning_manager') and self.config.get("learning_enabled", False):
reward = self.learning_manager.calculate_reward(member, neighbors, obstacles, environment_state)
# 创建状态表示
state = {
'neighbor_count': len(neighbors),
'obstacle_distance': self._calculate_min_obstacle_distance(member),
'boundary_distance': self._calculate_boundary_distance(member),
'velocity': member['velocity'].length(),
'position_x': member['position'].x,
'position_y': member['position'].y,
'position_z': member['position'].z
}
# 添加经验(简化)
# 在实际应用中,这里需要更复杂的动作表示
action = "maintain" # 简化动作
next_state = state.copy() # 简化下一状态
self.learning_manager.add_experience(state, action, reward, next_state)
# 获取环境响应力
environment_force = Vec3(0, 0, 0)
if (hasattr(self, 'environment_manager') and
self.config.get("environment_awareness_enabled", True)):
environment_force = self.environment_manager.get_environmental_response(
member, member['position'], member['velocity']
)
# 使用Boids算法更新成员状态添加环境响应力
self.boids_algorithm.update_member(
member, neighbors, obstacles, target, bounds, path, predators, interactions
)
# 应用环境响应力
if self.config.get("environment_awareness_enabled", True):
member['velocity'] += environment_force * 0.1 # 环境力权重
# 更新成员节点位置
member['node'].setPos(member['position'])
# 更新成员朝向(面向移动方向)
if member['velocity'].length() > 0:
# 创建一个向前的向量
forward = member['velocity'].normalized()
# 设置节点朝向
member['node'].lookAt(member['position'] + forward)
# 更新行为策略(定期更新)
if hasattr(self, 'learning_manager') and self.config.get("learning_enabled", False):
if self.frame_count % 60 == 0: # 每秒更新一次假设60FPS
self.learning_manager.update_behavior_policies()
def _update_swarm_parallel(self):
"""
使用并行计算更新群体行为
"""
# 获取扩展参数
obstacles = self.obstacles if self.config.get("obstacle_avoidance_enabled", True) else []
bounds = self.bounds if self.config.get("boundary_enabled", True) else None
predators = self.predators if self.config.get("predator_avoid_enabled", False) else []
target = self.target if self.config.get("seek_enabled", False) else None
path = self.path if self.config.get("path_following_enabled", False) else None
# 准备交互力
interaction_forces = {}
if hasattr(self, 'interaction_manager'):
# 为每个成员计算交互力
for member in self.members:
interaction_forces[id(member)] = {}
# 应用合作力
if 'cooperative_force' in member:
interaction_forces[id(member)]['cooperative_force'] = member['cooperative_force']
del member['cooperative_force']
# 应用竞争力
if 'competition_force' in member:
interaction_forces[id(member)]['competition_force'] = member['competition_force']
del member['competition_force']
# 应用捕食力
if 'predation_force' in member:
interaction_forces[id(member)]['predation_force'] = member['predation_force']
del member['predation_force']
# 应用逃避力
if 'escape_force' in member:
interaction_forces[id(member)]['escape_force'] = member['escape_force']
del member['escape_force']
# 准备环境力参数
environment_forces = {}
if (hasattr(self, 'environment_manager') and
self.config.get("environment_awareness_enabled", True)):
for member in self.members:
environment_forces[id(member)] = self.environment_manager.get_environmental_response(
member, member['position'], member['velocity']
)
else:
# 如果环境感知被禁用,设置为零力
for member in self.members:
environment_forces[id(member)] = Vec3(0, 0, 0)
# 使用并行算法更新群体成员
self.boids_algorithm.update_swarm_parallel(
self.members, self.members, obstacles, target, bounds, path, predators, interaction_forces, environment_forces
)
# 更新所有成员的节点位置和朝向
for member in self.members:
member['node'].setPos(member['position'])
# 更新成员朝向(面向移动方向)
if member['velocity'].length() > 0:
# 创建一个向前的向量
forward = member['velocity'].normalized()
# 设置节点朝向
member['node'].lookAt(member['position'] + forward)
def _update_predators(self):
"""
更新捕食者行为
"""
for predator in self.predators:
if self.members:
# 简单的捕食者行为:寻找最近的群体成员
nearest_member = None
nearest_distance = float('inf')
for member in self.members:
distance = (predator['position'] - member['position']).length()
if distance < nearest_distance:
nearest_distance = distance
nearest_member = member
if nearest_member:
# 向最近的成员移动
direction = (nearest_member['position'] - predator['position']).normalized()
predator['velocity'] = direction * 3.0 # 捕食者速度
predator['position'] += predator['velocity']
predator['node'].setPos(predator['position'])
def _calculate_environment_state(self):
"""
计算环境状态
:return: 环境状态字典
"""
if not self.members:
return {}
# 计算群体密度
member_count = len(self.members)
total_area = (self.bounds['max_x'] - self.bounds['min_x']) * (self.bounds['max_y'] - self.bounds['min_y'])
density = member_count / total_area if total_area > 0 else 0
# 计算平均速度
total_speed = sum(member['velocity'].length() for member in self.members)
avg_speed = total_speed / member_count if member_count > 0 else 0
# 计算与障碍物的平均距离
total_obstacle_distance = 0
obstacle_count = 0
for member in self.members:
min_distance = float('inf')
for obstacle in self.obstacles:
distance = (member['position'] - obstacle['position']).length() - obstacle.get('radius', 1.0)
min_distance = min(min_distance, distance)
if min_distance != float('inf'):
total_obstacle_distance += min_distance
obstacle_count += 1
avg_obstacle_distance = total_obstacle_distance / obstacle_count if obstacle_count > 0 else 10.0
# 威胁水平(基于与障碍物的距离)
threat_level = max(0.0, min(1.0, 1.0 - avg_obstacle_distance / 20.0))
# 资源丰富度(简化为群体密度的反比)
resource_abundance = max(0.0, min(1.0, 1.0 - density * 10.0))
return {
'density': density,
'avg_speed': avg_speed,
'avg_obstacle_distance': avg_obstacle_distance,
'threat_level': threat_level,
'resource_abundance': resource_abundance,
'member_count': member_count
}
def _calculate_min_obstacle_distance(self, member):
"""
计算成员与最近障碍物的距离
:param member: 群体成员
:return: 最小距离
"""
if not self.obstacles:
return float('inf')
min_distance = float('inf')
for obstacle in self.obstacles:
distance = (member['position'] - obstacle['position']).length() - obstacle.get('radius', 1.0)
min_distance = min(min_distance, distance)
return min_distance
def _calculate_boundary_distance(self, member):
"""
计算成员与边界的距离
:param member: 群体成员
:return: 最小边界距离
"""
min_distance = float('inf')
# 计算到各边界的距离
distances = [
member['position'].x - self.bounds['min_x'],
self.bounds['max_x'] - member['position'].x,
member['position'].y - self.bounds['min_y'],
self.bounds['max_y'] - member['position'].y,
member['position'].z - self.bounds['min_z'],
self.bounds['max_z'] - member['position'].z
]
return min(distances) if distances else float('inf')
def _update_boids_parameters(self, adapted_params):
"""
更新Boids算法参数
:param adapted_params: 适应后的参数
"""
# 更新速度
current_max_speed = self.config.get("max_speed", 5.0)
self.config.set("max_speed", current_max_speed * adapted_params['speed'])
# 更新行为权重
current_cohesion = self.config.get("cohesion_weight", 1.0)
self.config.set("cohesion_weight", current_cohesion * adapted_params['cohesion'])
current_separation = self.config.get("separation_weight", 1.5)
self.config.set("separation_weight", current_separation * adapted_params['separation'])
current_alignment = self.config.get("alignment_weight", 1.0)
self.config.set("alignment_weight", current_alignment * adapted_params['alignment'])
def _find_neighbors(self, member, index):
"""
查找邻居
使用空间分区优化邻居查找(简化实现)
"""
neighbors = []
perception_radius = self.config.get("perception_radius", self.perception_radius)
for i, other in enumerate(self.members):
if i != index: # 排除自己
distance = (member['position'] - other['position']).length()
if distance < perception_radius:
neighbors.append(other)
return neighbors
def add_member(self):
"""
添加一个新的群体成员
"""
# 随机位置(靠近现有群体)
if self.members:
# 在现有群体附近创建新成员
existing_member = random.choice(self.members)
pos = Vec3(
existing_member['position'].x + random.uniform(-5, 5),
existing_member['position'].y + random.uniform(-5, 5),
existing_member['position'].z + random.uniform(-2, 2)
)
else:
# 如果没有现有成员,在随机位置创建
pos = Vec3(
random.uniform(-20, 20),
random.uniform(-20, 20),
random.uniform(5, 15)
)
# 加载模型
try:
member_node = self.world.loader.loadModel("models/misc/sphere")
except:
member_node = self.world.loader.loadModel("models/misc/sphere")
member_node.reparentTo(self.world.render)
member_node.setPos(pos)
member_node.setScale(0.5)
# 随机初始速度
velocity = Vec3(
random.uniform(-1, 1),
random.uniform(-1, 1),
random.uniform(-1, 1)
)
# 添加到群体成员列表
member = {
'node': member_node,
'position': pos,
'velocity': velocity,
'index': len(self.members), # 成员索引
'type': self.swarm_type
}
self.members.append(member)
self.config.set("member_count", len(self.members))
return member
def remove_member(self):
"""
移除一个群体成员
"""
if self.members:
# 移除随机成员
member = self.members.pop()
member['node'].removeNode()
self.config.set("member_count", len(self.members))
return member
return None
def update_swarm_type(self, swarm_type):
"""
更新群体类型
"""
self.swarm_type = swarm_type
# 重新创建群体以应用新的类型
self.cleanup()
self.create_example_swarm()
def get_stats(self):
"""
获取群体统计信息
"""
return {
'member_count': len(self.members),
'paused': self.paused,
'fps': self.fps,
'swarm_type': self.swarm_type
}
def toggle_pause(self):
"""
切换暂停状态
"""
self.paused = not self.paused
print(f"群体模拟{'已暂停' if self.paused else '已恢复'}")
def cleanup(self):
"""
清理资源
"""
# 移除任务
if self.task:
self.world.taskMgr.remove(self.task)
# 移除所有群体成员
for member in self.members:
member['node'].removeNode()
# 移除所有捕食者
for predator in self.predators:
predator['node'].removeNode()
# 清空列表
self.members.clear()
self.obstacles.clear()
self.predators.clear()
def reset(self):
"""
重置群体
"""
self.cleanup()
self.create_example_swarm()