""" 行为树叶子节点 包括条件节点、动作节点、等待节点等 提供多种叶子节点实现 """ import time import random import math from typing import Optional, Callable, Any, Union from ..core.behavior_tree import BTNode, NodeStatus, BTNodeConfig class ConditionNode(BTNode): """ 条件节点 检查条件是否满足 支持多种条件检查方式和缓存机制 """ def __init__(self, config: Union[BTNodeConfig, str] = "Condition", condition_func: Optional[Callable[[Any], bool]] = None, cache_result: bool = False, # 是否缓存结果 cache_duration: float = 0.0): # 缓存持续时间(秒) super().__init__(config) self.condition_func = condition_func self.cache_result = cache_result self.cache_duration = cache_duration self.cached_result: Optional[bool] = None self.cache_time: float = 0.0 def execute(self, blackboard) -> NodeStatus: """执行条件检查""" current_time = time.time() # 检查缓存 if (self.cache_result and self.cached_result is not None and (self.cache_duration <= 0 or current_time - self.cache_time < self.cache_duration)): # 使用缓存结果 return NodeStatus.SUCCESS if self.cached_result else NodeStatus.FAILURE # 执行条件检查 result = self._evaluate_condition(blackboard) # 更新缓存 if self.cache_result: self.cached_result = result self.cache_time = current_time return NodeStatus.SUCCESS if result else NodeStatus.FAILURE def _evaluate_condition(self, blackboard) -> bool: """评估条件""" if self.condition_func: try: return bool(self.condition_func(blackboard)) except Exception as e: print(f"条件节点执行出错: {e}") return False else: # 如果没有提供条件函数,默认返回成功 return True def invalidate_cache(self) -> None: """使缓存失效""" self.cached_result = None self.cache_time = 0.0 def reset(self) -> None: """重置节点状态""" super().reset() self.invalidate_cache() class ActionNode(BTNode): """ 动作节点 执行具体行为 支持异步执行和进度跟踪 """ def __init__(self, config: Union[BTNodeConfig, str] = "Action", action_func: Optional[Callable[[Any], Any]] = None, async_action: bool = False, # 是否异步执行 progress_callback: Optional[Callable[[float], None]] = None): # 进度回调 super().__init__(config) self.action_func = action_func self.async_action = async_action self.progress_callback = progress_callback self.is_running = False self.start_time = 0.0 self.estimated_duration = 0.0 # 估计执行时间 def execute(self, blackboard) -> NodeStatus: """执行动作""" current_time = time.time() # 如果是异步动作且正在运行 if self.async_action and self.is_running: # 检查动作是否完成 if self._is_async_action_complete(blackboard): self.is_running = False self.start_time = 0.0 return NodeStatus.SUCCESS else: # 更新进度 if self.progress_callback: progress = self._calculate_progress(current_time) try: self.progress_callback(progress) except Exception as e: print(f"进度回调执行出错: {e}") return NodeStatus.RUNNING # 执行动作 if self.action_func: try: # 记录开始时间 self.start_time = current_time if self.async_action: # 异步执行 result = self._start_async_action(blackboard) if result == NodeStatus.RUNNING: self.is_running = True return NodeStatus.RUNNING else: self.start_time = 0.0 return result else: # 同步执行 result = self.action_func(blackboard) self.start_time = 0.0 if result is True: return NodeStatus.SUCCESS elif result is False: return NodeStatus.FAILURE elif result == NodeStatus.RUNNING: return NodeStatus.RUNNING else: # 默认返回成功 return NodeStatus.SUCCESS except Exception as e: print(f"动作节点执行出错: {e}") self.is_running = False self.start_time = 0.0 return NodeStatus.FAILURE else: # 如果没有提供动作函数,默认返回成功 return NodeStatus.SUCCESS def _start_async_action(self, blackboard) -> NodeStatus: """启动异步动作""" # 这里应该启动异步操作,例如创建线程或任务 # 为了简化,我们假设异步动作立即开始并需要继续运行 return NodeStatus.RUNNING def _is_async_action_complete(self, blackboard) -> bool: """检查异步动作是否完成""" # 这里应该检查异步操作是否完成 # 为了简化,我们随机决定是否完成 if self.estimated_duration > 0: current_time = time.time() elapsed = current_time - self.start_time return elapsed >= self.estimated_duration else: # 随机完成(用于演示) return random.random() < 0.1 # 10%概率完成 def _calculate_progress(self, current_time: float) -> float: """计算进度""" if self.estimated_duration > 0: elapsed = current_time - self.start_time progress = min(1.0, elapsed / self.estimated_duration) return max(0.0, progress) else: return 0.0 def reset(self) -> None: """重置节点状态""" super().reset() self.is_running = False self.start_time = 0.0 class WaitNode(ActionNode): """ 等待节点 等待指定时间后返回成功 支持随机等待时间和进度回调 """ def __init__(self, config: Union[BTNodeConfig, str] = "Wait", duration: float = 1.0, random_variance: float = 0.0, # 随机变化范围(秒) progress_callback: Optional[Callable[[float], None]] = None): super().__init__(config, None, False, progress_callback) self.base_duration = duration self.random_variance = random_variance self.actual_duration = duration # 实际等待时间 self.start_time = 0.0 def execute(self, blackboard) -> NodeStatus: """执行等待""" current_time = time.time() # 如果是第一次执行,计算实际等待时间 if self.start_time == 0.0: self.start_time = current_time # 添加随机变化 if self.random_variance > 0: variance = random.uniform(-self.random_variance, self.random_variance) self.actual_duration = max(0.0, self.base_duration + variance) else: self.actual_duration = self.base_duration # 检查是否等待完成 elapsed = current_time - self.start_time if elapsed >= self.actual_duration: # 等待完成,重置开始时间 self.start_time = 0.0 return NodeStatus.SUCCESS else: # 更新进度 if self.progress_callback: progress = min(1.0, elapsed / self.actual_duration) try: self.progress_callback(progress) except Exception as e: print(f"进度回调执行出错: {e}") return NodeStatus.RUNNING def reset(self) -> None: """重置节点状态""" super().reset() self.start_time = 0.0 self.actual_duration = self.base_duration class SubtreeNode(BTNode): """ 子树节点 执行另一个行为树作为子树 """ def __init__(self, config: Union[BTNodeConfig, str] = "Subtree", subtree: Optional['BehaviorTree'] = None): super().__init__(config) self.subtree = subtree self.is_running = False def execute(self, blackboard) -> NodeStatus: """执行子树""" if not self.subtree: return NodeStatus.FAILURE # 设置子树的黑板 self.subtree.set_blackboard(blackboard) # 执行子树 try: result = self.subtree.run() return result except Exception as e: print(f"子树执行出错: {e}") return NodeStatus.FAILURE def set_subtree(self, subtree: 'BehaviorTree') -> None: """设置子树""" self.subtree = subtree def get_subtree(self) -> Optional['BehaviorTree']: """获取子树""" return self.subtree class ProbabilityNode(ActionNode): """ 概率节点 根据概率决定执行结果 """ def __init__(self, config: Union[BTNodeConfig, str] = "Probability", success_probability: float = 0.5, # 成功概率 action_func: Optional[Callable[[Any], Any]] = None): super().__init__(config, action_func) self.success_probability = max(0.0, min(1.0, success_probability)) self.has_executed = False self.result = NodeStatus.FAILURE def execute(self, blackboard) -> NodeStatus: """执行概率动作""" # 如果已经执行过,返回之前的结果 if self.has_executed: return self.result # 执行实际动作(如果提供了) if self.action_func: try: action_result = self.action_func(blackboard) # 如果动作返回了具体状态,使用该状态 if action_result == NodeStatus.SUCCESS: self.result = NodeStatus.SUCCESS elif action_result == NodeStatus.FAILURE: self.result = NodeStatus.FAILURE elif action_result == NodeStatus.RUNNING: return NodeStatus.RUNNING except Exception as e: print(f"概率节点动作执行出错: {e}") self.result = NodeStatus.FAILURE else: # 根据概率决定结果 if random.random() < self.success_probability: self.result = NodeStatus.SUCCESS else: self.result = NodeStatus.FAILURE self.has_executed = True return self.result def reset(self) -> None: """重置节点状态""" super().reset() self.has_executed = False self.result = NodeStatus.FAILURE class CounterNode(ConditionNode): """ 计数器节点 根据执行次数决定结果 """ def __init__(self, config: Union[BTNodeConfig, str] = "Counter", target_count: int = 1, # 目标计数 reset_on_target: bool = True, # 达到目标后是否重置 condition_func: Optional[Callable[[Any], bool]] = None): super().__init__(config, condition_func) self.target_count = max(1, target_count) self.reset_on_target = reset_on_target self.current_count = 0 def _evaluate_condition(self, blackboard) -> bool: """评估条件""" # 首先检查提供的条件函数 if self.condition_func: try: if not self.condition_func(blackboard): return False except Exception as e: print(f"计数器节点条件检查出错: {e}") return False # 增加计数 self.current_count += 1 # 检查是否达到目标计数 result = self.current_count >= self.target_count # 如果达到目标且需要重置,重置计数器 if result and self.reset_on_target: self.current_count = 0 return result def reset(self) -> None: """重置节点状态""" super().reset() self.current_count = 0 class TimeoutNode(ActionNode): """ 超时节点 限制动作执行时间 """ def __init__(self, config: Union[BTNodeConfig, str] = "Timeout", action_func: Optional[Callable[[Any], Any]] = None, timeout: float = 5.0): # 超时时间(秒) super().__init__(config, action_func) self.timeout = timeout self.start_time = 0.0 def execute(self, blackboard) -> NodeStatus: """执行带超时的动作""" current_time = time.time() # 记录开始时间 if self.start_time == 0.0: self.start_time = current_time # 检查是否超时 if current_time - self.start_time >= self.timeout: # 超时,返回失败 self.start_time = 0.0 return NodeStatus.FAILURE # 执行动作 if self.action_func: try: result = self.action_func(blackboard) # 如果动作完成,重置开始时间 if result != NodeStatus.RUNNING: self.start_time = 0.0 if result is True: return NodeStatus.SUCCESS elif result is False: return NodeStatus.FAILURE elif result == NodeStatus.RUNNING: return NodeStatus.RUNNING else: # 默认返回成功 self.start_time = 0.0 return NodeStatus.SUCCESS except Exception as e: print(f"超时节点动作执行出错: {e}") self.start_time = 0.0 return NodeStatus.FAILURE else: # 如果没有提供动作函数,默认返回成功 self.start_time = 0.0 return NodeStatus.SUCCESS def reset(self) -> None: """重置节点状态""" super().reset() self.start_time = 0.0