def _calc_projectile_path_avoidance(self): rocket_location = self.history.rocket.location turret_location = self.parameters.turret.location projectile_path_avoidance = [] for projectile in self.history.active_projectiles: gradient = math.tan(projectile.firing_angle) y_intercept = turret_location.y - gradient * turret_location.x y_value = gradient * rocket_location.x + y_intercept avoidance_angle = normalise_angle( projectile.firing_angle + (1 if rocket_location.y > y_value else -1) * math.pi / 2) min_dist_rocket2path = self.calc_minimum_distance_from_location2line( rocket_location, gradient, y_intercept) projectile_location = self.helpers.calc_projectile_location( projectile) dist_rockt2projectile = rocket_location.distance2( projectile_location) try: avoidance_strength = 1 / ( min_dist_rocket2path * (dist_rockt2projectile - self.parameters.rocket.target_radius)) except ZeroDivisionError: avoidance_strength = float("inf") projectile_path_avoidance.append( PolarCoordinate(avoidance_strength, avoidance_angle).pol2cart()) return (average(projectile_path_avoidance) if projectile_path_avoidance else Coordinate(0.0, 0.0))
def _calc_single_obstacle_shadow_attraction( self, obstacle: Coordinate) -> Coordinate: # TODO: Make this more efficient by storing it between cycles # TODO: Deal with perfectly vertical gradients angle_turret2obstacle = (obstacle.location - self.parameters.turret.location).angle edge_gradients = self.calc_shadow_edge_gradients(obstacle) shadow_attractions = [] rocket_location = self.history.rocket.location for gradient in edge_gradients: y_intercept = Line.calculate_y_intercept( gradient, self.parameters.turret.location) shadow_edge_line = Line(gradient, y_intercept) closest_point = shadow_edge_line.closest_point_on_line( rocket_location) strength = 1 / rocket_location.distance2(closest_point) angle_turret2closest_point = ( closest_point - self.parameters.turret.location).angle if normalise_angle(angle_turret2closest_point - angle_turret2obstacle) > 0: rotation = -1 else: rotation = 1 direction_angle = angle_turret2closest_point + rotation * math.pi / 2 shadow_attractions.append( PolarCoordinate(strength, direction_angle).pol2cart()) return sum(shadow_attractions)
def will_projectile_hit_rocket_before_obstacle(self): projectile_location = self.parameters.turret.location projectile_speed = self.parameters.turret.projectile_speed projectile_angle = self.history.turret.angle projectile_velocity = PolarCoordinate(projectile_speed, projectile_angle).pol2cart() rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() projectile2rocket = RelativeObjects(projectile_location, rocket_location, projectile_velocity, rocket_velocity) rocket_output = projectile2rocket.time_objects_first_within_distance( self.parameters.rocket.target_radius) if rocket_output is None: return False # Doesn't hit rocket at all time_rocket_intercept, _ = rocket_output for obstacle in self.parameters.environment.obstacles: projectile2obstacle = RelativeObjects(projectile_location, obstacle.location, projectile_velocity) obstacle_output = projectile2obstacle.time_objects_first_within_distance( obstacle.radius) if obstacle_output is None: continue time_obstacle_intercept, _ = obstacle_output if time_obstacle_intercept < time_rocket_intercept: return False return True
def will_projectile_hit_rocket_within_bounds(self): safety_buffer = 2.0 projectile_location = self.parameters.turret.location projectile_speed = self.parameters.turret.projectile_speed projectile_angle = self.history.turret.angle projectile_velocity = PolarCoordinate(projectile_speed, projectile_angle).pol2cart() rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() projectile2rocket = RelativeObjects(projectile_location, rocket_location, projectile_velocity, rocket_velocity) ( min_dist, _, (projectile_location_min_dist, rocket_location_min_dist), ) = projectile2rocket.minimum_distance_between_objects() return ( min_dist <= self.parameters.rocket.target_radius / safety_buffer and self.helpers.is_within_bounds(projectile_location_min_dist) and self.helpers.is_within_bounds(rocket_location_min_dist))
def _calc_within_buffer_projectile_avoidance(self, safety_factor=2.0): rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() within_buffer_projectile_avoidance = [] for projectile in self.history.active_projectiles: projectile_location = self.helpers.calc_projectile_location( projectile) projectile_velocity = self.helpers.calc_projectile_velocity( projectile) rocket2projectile = RelativeObjects( rocket_location, projectile_location, rocket_velocity, projectile_velocity, ) ( min_dist, _, (rocket_location_min_dist, projectile_location_min_dist), ) = rocket2projectile.minimum_distance_between_objects() buffer = safety_factor * self.parameters.rocket.target_radius if min_dist > buffer: continue output = rocket2projectile.time_objects_first_within_distance( buffer) if output: # Rocket is currently outside buffer ( time_rocket_enters_projectile_buffer, (rocket_location_enter_buffer, projectile_location_enter_buffer), ) = output # Check if the collision is out of bounds if not self.helpers.is_within_bounds( rocket_location_enter_buffer ) or not self.helpers.is_within_bounds( projectile_location_enter_buffer): continue current_dist = ( self.controller_helpers. calc_dist_between_rocket_and_projectile(projectile)) try: avoidance_strength = 1 / ( min_dist * (current_dist - self.parameters.rocket.target_radius)) except ZeroDivisionError: avoidance_strength = float("inf") avoidance_angle = (rocket_location_min_dist - projectile_location_min_dist).angle within_buffer_projectile_avoidance.append( PolarCoordinate(avoidance_strength, avoidance_angle).pol2cart()) return (average(within_buffer_projectile_avoidance) if within_buffer_projectile_avoidance else Coordinate(0.0, 0.0))
def _plot_engine_thrust( self, force, projection_location, relative_engine_angle, engine_plot ): rocket_angle = self.history.rocket.angle projection_angle = normalise_angle(rocket_angle + relative_engine_angle) max_main_engine_force = self.parameters.rocket.max_main_engine_force rocket_length = self.parameters.rocket.length thrust_ratio = force / max_main_engine_force edge_length = ( self.visual.rocket_length_max_thrust_length_ratio * rocket_length * thrust_ratio ) left_angle = normalise_angle(projection_angle + self.visual.thrust_cone_angle) relative_thrust_left_location = PolarCoordinate( edge_length, left_angle ).pol2cart() thrust_left_location = projection_location + relative_thrust_left_location right_angle = normalise_angle(projection_angle - self.visual.thrust_cone_angle) relative_thrust_right_location = PolarCoordinate( edge_length, right_angle ).pol2cart() thrust_right_location = projection_location + relative_thrust_right_location engine_plot.set_data( [ projection_location.x, thrust_left_location.x, thrust_right_location.x, projection_location.x, ], [ projection_location.y, thrust_left_location.y, thrust_right_location.y, projection_location.y, ], )
def _calc_intersecting_projectile_avoidance(self): rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() intersecting_projectile_avoidance = [] for projectile in self.history.active_projectiles: projectile_location = self.helpers.calc_projectile_location( projectile) projectile_velocity = self.helpers.calc_projectile_velocity( projectile) rocket2projectile = RelativeObjects( rocket_location, projectile_location, rocket_velocity, projectile_velocity, ) ( min_dist, _, (rocket_location_min_dist, projectile_location_min_dist), ) = rocket2projectile.minimum_distance_between_objects() # Check if the projectile will ever get close enough threshold = self.parameters.rocket.target_radius if min_dist > threshold: continue ( time_projectile_hits_rocket, (rocket_location_hit, projectile_location_hit), ) = rocket2projectile.time_objects_first_within_distance(threshold) # Check if the collision is out of bounds if not self.helpers.is_within_bounds( rocket_location_hit) or not self.helpers.is_within_bounds( projectile_location_hit): continue dist2collision = rocket_location.distance2(rocket_location_hit) try: avoidance_strength = 1 / (min_dist * dist2collision) except ZeroDivisionError: avoidance_strength = float("inf") avoidance_angle = (rocket_location_min_dist - projectile_location_min_dist).angle intersecting_projectile_avoidance.append( PolarCoordinate(avoidance_strength, avoidance_angle).pol2cart()) return (average(intersecting_projectile_avoidance) if intersecting_projectile_avoidance else Coordinate(0.0, 0.0))
def get_rocket_ends(self): rocket_location = self.history.rocket.location rocket_angle = self.history.rocket.angle rocket_length = self.parameters.rocket.length relative_rocket_end = PolarCoordinate( rocket_length / 2, rocket_angle ).pol2cart() rocket_front_location = rocket_location + relative_rocket_end rocket_rear_location = rocket_location - relative_rocket_end return rocket_front_location, rocket_rear_location
def _calc_projectile_avoidance(self): rocket_location = self.history.rocket.location projectile_avoidance = [] for projectile in self.history.active_projectiles: delta = rocket_location - self.helpers.calc_projectile_location( projectile) avoidance_strength = 1 / (delta.magnitude - self.parameters.rocket.target_radius) projectile_avoidance.append( PolarCoordinate(avoidance_strength, delta.angle).pol2cart()) return (average(projectile_avoidance) if projectile_avoidance else Coordinate(0.0, 0.0))
def _calc_obstacle_avoidance(self): rocket_location = self.history.rocket.location obstacle_avoidance = [] for obstacle in self.parameters.environment.obstacles: delta = rocket_location - obstacle.location avoidance_strength = 1 / (delta.magnitude - obstacle.radius - self.parameters.rocket.target_radius) obstacle_avoidance.append( PolarCoordinate( avoidance_strength, delta.angle, ).pol2cart()) return (average(obstacle_avoidance) if obstacle_avoidance else Coordinate(0.0, 0.0))
def plot_turret_barrel(self): barrel_length = ( self.visual.barrel_length_turret_radius_ratio * self.parameters.turret.radius ) turret_location = self.parameters.turret.location turret_angle = self.history.turret.angle relative_barrel_tip_location = PolarCoordinate( barrel_length, turret_angle ).pol2cart() barrel_tip_location = turret_location + relative_barrel_tip_location self.turret_barrel.set_data( [turret_location.x, barrel_tip_location.x], [turret_location.y, barrel_tip_location.y], )
def get_engine_bridge_ends(self): _, rocket_rear_location = self.get_rocket_ends() rocket_length = self.parameters.rocket.length engine_bridge_width = ( self.visual.rocket_length_engine_bridge_width_ratio * rocket_length ) rocket_angle = self.history.rocket.angle perpendicular_angle = normalise_angle(rocket_angle + math.pi / 2) relative_engine_end = PolarCoordinate( engine_bridge_width / 2, perpendicular_angle ).pol2cart() engine_bridge_left_location = rocket_rear_location + relative_engine_end engine_bridge_right_location = rocket_rear_location - relative_engine_end return engine_bridge_left_location, engine_bridge_right_location
def _calc_turret_attraction(self): min_turret_pull = 0.01 max_turret_pull = 0.1 attraction_angle = self.controller_helpers.calc_angle2turret_relative2rocket( ) dist2turret = self.controller_helpers.calc_dist_between_rocket_and_turret( ) turret_radius = self.parameters.turret.radius rocket_radius = self.parameters.rocket.target_radius attraction_strength = 1 / (dist2turret - rocket_radius - turret_radius) clamped_attraction_strength = self.clamp(attraction_strength, min_turret_pull, max_turret_pull) return PolarCoordinate(clamped_attraction_strength, attraction_angle).pol2cart()
def _calc_within_buffer_obstacle_avoidance(self, safety_factor=2.0): rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() within_buffer_obstacle_avoidance = [] for obstacle in self.parameters.environment.obstacles: rocket2obstacle = RelativeObjects(rocket_location, obstacle.location, rocket_velocity) ( min_dist, _, (rocket_location_min_dist, _), ) = rocket2obstacle.minimum_distance_between_objects() buffer = safety_factor * (self.parameters.rocket.target_radius + obstacle.radius) if min_dist > buffer: continue # Rocket doesn't come within buffer output = rocket2obstacle.time_objects_first_within_distance(buffer) if output: # Rocket is currently outside buffer time_rocket_enter_buffer, (rocket_location_enter_buffer, _) = output if not self.helpers.is_within_bounds( rocket_location_enter_buffer): continue # Rocket will be out of bounds before it enters buffer try: avoidance_strength = 1 / min_dist except ZeroDivisionError: avoidance_strength = float("inf") avoidance_angle = (rocket_location_min_dist - obstacle.location).angle within_buffer_obstacle_avoidance.append( PolarCoordinate(avoidance_strength, avoidance_angle).pol2cart()) return (average(within_buffer_obstacle_avoidance) if within_buffer_obstacle_avoidance else Coordinate(0.0, 0.0))
def _calc_intersecting_obstacle_avoidance(self): rocket_location = self.history.rocket.location rocket_velocity = self.physics.calc_rocket_velocity() intersecting_obstacle_avoidance = [] for obstacle in self.parameters.environment.obstacles: rocket2obstacle = RelativeObjects(rocket_location, obstacle.location, rocket_velocity) ( min_dist, _, (rocket_location_min_dist, _), ) = rocket2obstacle.minimum_distance_between_objects() threshold = self.parameters.rocket.target_radius + obstacle.radius if min_dist <= threshold and self.helpers.is_within_bounds( rocket_location_min_dist): _, ( rocket_location_thresh_dist, _, ) = rocket2obstacle.time_objects_first_within_distance( threshold) dist2threshold = rocket_location.distance2( rocket_location_thresh_dist) try: avoidance_strength = obstacle.radius / (min_dist * dist2threshold) except ZeroDivisionError: avoidance_strength = float("inf") avoidance_angle = (rocket_location_min_dist - obstacle.location).angle intersecting_obstacle_avoidance.append( PolarCoordinate(avoidance_strength, avoidance_angle).pol2cart()) return (average(intersecting_obstacle_avoidance) if intersecting_obstacle_avoidance else Coordinate(0.0, 0.0))
def _calc_firing_path_avoidance(self): rocket_location = self.history.rocket.location turret_location = self.parameters.turret.location recharge_factor = self._calc_recharge_factor() rotation_factor = self._calc_rotation_factor() turret_angle = self.history.turret.angle gradient = math.tan(turret_angle) y_intercept = turret_location.y - gradient * turret_location.x y_value = gradient * rocket_location.x + y_intercept avoidance_angle = normalise_angle( turret_angle + (1 if rocket_location.y > y_value else -1) * math.pi / 2) min_dist_rocket2path = self.calc_minimum_distance_from_location2line( rocket_location, gradient, y_intercept) dist_rockt2projectile = ( self.controller_helpers.calc_dist_between_rocket_and_turret()) return PolarCoordinate( rotation_factor * recharge_factor / (min_dist_rocket2path * dist_rockt2projectile), avoidance_angle, ).pol2cart()
def calc_projectile_velocity(self, projectile): angle = projectile.firing_angle velocity = self.parameters.turret.projectile_speed return PolarCoordinate(velocity, angle).pol2cart()