import os from numbers import Real from behaviors.behavior import Behavior from behaviors.custom.keyframe.keyframe import KeyframeSkill class Kick(Behavior): SHORT_MAX_DISTANCE: float = 1.8 MID_MAX_DISTANCE: float = 4.5 TEN_METER_MIN_DISTANCE: float = 8.0 DEFAULT_DISTANCE: float = 3.0 def __init__(self, agent): super().__init__(agent) base_dir = os.path.dirname(__file__) self.short_kick = KeyframeSkill( agent=agent, file=os.path.join(base_dir, "kick_short.yaml"), ) self.mid_kick = KeyframeSkill( agent=agent, file=os.path.join(base_dir, "kick_mid.yaml"), ) self.long_kick = KeyframeSkill( agent=agent, file=os.path.join(base_dir, "kick_long.yaml"), ) self.ten_meter_kick = KeyframeSkill( agent=agent, file=os.path.join(base_dir, "kick_10m.yaml"), ) self.current_kick: KeyframeSkill | None = None self.should_reset_kick: bool = True self.should_execute_neutral: bool = True def execute(self, reset: bool, *args, **kwargs) -> bool: if reset: kick_distance = self._extract_kick_distance(*args, **kwargs) self.current_kick = self._choose_kick_from_distance(kick_distance) self.should_reset_kick = True self.should_execute_neutral = True if self.current_kick is None: self.current_kick = self.mid_kick if self.should_execute_neutral: neutral_finished = self.agent.skills_manager.execute( "Neutral", ) self.should_reset_kick = False if not neutral_finished: return False self.should_execute_neutral = False self.should_reset_kick = True has_finished = self.current_kick.execute(reset=self.should_reset_kick) self.should_reset_kick = False return has_finished def _extract_kick_distance(self, *args, **kwargs) -> float: distance_candidates = ( kwargs.get("distance"), kwargs.get("kick_distance"), kwargs.get("target_distance"), kwargs.get("ball_to_target_distance"), args[0] if args else None, ) for candidate in distance_candidates: if isinstance(candidate, Real): return float(max(0.0, candidate)) return self.DEFAULT_DISTANCE def _choose_kick_from_distance(self, distance: float) -> KeyframeSkill: if distance <= self.SHORT_MAX_DISTANCE: return self.short_kick if distance <= self.MID_MAX_DISTANCE: return self.mid_kick if distance >= self.TEN_METER_MIN_DISTANCE: return self.ten_meter_kick return self.long_kick def is_ready(self, *args) -> bool: return True