481 lines
19 KiB
Python
481 lines
19 KiB
Python
"""
|
|
环境感知和响应管理器
|
|
提供群体对环境的感知能力和响应机制
|
|
"""
|
|
|
|
from panda3d.core import Vec3
|
|
import random
|
|
import math
|
|
from typing import Dict, List, Tuple, Optional, Any
|
|
|
|
|
|
class EnvironmentSensor:
|
|
"""
|
|
环境传感器类
|
|
模拟群体成员的环境感知能力
|
|
"""
|
|
|
|
def __init__(self, sensor_range: float = 15.0, sensor_accuracy: float = 0.9):
|
|
"""
|
|
初始化传感器
|
|
|
|
:param sensor_range: 传感器感知范围
|
|
:param sensor_accuracy: 传感器精度 (0.0-1.0)
|
|
"""
|
|
self.sensor_range = sensor_range
|
|
self.sensor_accuracy = sensor_accuracy
|
|
self.sensor_noise = 1.0 - sensor_accuracy # 传感器噪声水平
|
|
|
|
def sense_environment(self, position: Vec3, environment_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
感知环境
|
|
返回在指定位置感知到的环境信息
|
|
|
|
:param position: 感知位置
|
|
:param environment_data: 环境数据
|
|
:return: 感知到的环境信息
|
|
"""
|
|
sensed_data = {}
|
|
|
|
# 感知障碍物
|
|
sensed_data['obstacles'] = self._sense_obstacles(position, environment_data.get('obstacles', []))
|
|
|
|
# 感知其他群体
|
|
sensed_data['other_swarms'] = self._sense_other_swarms(position, environment_data.get('swarms', []))
|
|
|
|
# 感知捕食者
|
|
sensed_data['predators'] = self._sense_predators(position, environment_data.get('predators', []))
|
|
|
|
# 感知天气/环境条件
|
|
sensed_data['weather'] = self._sense_weather(position, environment_data.get('weather', {}))
|
|
|
|
# 感知资源点
|
|
sensed_data['resources'] = self._sense_resources(position, environment_data.get('resources', []))
|
|
|
|
# 感知危险区域
|
|
sensed_data['hazards'] = self._sense_hazards(position, environment_data.get('hazards', []))
|
|
|
|
# 添加传感器噪声
|
|
sensed_data = self._add_sensor_noise(sensed_data)
|
|
|
|
return sensed_data
|
|
|
|
def _sense_obstacles(self, position: Vec3, obstacles: List[Dict]) -> List[Dict]:
|
|
"""
|
|
感知障碍物
|
|
"""
|
|
sensed_obstacles = []
|
|
for obstacle in obstacles:
|
|
distance = (position - obstacle['position']).length()
|
|
if distance <= self.sensor_range:
|
|
# 计算感知误差
|
|
error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
|
|
sensed_obstacle = obstacle.copy()
|
|
sensed_obstacle['distance'] = distance * error_factor
|
|
sensed_obstacle['direction'] = (obstacle['position'] - position).normalized()
|
|
sensed_obstacles.append(sensed_obstacle)
|
|
|
|
return sensed_obstacles
|
|
|
|
def _sense_other_swarms(self, position: Vec3, swarms: List[Dict]) -> List[Dict]:
|
|
"""
|
|
感知其他群体
|
|
"""
|
|
sensed_swarms = []
|
|
for swarm in swarms:
|
|
# 计算群体中心位置
|
|
if 'members' in swarm and len(swarm['members']) > 0:
|
|
center = Vec3(0, 0, 0)
|
|
for member in swarm['members']:
|
|
center += member['position']
|
|
center /= len(swarm['members'])
|
|
|
|
distance = (position - center).length()
|
|
if distance <= self.sensor_range:
|
|
error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
|
|
sensed_swarm = {
|
|
'id': swarm['id'],
|
|
'type': swarm['type'],
|
|
'distance': distance * error_factor,
|
|
'direction': (center - position).normalized(),
|
|
'size': len(swarm['members'])
|
|
}
|
|
sensed_swarms.append(sensed_swarm)
|
|
|
|
return sensed_swarms
|
|
|
|
def _sense_predators(self, position: Vec3, predators: List[Dict]) -> List[Dict]:
|
|
"""
|
|
感知捕食者
|
|
"""
|
|
sensed_predators = []
|
|
for predator in predators:
|
|
distance = (position - predator['position']).length()
|
|
if distance <= self.sensor_range:
|
|
error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
|
|
sensed_predator = {
|
|
'position': predator['position'],
|
|
'distance': distance * error_factor,
|
|
'direction': (predator['position'] - position).normalized(),
|
|
'velocity': predator.get('velocity', Vec3(0, 0, 0))
|
|
}
|
|
sensed_predators.append(sensed_predator)
|
|
|
|
return sensed_predators
|
|
|
|
def _sense_weather(self, position: Vec3, weather: Dict) -> Dict:
|
|
"""
|
|
感知天气/环境条件
|
|
"""
|
|
# 天气信息通常对整个区域是相同的,但可能有局部变化
|
|
sensed_weather = weather.copy()
|
|
|
|
# 添加局部变化
|
|
if 'wind' in sensed_weather:
|
|
wind = sensed_weather['wind']
|
|
# 添加传感器噪声
|
|
noise_x = random.uniform(-self.sensor_noise, self.sensor_noise) * wind['direction'].x
|
|
noise_y = random.uniform(-self.sensor_noise, self.sensor_noise) * wind['direction'].y
|
|
sensed_weather['wind']['direction'] = Vec3(
|
|
wind['direction'].x + noise_x,
|
|
wind['direction'].y + noise_y,
|
|
wind['direction'].z
|
|
).normalized()
|
|
|
|
return sensed_weather
|
|
|
|
def _sense_resources(self, position: Vec3, resources: List[Dict]) -> List[Dict]:
|
|
"""
|
|
感知资源点
|
|
"""
|
|
sensed_resources = []
|
|
for resource in resources:
|
|
distance = (position - resource['position']).length()
|
|
if distance <= self.sensor_range:
|
|
error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
|
|
sensed_resource = resource.copy()
|
|
sensed_resource['distance'] = distance * error_factor
|
|
sensed_resource['direction'] = (resource['position'] - position).normalized()
|
|
sensed_resources.append(sensed_resource)
|
|
|
|
return sensed_resources
|
|
|
|
def _sense_hazards(self, position: Vec3, hazards: List[Dict]) -> List[Dict]:
|
|
"""
|
|
感知危险区域
|
|
"""
|
|
sensed_hazards = []
|
|
for hazard in hazards:
|
|
distance = (position - hazard['position']).length()
|
|
if distance <= self.sensor_range:
|
|
error_factor = random.uniform(1 - self.sensor_noise, 1 + self.sensor_noise)
|
|
sensed_hazard = hazard.copy()
|
|
sensed_hazard['distance'] = distance * error_factor
|
|
sensed_hazard['direction'] = (hazard['position'] - position).normalized()
|
|
sensed_hazards.append(sensed_hazard)
|
|
|
|
return sensed_hazards
|
|
|
|
def _add_sensor_noise(self, sensed_data: Dict) -> Dict:
|
|
"""
|
|
为感知数据添加噪声
|
|
"""
|
|
# 在实际应用中,可以对某些数值添加噪声
|
|
return sensed_data
|
|
|
|
|
|
class EnvironmentalResponseSystem:
|
|
"""
|
|
环境响应系统
|
|
根据感知到的环境信息决定群体的响应行为
|
|
"""
|
|
|
|
def __init__(self, config):
|
|
self.config = config
|
|
|
|
def calculate_response(self, member: Dict, sensed_data: Dict,
|
|
current_velocity: Vec3, current_position: Vec3) -> Vec3:
|
|
"""
|
|
根据感知数据计算响应力
|
|
"""
|
|
response_force = Vec3(0, 0, 0)
|
|
|
|
# 避开障碍物
|
|
response_force += self._avoid_obstacles(sensed_data['obstacles'], current_position, current_velocity)
|
|
|
|
# 应对捕食者
|
|
response_force += self._respond_to_predators(sensed_data['predators'], current_position)
|
|
|
|
# 寻找资源
|
|
response_force += self._seek_resources(sensed_data['resources'], current_position)
|
|
|
|
# 避开危险区域
|
|
response_force += self._avoid_hazards(sensed_data['hazards'], current_position)
|
|
|
|
# 适应天气条件
|
|
response_force += self._adapt_to_weather(sensed_data['weather'], current_position, current_velocity)
|
|
|
|
# 处理其他群体
|
|
response_force += self._respond_to_other_swarms(sensed_data['other_swarms'], current_position)
|
|
|
|
return response_force
|
|
|
|
def _avoid_obstacles(self, obstacles: List[Dict], position: Vec3, velocity: Vec3) -> Vec3:
|
|
"""
|
|
避开障碍物
|
|
"""
|
|
avoidance_force = Vec3(0, 0, 0)
|
|
|
|
for obstacle in obstacles:
|
|
distance = obstacle['distance']
|
|
if distance < 5.0: # 在近距离内才需要避障
|
|
# 计算避障方向(远离障碍物)
|
|
direction = obstacle['direction'] * -1
|
|
# 距离越近,避障力越大
|
|
magnitude = max(0, 5.0 - distance) / 5.0
|
|
avoidance_force += direction * magnitude
|
|
|
|
return avoidance_force * self.config.get("obstacle_response_weight", 2.0)
|
|
|
|
def _respond_to_predators(self, predators: List[Dict], position: Vec3) -> Vec3:
|
|
"""
|
|
响应捕食者
|
|
"""
|
|
flee_force = Vec3(0, 0, 0)
|
|
|
|
for predator in predators:
|
|
distance = predator['distance']
|
|
if distance < self.config.get("predator_radius", 15.0):
|
|
# 逃离捕食者方向
|
|
direction = predator['direction'] * -1
|
|
# 距离越近,逃离力越大
|
|
magnitude = max(0, (self.config.get("predator_radius", 15.0) - distance) / self.config.get("predator_radius", 15.0))
|
|
flee_force += direction * magnitude
|
|
|
|
return flee_force * self.config.get("predator_response_weight", 3.0)
|
|
|
|
def _seek_resources(self, resources: List[Dict], position: Vec3) -> Vec3:
|
|
"""
|
|
寻找资源
|
|
"""
|
|
if not resources:
|
|
return Vec3(0, 0, 0)
|
|
|
|
# 寻找最近的资源
|
|
nearest_resource = min(resources, key=lambda r: r['distance'])
|
|
distance = nearest_resource['distance']
|
|
|
|
if distance < 20.0: # 在一定范围内才寻求资源
|
|
direction = nearest_resource['direction']
|
|
# 距离越远,寻求力越大,当接近时减小
|
|
magnitude = max(0.1, 1.0 - distance/20.0)
|
|
seek_force = direction * magnitude
|
|
return seek_force * self.config.get("resource_seek_weight", 0.5) # 使用配置中的权重
|
|
|
|
return Vec3(0, 0, 0)
|
|
|
|
def _avoid_hazards(self, hazards: List[Dict], position: Vec3) -> Vec3:
|
|
"""
|
|
避开危险区域
|
|
"""
|
|
avoidance_force = Vec3(0, 0, 0)
|
|
|
|
for hazard in hazards:
|
|
distance = hazard['distance']
|
|
hazard_radius = hazard.get('radius', 5.0)
|
|
if distance < hazard_radius * 2: # 在危险区域两倍半径内
|
|
direction = hazard['direction'] * -1 # 远离危险
|
|
magnitude = max(0, (hazard_radius * 2 - distance) / (hazard_radius * 2))
|
|
avoidance_force += direction * magnitude
|
|
|
|
return avoidance_force * self.config.get("hazard_avoid_weight", 3.0) # 使用配置中的权重
|
|
|
|
def _adapt_to_weather(self, weather: Dict, position: Vec3, velocity: Vec3) -> Vec3:
|
|
"""
|
|
适应天气条件
|
|
"""
|
|
if not weather or 'wind' not in weather:
|
|
return Vec3(0, 0, 0)
|
|
|
|
wind = weather['wind']
|
|
wind_force = wind['direction'] * wind['strength']
|
|
|
|
# 根据成员类型调整对天气的响应
|
|
member_type = position # 位置参数用于占位
|
|
adaptation_factor = 1.0
|
|
|
|
# 实际应用中,可以根据成员类型调整响应
|
|
if hasattr(self, 'member_type'):
|
|
if self.member_type == "鸟类":
|
|
adaptation_factor = 0.7 # 鸟类受风影响较小
|
|
elif self.member_type == "昆虫":
|
|
adaptation_factor = 1.5 # 昆虫受风影响较大
|
|
|
|
return wind_force * adaptation_factor
|
|
|
|
def _respond_to_other_swarms(self, other_swarms: List[Dict], position: Vec3) -> Vec3:
|
|
"""
|
|
响应其他群体
|
|
根据群体类型和关系决定响应
|
|
"""
|
|
response_force = Vec3(0, 0, 0)
|
|
|
|
for swarm in other_swarms:
|
|
distance = swarm['distance']
|
|
swarm_type = swarm['type']
|
|
|
|
if distance < 10.0: # 在近距离内响应
|
|
direction = swarm['direction']
|
|
|
|
# 根据群体类型决定响应
|
|
if swarm_type == "predator": # 假设这是捕食者群体
|
|
# 逃离
|
|
response_force += direction * -1 * max(0, (10.0 - distance) / 10.0) * 2.0
|
|
elif swarm_type == "same": # 同类群体
|
|
# 可能靠近或远离,取决于密度
|
|
response_force += direction * max(0, (distance - 5.0) / 5.0) * 0.5
|
|
else: # 其他类型
|
|
# 中性响应
|
|
response_force += direction * 0.1
|
|
|
|
return response_force
|
|
|
|
|
|
class EnvironmentManager:
|
|
"""
|
|
环境管理器
|
|
管理整个环境的状态和变化
|
|
"""
|
|
|
|
def __init__(self, config):
|
|
self.config = config
|
|
self.sensors = {}
|
|
self.response_system = EnvironmentalResponseSystem(config)
|
|
self.environment_state = {
|
|
'obstacles': [],
|
|
'swarms': [],
|
|
'predators': [],
|
|
'weather': {},
|
|
'resources': [],
|
|
'hazards': [],
|
|
'time_of_day': 12.0, # 24小时制时间
|
|
'season': 'spring'
|
|
}
|
|
self.weather_effects = {
|
|
'wind': {'direction': Vec3(0, 1, 0), 'strength': 0.2},
|
|
'temperature': 20.0,
|
|
'precipitation': 0.0
|
|
}
|
|
|
|
def add_sensor(self, member_id: str, sensor_range: float = None, sensor_accuracy: float = None):
|
|
"""
|
|
为成员添加传感器
|
|
"""
|
|
if sensor_range is None:
|
|
sensor_range = self.config.get("sensor_range", 15.0)
|
|
if sensor_accuracy is None:
|
|
sensor_accuracy = self.config.get("sensor_accuracy", 0.9)
|
|
|
|
self.sensors[member_id] = EnvironmentSensor(sensor_range, sensor_accuracy)
|
|
|
|
def update_environment_state(self, obstacles: List[Dict], swarms: List[Dict],
|
|
predators: List[Dict], resources: List[Dict],
|
|
hazards: List[Dict]):
|
|
"""
|
|
更新环境状态
|
|
"""
|
|
self.environment_state['obstacles'] = obstacles
|
|
self.environment_state['swarms'] = swarms
|
|
self.environment_state['predators'] = predators
|
|
self.environment_state['resources'] = resources
|
|
self.environment_state['hazards'] = hazards
|
|
|
|
# 更新天气效果(简化模拟)
|
|
self._update_weather_effects()
|
|
|
|
def _update_weather_effects(self):
|
|
"""
|
|
更新天气效果(随时间变化)
|
|
"""
|
|
# 简单的天气变化模拟
|
|
time_factor = math.sin(self.environment_state['time_of_day'] * math.pi / 12) # 0-24小时周期
|
|
self.weather_effects['wind']['strength'] = 0.2 + abs(time_factor) * 0.3
|
|
|
|
# 温度变化
|
|
self.weather_effects['temperature'] = 15 + time_factor * 10
|
|
|
|
# 更新环境状态
|
|
self.environment_state['weather'] = self.weather_effects.copy()
|
|
|
|
def get_environmental_response(self, member: Dict, position: Vec3, velocity: Vec3) -> Vec3:
|
|
"""
|
|
获取成员的环境响应力
|
|
"""
|
|
member_id = id(member)
|
|
|
|
# 如果成员没有传感器,添加一个默认传感器
|
|
if member_id not in self.sensors:
|
|
self.add_sensor(member_id)
|
|
|
|
# 使用传感器感知环境
|
|
sensed_data = self.sensors[member_id].sense_environment(position, self.environment_state)
|
|
|
|
# 计算环境响应
|
|
response_force = self.response_system.calculate_response(
|
|
member, sensed_data, velocity, position
|
|
)
|
|
|
|
return response_force
|
|
|
|
def advance_time(self, dt: float):
|
|
"""
|
|
推进环境时间
|
|
"""
|
|
self.environment_state['time_of_day'] += dt * 0.1 # 时间流逝速度调整
|
|
if self.environment_state['time_of_day'] >= 24.0:
|
|
self.environment_state['time_of_day'] -= 24.0
|
|
|
|
def add_resource(self, position: Vec3, resource_type: str = "food", amount: float = 100.0):
|
|
"""
|
|
添加资源点
|
|
"""
|
|
resource = {
|
|
'position': position,
|
|
'type': resource_type,
|
|
'amount': amount,
|
|
'radius': 3.0
|
|
}
|
|
self.environment_state['resources'].append(resource)
|
|
return resource
|
|
|
|
def add_hazard(self, position: Vec3, hazard_type: str = "toxic", radius: float = 5.0):
|
|
"""
|
|
添加危险区域
|
|
"""
|
|
hazard = {
|
|
'position': position,
|
|
'type': hazard_type,
|
|
'radius': radius
|
|
}
|
|
self.environment_state['hazards'].append(hazard)
|
|
return hazard
|
|
|
|
def get_environment_info(self) -> Dict:
|
|
"""
|
|
获取环境信息
|
|
"""
|
|
return self.environment_state.copy()
|
|
|
|
def update_environment_dynamics(self):
|
|
"""
|
|
更新环境动态变化
|
|
如资源消耗、天气变化等
|
|
"""
|
|
# 更新资源(简化模拟资源消耗)
|
|
for i, resource in enumerate(self.environment_state['resources']):
|
|
if resource['amount'] > 0:
|
|
# 模拟资源随时间缓慢恢复
|
|
resource['amount'] = min(resource['amount'] + 0.01, 100.0)
|
|
|
|
# 更新天气
|
|
self._update_weather_effects() |