def simple_aim(position: Vector3, yaw: float, target: Vector3) -> float: pos_to_target = target - position facing = Vector3(math.cos(yaw), math.sin(yaw), 0) self_right = Vector3.cross_product(facing, Vector3(0, 0, 1)) if Vector3.dot_product(self_right, pos_to_target) < 0: return 1.0 else: return -1.0
def arrive_on_time(position: Vector3, velocity: Vector3, target: Vector3, time_taken: float) -> SimpleControllerState: to_target = target - position distance = to_target.magnitude() average_speed = distance / (time_taken + 0.0000001) current_speed = velocity.magnitude() target_speed = (1 - SPEED_MATCH) * current_speed + SPEED_MATCH * average_speed controller = SimpleControllerState() if current_speed < target_speed: controller.throttle = 1 controller.boost = target_speed > 1410 else: controller.boost = False if current_speed - target_speed > 75: controller.throttle = -1 else: controller.throttle = 0 if current_speed < 100: controller.throttle = 0.2 return controller
def decide_step(self, packet: GameTickPacket) -> BaseStep: # If the ball is going to land on our side, go and dribble it. # If the is ball on their side, hover over where the most damaged areas are on our side. # If the bot has possession of the ball and is aiming at the other side, dodge to flick it to the other side. ball = PhysicsObject(packet.game_ball.physics) bot = PhysicsObject(packet.game_cars[self.agent.index].physics) ball_landing, _ = predict_landing_pos_time(ball.location, ball.velocity) ball_landing_on_our_side = (self.agent.team == 0 and ball_landing.y < 0 ) or (self.agent.team == 1 and ball_landing.y > 0) # Dodge if dodging is in progress and it is not going to expire. Else, expire dodge_step if it isn't already. if self.dodge_step is not None: # Is dodging in progress? if self.dodge_step.get_output( packet) is not None: # Is it going to expire this frame? return self.dodge_step else: self.dodge_step = None # Expire dodge_step if ball_landing_on_our_side: # If carrying the ball if Vector3.distance(ball.location, bot.location) < 300: # If the bot is facing the opponents' side, dodge into the ball. Else, dribble it. # if (1/4*math.pi < bot.rotation.z < 3/4*math.pi) if self.agent.team == 0 else (-3/4*math.pi < bot.rotation.z < -1/4*math.pi): # # Instantiate a new DodgeStep if the previous one expired # if self.dodge_step is None: # self.dodge_step = DodgeStep(self.agent, ball.location) # return self.dodge_step return DribbleStep(self.agent, ball.location) return SimpleDribbleStep(self.agent) else: # Stay on our side if the ball is on the opponents' side return HoverStep(self.agent)
def get_tile_average(packet: GameTickPacket, field_info: FieldInfoPacket) -> Vector3: num_tiles = 70 # Don't hard code this. It was like this because it was giving errors. sum_x = 0 sum_y = 0 sum_z = 0 total_weight = 0 weight_multiplier = 2 # tested 2 and 3, 2 seems better for num_tile in range(num_tiles): tile_weight = packet.dropshot_tiles[ num_tile].tile_state**weight_multiplier tile_x = field_info.goals[num_tile].location.x * tile_weight tile_y = field_info.goals[num_tile].location.y * tile_weight tile_z = field_info.goals[num_tile].location.z * tile_weight sum_x += tile_x sum_y += tile_y sum_z += tile_z total_weight += tile_weight median_x = sum_x / total_weight median_y = sum_y / total_weight median_z = sum_z / total_weight return Vector3(median_x, median_y, median_z)
def __init__(self, agent: BaseAgent, zone: Zone): super().__init__(agent) self.steps: List[BaseStep] = [] self.sequential = False self.zone: Zone = zone self.area: Vector3 = Vector3(2500, 2250, 0) if zone == Zone.FOUR: self.area.x *= -1 if self.agent.team == 1: # Orange team self.area.y *= -1
def __choose_kickoff_plan(self, packet: GameTickPacket) -> Plan: is_on_diagonal = False teammate_on_diagonal = [] bot_loc = Vector3(packet.game_cars[self.agent.index].physics.location) # For every bot in our team for i in range(3 * self.agent.team, 3 * (self.agent.team + 1)): location = packet.game_cars[i].physics.location # We are using ranges instead of exact values because the game engine will not always have the exact value. if 1860 < abs(location.x) < 1870 and 2375 < abs(location.y) < 2385: if i == self.agent.index: is_on_diagonal = True else: teammate_on_diagonal.append(True) # On a kickoff, the bot goes to the ball if: # - It's the only one on a diagonal kickoff # - Or if the bot is on the left for blue, or the right for orange # (The second point is arbitrary but it's a good way to not double commit on the ball on kickoff) # # If it's not going for kickoff and it's the closest to the other side compared to the other non-kickoff bot, # it will go to the opponent's side and chill there waiting for the ball to be passed to it. # # The remaining bot will stay on its side. team_side_y = 1200 * (1 if self.agent.team else -1) if is_on_diagonal: if True not in teammate_on_diagonal: self.zone = Zone.THREE return DribblePlan(self.agent, Vector3(packet.game_ball.physics.location)) else: if bot_loc.x > 0: self.zone = Zone.THREE return DribblePlan( self.agent, Vector3(packet.game_ball.physics.location)) else: self.zone = Zone.FOUR opponent_side = Vector3(bot_loc.x, -team_side_y, bot_loc.z) return MovePlan(self.agent, opponent_side) else: if teammate_on_diagonal.count(True) == 2: self.zone = Zone.ONE_AND_TWO team_side = Vector3(bot_loc.x, team_side_y, bot_loc.z) return MovePlan(self.agent, team_side) else: if bot_loc.x > 0: self.zone = Zone.ONE_AND_TWO team_side = Vector3(bot_loc.x, team_side_y, bot_loc.z) return MovePlan(self.agent, team_side) else: self.zone = Zone.FOUR opponent_side = Vector3(bot_loc.x, -team_side_y, bot_loc.z) return MovePlan(self.agent, opponent_side)
def predict_landing_pos_time(position: Vector3, velocity: Vector3) -> Tuple[Vector3, float]: distance_ball_to_ground = GROUND_Z_AXIS - position.z a = velocity.z**2 / GRAVITY**2 b = 2 * distance_ball_to_ground / GRAVITY quadratic = math.sqrt(a - b) flight_time = velocity.z / GRAVITY + quadratic distance_covered_x = velocity.x * flight_time distance_covered_y = velocity.y * flight_time landing_pos = position + Vector3(distance_covered_x, distance_covered_y, distance_ball_to_ground) return landing_pos, flight_time
def get_ground_bounces(path: BallPrediction) -> List[Tuple[Vector3, float]]: ground_bounces: List[Tuple[Vector3, float]] = [] for i in range(1, path.num_slices): prev_ang_v = path.slices[i - 1].physics.angular_velocity prev_norm_ang_vel = (math.sqrt(prev_ang_v.x**2 + prev_ang_v.y**2 + prev_ang_v.z**2)) current_slice = path.slices[i] current_ang_v = current_slice.physics.angular_velocity current_norm_ang_vel = (math.sqrt(current_ang_v.x**2 + current_ang_v.y**2 + current_ang_v.z**2)) if prev_norm_ang_vel != current_norm_ang_vel and current_slice.physics.location.z < 125: ground_bounces.append((Vector3(current_slice.physics.location), current_slice.game_seconds)) return ground_bounces
def __init__(self, physics: game_data_struct.Physics): self.location: Vector3 = Vector3(physics.location) self.velocity: Vector3 = Vector3(physics.velocity) self.rotation: Vector3 = Vector3(physics.rotation) self.angular_velocity: Vector3 = Vector3(physics.angular_velocity)