def boost_steal(self, controls, car_location, my_car, ball_location): active_boosts = [ boost for boost in self.boost_pad_tracker.get_full_boosts() if boost.is_active == True ] car_x = int(car_location.x) car_y = int(car_location.y) boost_distances = [] for boost in active_boosts: boost_x = int(boost.location.x) boost_y = int(boost.location.y) distance_from_boost = abs(boost_x - car_x) + abs(boost_y - car_y) boost_distances.append(distance_from_boost) if len(active_boosts) == 0: controls.steer = steer_toward_target(my_car, ball_location) controls.throttle = 1.0 else: boost_index = boost_distances.index(min(boost_distances)) boost_location = active_boosts[boost_index].location controls.steer = steer_toward_target(my_car, boost_location) controls.throttle = 1.0
def goalie(): target_location = car_location # Roll back onto the wheels if abs(car_rotation.roll) >= math.pi * 3 / 4: override = self.jump_once(packet) # Prepare for a save if sign(car_location.y) == -sign(send_location.y) and abs( car_location.y) >= abs(send_location.y): target_location = car_location - Vec3(0, send_location.y, 0) if car_velocity.length() >= 850: controls.throttle = -1 else: if Vec3(car_velocity.x, car_velocity.y, 0).length() >= 250: override = self.reverse_flip(packet) else: controls.pitch = 0 controls.roll = 0 if (not math.pi * 0.4 <= abs(car_rotation.yaw) <= math.pi * 0.6 or sign(car_rotation.yaw) == -sign(send_location.y)) and abs( car_velocity.z) <= 1: override = self.jump_once(packet) controls.yaw = clamp( steer_toward_target(my_car, send_location) - my_car.physics.angular_velocity.z, -1, 1) controls.throttle = 0 # Drive into the goal unless it's already done so else: target_location = defend() return target_location
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: """ This function will be called by the framework many times per second. This is where you can see the motion of the ball, etc. and return controls to drive your car. """ # This is good to keep at the beginning of get_output. It will allow you to continue # any sequences that you may have started during a previous call to get_output. if self.active_sequence and not self.active_sequence.done: return self.active_sequence.tick(packet) self.spike_watcher.read_packet(packet) ball_prediction = self.get_ball_prediction_struct() # Example of predicting a goal event predicted_goal = find_future_goal(ball_prediction) goal_text = "No Goal Threats" if predicted_goal: goal_text = f"Goal in {predicted_goal.time - packet.game_info.seconds_elapsed:.2f}s" my_car = packet.game_cars[self.index] car_velocity = Vec3(my_car.physics.velocity) # Example of using a sequence # This will do a front flip if the car's velocity is between 550 and 600 if 550 < car_velocity.length() < 600: self.active_sequence = Sequence([ ControlStep(0.05, SimpleControllerState(jump=True)), ControlStep(0.05, SimpleControllerState(jump=False)), ControlStep(0.2, SimpleControllerState(jump=True, pitch=-1)), ControlStep(0.8, SimpleControllerState()), ]) return self.active_sequence.tick(packet) # Example of using the spike watcher. # This will make the bot say I got it! when it spikes the ball, # then release it 2 seconds later. if self.spike_watcher.carrying_car == my_car: if self.spike_watcher.carry_duration == 0: self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Information_IGotIt) elif self.spike_watcher.carry_duration > 2: return SimpleControllerState(use_item=True) # Example of doing an aerial. This will cause the car to jump and fly toward the # ceiling in the middle of the field. if my_car.boost > 50 and my_car.has_wheel_contact: self.start_aerial(Vec3(0, 0, 2000), packet.game_info.seconds_elapsed + 4) # If nothing else interesting happened, just chase the ball! ball_location = Vec3(packet.game_ball.physics.location) self.controller_state.steer = steer_toward_target( my_car, ball_location) self.controller_state.throttle = 1.0 # Draw some text on the screen draw_debug(self.renderer, [goal_text]) return self.controller_state
def demo(): nearest = None best_time = math.inf last = True for i in range(len(packet.game_cars)): if packet.game_cars[i].team != self.team and Vec3( packet.game_cars[i].physics.location).z > 0: time_taken = (Vec3(packet.game_cars[i].physics.location) - car_location).length() if time_taken < best_time: best_time = time_taken nearest = packet.game_cars[i] # Get location target_location = Vec3( nearest.physics.location) + Vec3(nearest.physics.velocity) * ( (Vec3(nearest.physics.location) - car_location).length() - 30) * safe_div(car_velocity.length()) controls.throttle = 1 controls.boost = abs(steer_toward_target( my_car, target_location)) <= 0.1 and car_velocity.length() < 2200 self.renderer.draw_line_3d(car_location, target_location, self.renderer.black()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.black(), centered=True) return target_location
def move_towards_point(self, my_car, point, boost: bool) -> SimpleControllerState: # Set the final controls based off of above decision making controls = SimpleControllerState() controls.steer = steer_toward_target(my_car, point) controls.throttle = 1.0 if boost: controls.boost = True return controls
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: """ This function will be called by the framework many times per second. This is where you can see the motion of the ball, etc. and return controls to drive your car. """ # Keep our boost pad info updated with which pads are currently active self.boost_pad_tracker.update_boost_status(packet) # This is good to keep at the beginning of get_output. It will allow you to continue # any sequences that you may have started during a previous call to get_output. if self.active_sequence is not None and not self.active_sequence.done: controls = self.active_sequence.tick(packet) if controls is not None: return controls # Gather some information about our car and the ball my_car = packet.game_cars[self.index] car_location = Vec3(my_car.physics.location) car_velocity = Vec3(my_car.physics.velocity) ball_location = Vec3(packet.game_ball.physics.location) nearest_boost_loc = self.get_nearest_boost(car_location) # By default we will chase the ball, but target_location can be changed later target_location = nearest_boost_loc # if car_location.dist(ball_location) > 1500: # # We're far away from the ball, let's try to lead it a little bit # ball_prediction = self.get_ball_prediction_struct() # This can predict bounces, etc # ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2) # # # ball_in_future might be None if we don't have an adequate ball prediction right now, like during # # replays, so check it to avoid errors. # if ball_in_future is not None: # target_location = Vec3(ball_in_future.physics.location) # self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan()) # Draw some things to help understand what the bot is thinking self.renderer.draw_line_3d(car_location, target_location, self.renderer.white()) self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True) if 750 < car_velocity.length() < 800: # We'll do a front flip if the car is moving at a certain speed. return self.begin_front_flip(packet) controls = SimpleControllerState() controls.steer = steer_toward_target(my_car, target_location) controls.throttle = 1.0 controls.boost = True controls.handbrake = True # You can set more controls if you want, like controls.boost. return controls
def go_towards_own_goal(self, controls, my_car, car_location, ball_location): """ Goes towards own goal and changes back to ball chasing when a bit away from the ball """ self.renderer.draw_string_3d(car_location, 1, 1, "\nGoing towards own goal", self.renderer.red()) info = self.get_field_info() own_goal_vec = info.goals[self.team].location own_goal_location = Vec3(own_goal_vec) controls.steer = steer_toward_target(my_car, own_goal_location) controls.throttle = 1.0 # goes back to ball chase state if far enough away from the ball if car_location.dist(ball_location) > 1000 or car_location.dist(own_goal_location) < 4000: self.bot_state = 0
def ball_chase(self, controls, my_car, car_location, car_velocity, ball_location, packet): if car_location.dist(ball_location) > 1500: # We're far away from the ball, let's try to lead it a little bit ball_prediction = self.get_ball_prediction_struct( ) # This can predict bounces, etc ball_in_future = find_slice_at_time( ball_prediction, packet.game_info.seconds_elapsed + 2) target_location = Vec3(ball_in_future.physics.location) self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan()) else: target_location = ball_location controls.steer = steer_toward_target(my_car, ball_location) controls.throttle = 1.0 self.manage_speed(packet, controls, my_car, car_velocity)
def front_flip_kickoff(self, my_car, car_location, car_velocity, ball_location, controls, packet): self.send_quick_chat( team_only=False, quick_chat=QuickChatSelection.Information_Incoming) controls.steer = steer_toward_target(my_car, ball_location) controls.throttle = 1.0 controls.boost = True distance_from_ball = car_location.dist(ball_location) # tweak these settings so the first and second flips go off at the right time if 750 < car_velocity.length() < 900: self.begin_front_flip(packet) if distance_from_ball <= 1000: self.begin_front_flip(packet)
def retreat_to_goal(self, controls, packet, my_car, car_location, car_velocity): """ Makes the bot retreat back to the goal and only change back to another state when it's close to the goal """ self.renderer.draw_string_3d(car_location, 1, 1, "\nRetreating to goal", self.renderer.red()) info = self.get_field_info() own_goal_vec = info.goals[self.team].location own_goal_location = Vec3(own_goal_vec) controls.steer = steer_toward_target(my_car, own_goal_location) controls.throttle = 1.0 if not my_car.is_super_sonic and car_velocity.length() > 200 and car_location.dist(own_goal_location) > 4500: controls.boost = True # change back to ball chasing if distance to goal is small self.renderer.draw_string_3d(car_location, 1, 1, f"\n\nDist to goal {car_location.dist(own_goal_location)}", self.renderer.white()) if car_location.dist(own_goal_location) < 4000: self.bot_state = 0
def ball_chase(self, controls, packet, my_car, car_velocity, car_location, target_location, ball_location, relative, time_to_target, time_to_floor, orientation): """ Makes the bot chase the ball unless some conditions are valid """ # retreat to own goal if the ball is a lot closer to our goal than we are info = self.get_field_info() own_goal_vec = info.goals[self.team].location own_goal_location = Vec3(own_goal_vec) if ball_location.dist(own_goal_location) + 1000 < car_location.dist(own_goal_location) and car_location.dist(own_goal_location) > 4000: self.bot_state = 1 elif own_goal_vec.y > 5000 and car_location.y + 100 < target_location.y: # BLUE self.bot_state = 2 elif own_goal_vec.y < -5000 and car_location.y > target_location.y + 100: # ORANGE self.bot_state = 2 self.renderer.draw_string_3d(car_location, 1, 1, "\nBall chasing", self.renderer.red()) # makes the bots shoot towards the goal target_location = self.ball_towards_goal_location(target_location, own_goal_location, car_location, ball_location) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.red(), centered=True) self.renderer.draw_line_3d(car_location, target_location, self.renderer.red()) controls.steer = steer_toward_target(my_car, target_location) controls.throttle = 1.0 # You can set more controls if you want, like controls.boost. # angle to ball car_to_ball = Vec3(ball_location.x - car_location.x, ball_location.y - car_location.y, ball_location.z - car_location.z) angle = math.degrees(orientation.forward.ang_to(car_to_ball)) # boost if angle < 20 and not my_car.is_super_sonic: controls.boost = True # try to turn around quickly if angle > 160 and relative.x < -2000: self.begin_half_flip(packet) elif angle > 40: controls.handbrake = True elif 1000 < car_velocity.length() and angle < 90 and car_to_ball.length() < 400 and relative.z < 200: # We'll do a front flip if the car is moving at a certain speed. return self.begin_front_flip(packet, angle, orientation.right.length())
def tick(self, packet: GameTickPacket) -> StepResult: car = packet.game_cars[self.index] seconds_till_arrival = self.arrival_time - packet.game_info.seconds_elapsed if seconds_till_arrival <= 0: return StepResult(SimpleControllerState(), done=True) current_speed = Vec3(car.physics.velocity).length() avg_speed_needed = Vec3(car.physics.location).flat().dist( self.target.flat()) / seconds_till_arrival steering = steer_toward_target(car, self.target) controls = SimpleControllerState( steer=steering, throttle=1 if avg_speed_needed > current_speed else 0, boost=avg_speed_needed > current_speed and avg_speed_needed > MAX_SPEED_WITHOUT_BOOST) ready_to_jump = abs( steering) < 0.1 and current_speed / avg_speed_needed > 0.7 return StepResult(controls, done=ready_to_jump)
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: # Get currently active boost pad info self.boost_pad_tracker.update_boost_status(packet) # Continue sequences from previous call if self.active_sequence and not self.active_sequence.done: controls = self.active_sequence.tick(packet) if controls is not None: return controls # Gather information about car and ball my_car = packet.game_cars[self.index] car_location = Vec3(my_car.physics.location) car_velocity = Vec3(my_car.physics.velocity) ball_location = Vec3(packet.game_ball.physics.location) if car_location.dist(ball_location) > 1500: # Set path of car to future ball location ball_prediction = self.get_ball_prediction_struct() # This can predict bounces, etc ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2) target_location = Vec3(ball_in_future.physics.location) self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan()) else: target_location = ball_location # Draw rendering lines self.renderer.draw_line_3d(car_location, target_location, self.renderer.white()) self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True) # Front flip if car is moving at a certain speed if 750 < car_velocity.length() < 800: return self.begin_front_flip(packet) controls = SimpleControllerState() controls.steer = steer_toward_target(my_car, target_location) controls.throttle = 1.0 return controls
def get_controls(self, car_state: CarState, car: Car): controls = SimpleControllerState() target_Vec3 = Vec3(self.location[0], self.location[1], self.location[2]) if angle_between(self.location - to_vec3(car_state.physics.location), car.forward()) > pi / 2: controls.boost = False controls.handbrake = True elif angle_between(self.location - to_vec3(car_state.physics.location), car.forward()) > pi / 4: controls.boost = False controls.handbrake = False else: controls.boost = self.boost controls.handbrake = False # Be smart about not using boost at max speed # if Vec3(car.physics.velocity).length() > self.boost_analysis.frames[-1].speed - 10: # controls.boost = False controls.steer = steer_toward_target(car_state, target_Vec3) controls.throttle = 1 return controls
def get_output(self, parsed_packet: ParsedPacket, packet: rl.GameTickPacket, agent: DrawingAgent) -> SimpleControllerState: # Gather some information about our car and the ball my_car = parsed_packet.my_car car_location = my_car.physics.location car_velocity = my_car.physics.velocity ball_location = parsed_packet.ball.physics.location ball_velocity = parsed_packet.ball.physics.velocity ball_prediction = agent.get_ball_prediction_struct() slices = list(map(lambda x : Vector(x.physics.location), ball_prediction.slices)) agent.draw_circle(parsed_packet.my_car.physics.location, self.STOP_AND_WAIT_RADIUS, agent.renderer.white(), False, 0) my_car_ori = Orientation(my_car.physics.rotation) car_to_ball = ball_location - car_location car_to_ball_angle = my_car_ori.forward.ang_to(car_to_ball) self.chooseContactPoint(ball_prediction.slices, my_car.physics, agent) if(self.contactSlice == None): flip_point = Vector(find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 1).physics.location) else: flip_point = Vector(self.contactSlice.physics.location) target_location = flip_point if not agent.prev_seq_done and agent.WRITE_FLIP_PHYSICS_TO_DB: agent.prev_seq_done = True agent.write_flip_physics(agent.current_flip_physics) if car_location.dist(flip_point) < 300 and self.contactSlice != None: if agent.WRITE_FLIP_PHYSICS_TO_DB == True: # record physics info at beginning of flip agent.current_flip_physics = {} # TODO: add slices here agent.current_flip_physics["car_ball_angle"] = car_to_ball_angle agent.current_flip_physics["car_ball_dist"] = car_location.dist(ball_location) agent.current_flip_physics["car_velo_x"] = car_velocity[0] agent.current_flip_physics["car_velo_y"] = car_velocity[1] agent.current_flip_physics["car_velo_z"] = car_velocity[2] agent.current_flip_physics["car_velo_mag"] = car_velocity.length() agent.current_flip_physics["car_loc_x"] = car_location[0] agent.current_flip_physics["car_loc_y"] = car_location[1] agent.current_flip_physics["car_loc_z"] = car_location[2] agent.current_flip_physics["ball_velo_x"] = ball_velocity[0] agent.current_flip_physics["ball_velo_y"] = ball_velocity[1] agent.current_flip_physics["ball_velo_z"] = ball_velocity[2] agent.current_flip_physics["ball_velo_mag"] = ball_velocity.length() agent.current_flip_physics["ball_loc_x"] = ball_location[0] agent.current_flip_physics["ball_loc_y"] = ball_location[1] agent.current_flip_physics["ball_loc_z"] = ball_location[2] agent.current_flip_physics["contact"] = False return agent.begin_front_flip(packet) # Draw target to show where the bot is attempting to go if (self.contactSlice == None): agent.draw_line_with_rect(car_location, target_location, 8, agent.renderer.cyan()) else: contactPt = Vector(self.contactSlice.physics.location) agent.draw_line_with_rect(contactPt, contactPt + get_post_collision_velocity(my_car.physics, Physics(self.contactSlice.physics)), 1, agent.renderer.red()) angle = get_angle(parsed_packet.my_car.physics.rotation, parsed_packet.my_car.physics.location, target_location) agent.write_string_2d(1000, 1000, f"{angle}") # Set the final controls based off of above decision making controls = SimpleControllerState() controls.steer = steer_toward_target(my_car, target_location) if(self.contactSlice != None or car_location.dist(ball_location) > self.STOP_AND_WAIT_RADIUS): controls.throttle = 1.0 else: controls.throttle = -1 if (angle > self.POWERSLIDE_THRESHOLD): controls.handbrake = True # You can set more controls if you want, like controls.boost. return controls
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.boost_pad_tracker.update_boost_status(packet) if self.active_sequence is not None and not self.active_sequence.done: controls = self.active_sequence.tick(packet) if controls is not None: return controls # Get the distance from the nearest surface (walls, floor, roof, etc.) def distance_from_surface(pos): min_dist = math.inf nearest_surface = pos if min_dist > pos.z: min_dist = pos.z nearest_surface = Vec3(pos.x, pos.y, 0) if min_dist > self.map_size[1] - abs(pos.x): min_dist = self.map_size[1] - abs(pos.x) nearest_surface = Vec3( sign(pos.x) * self.map_size[1], pos.y, pos.z) if min_dist > self.map_size[0] - abs(pos.y): min_dist = self.map_size[0] - abs(pos.y) nearest_surface = Vec3(pos.x, sign(pos.y) * self.map_size[0], pos.z) if min_dist > 99999 + (8064 - abs(pos.x) - abs(pos.y)) / math.sqrt(2): min_dist = (8064 - abs(pos.x) - abs(pos.y)) / math.sqrt(2) nearest_surface = Vec3(pos.x, sign(pos.y) * self.map_size[0], pos.z) return nearest_surface # Get the rate in which the object is moving away from the nearest surface def velocity_from_surface(pos, vel): val = pos - distance_from_surface(pos) if val.x != 0: return vel.x * sign(val.x) elif val.y != 0: return vel.y * sign(val.y) elif val.z != 0: return vel.z * sign(val.z) # Get the order within the team def distance_order(teams): nearest = 1 overall_nearest = 1 last = 0 ref = (car_location - ball_location).length( ) / (car_velocity.length() + 2300) + math.asin( (car_velocity * safe_div(car_velocity.length()) - ball_location * safe_div(ball_location.length())).length() / 2) * 3 / math.pi * 0 for i in range(len(packet.game_cars)): if (packet.game_cars[i].team != (-teams * packet.game_cars[self.index].team + (1 + teams) / 2) or teams == False ) and packet.game_cars[i].physics.location.z > 0: time_taken = ( Vec3(packet.game_cars[i].physics.location) - ball_location).length() / (Vec3(packet.game_cars[ i].physics.velocity).length() + 2300) + math.asin( (Vec3(packet.game_cars[i].physics.velocity) * safe_div( Vec3(packet.game_cars[i].physics.velocity ).length()) - ball_location * safe_div(ball_location.length())).length() / 2) * 3 / math.pi * 0 # When the car is further front than the POV if ref > time_taken: if ((Vec3(packet.game_cars[i].physics.location) + send_location).length() <= (ball_location + send_location).length() or (car_location + send_location).length() > (ball_location + send_location).length()): nearest += 1 overall_nearest += 1 last += 1 # Keep the full-time goal keeper if overall_nearest == last: nearest = overall_nearest # Prevent the division by 0 error return last, nearest # Find the best boost pads to use to refuel as fast as possible def find_best_boost_pads(): best_pad = None best_score = math.inf for i in range(len(self.get_field_info().boost_pads)): pad = self.get_field_info().boost_pads[i] if packet.game_boosts[ i].is_active == True or packet.game_boosts[i].timer <= ( Vec3(pad.location) - car_location).length() / 2300: score = (Vec3(pad.location) - car_location).length( ) * safe_div(car_velocity.length()) + math.sin( ((Vec3(pad.location) - car_location) / (Vec3(pad.location) - car_location).length() - car_velocity * safe_div(car_velocity.length()) ).length() / 2) * 3 / math.pi if pad.is_full_boost: score *= safe_div((50 - my_car.boost / 2) / 6) if score < best_score: best_score = score best_pad = pad return Vec3(best_pad.location) # Get the yaw based on position def get_yaw(x, y): a = math.acos(x / Vec3(x, y, 0).length()) if abs(a) < math.pi: return a * sign(y) else: return math.pi # Get the angle between two places def get_angle(p1, p2): d = (p1 * safe_div(p1.length()) - p2 * safe_div(p2.length())).length() angle = 2 * math.asin(d / 2) return angle # Determine when the car would intersect the ball assuming a speed def intersect_time(surface): t1 = 5 t2 = 5 best_spd = math.inf slowest = math.inf if surface == False: for i in range(1, 101): time_location = Vec3(predict_ball(i / 20).physics.location) if (time_location - car_location).length( ) * 20 / i <= car_velocity.length() and t1 == 5: t1 = i / 20 if (time_location - car_location).length() * 20 / i <= slowest: slowest = (time_location - car_location).length() * 20 / i t2 = i / 20 else: for i in range(1, 101): time_location = Vec3(predict_ball(i / 20).physics.location) if (distance_from_surface(time_location) - distance_from_surface(car_location)).length( ) * 20 / i <= car_velocity.length() and t1 == 5: t1 = i / 20 if (distance_from_surface(time_location) - distance_from_surface(car_location) ).length() * 20 / i <= slowest: slowest = (distance_from_surface(time_location) - distance_from_surface(car_location) ).length() * 20 / i t2 = i / 20 return t1, t2 # Determine when the car should jump def jump_ready(val): if val <= 300 and val > 92.75: delay = (2 * (val - 92.75) / 650)**0.5 return delay else: return 0 # Get the nearest player to the ball def nearest_player(teams, speed_offset): nearest = None best_time = math.inf last = True for i in range(len(packet.game_cars)): if (packet.game_cars[i].team != (-teams * packet.game_cars[self.index].team + (1 + teams) / 2) or teams == False) and Vec3( packet.game_cars[i].physics.location) != Vec3( 0, 0, 0): time_taken = (Vec3( packet.game_cars[i].physics.location ) - ball_location).length() / (Vec3( packet.game_cars[i].physics.velocity ).length() + speed_offset) + math.sin( (Vec3(packet.game_cars[i].physics.velocity) * safe_div( Vec3(packet.game_cars[i].physics.velocity).length( )) - ball_location * safe_div(ball_location.length())).length() / 2) * 3 / math.pi if time_taken < best_time: best_time = time_taken nearest = packet.game_cars[i] return nearest, best_time # Get the list of moments when the ball should be hit def opportunities(): li = [] prev_pos = ball_location for i in range(1, 101): time_location = predict_ball(i / 20) if time_location.z <= 300: li.append([ i / 20, (time_location - car_location).length() * 20 / i ]) prev_pos = time_location return li # ??? def plane_dist(pos, dist): if Vec3(pos.x, pos.y, 0).length() <= dist: return True elif Vec3(pos.x, 0, pos.z).length() <= dist: return True elif Vec3(0, pos.y, pos.z).length() <= dist: return True else: return False # Get the ball's position and velocity at a specific time def predict_ball(t): ball_in_future = find_slice_at_time( ball_prediction, packet.game_info.seconds_elapsed + t) if ball_in_future is not None: return ball_in_future else: return packet.game_ball # Divide numbers without division by 0 def safe_div(x): if x == 0: return math.inf else: return 1 / x # Return the direction of the value from 0 def sign(x): if x < 0: return -1 elif x > 0: return 1 else: return 0 # Return a value with limitations def clamp(x, m, M): if x < m: return m elif x > M: return M else: return x # Move the target location to straighten the ascent up walls def move_target_for_walls(pos1, pos2): up1 = distance_from_surface(pos1) up2 = distance_from_surface(pos2) new_pos = pos2 if up1.z == 0 and up2.z > 0: new_pos = Vec3(new_pos, 0, new_pos) + (up2 - pos2) * safe_div( (up2 - pos2).length()) * up2.z if up1.z > 0 and up2.z == 0 and pos1.z >= 30: if abs(up1.x) == self.map_size[1]: new_pos = Vec3(up1.x, up2.y, -abs(up2.x - up1.x)) elif abs(up1.y) == self.map_size[0]: new_pos = Vec3(up2.x, up1.y, -abs(up2.y - up1.y)) return new_pos # Actions # Use flip jumps to attack the ball def jump_attack(): dir_y = 0 dir_x = 0 if ((car_location + car_velocity / 5) - (ball_location + ball_velocity / 5)).length() <= 175: if (car_location + Vec3(car_velocity.y, -car_velocity.x, 0) * safe_div(car_velocity.length()) - ball_location).length() < (car_location - ball_location).length(): dir_x = -1 if (car_location + Vec3(-car_velocity.y, car_velocity.x, 0) * safe_div(car_velocity.length()) - ball_location).length() < (car_location - ball_location).length(): dir_x = 1 if (car_location + car_velocity / 5 - ball_location - ball_velocity / 5 ).length() <= (car_location - ball_location).length() - 50: dir_y = -1 dir_x *= sign(math.pi / 2 - get_angle(car_direction, car_velocity)) dir_y *= sign(math.pi / 2 - get_angle(car_direction, car_velocity)) override = self.flip(packet, dir_x, dir_y, not my_car.jumped) # Jump over cars to prevent collision def avoid_bump(): for i in range(len(packet.game_cars)): if i != self.index and packet.game_cars[ i].physics.location.z > 0: pos = car_location pos2 = Vec3(packet.game_cars[i].physics.location) vel = car_velocity vel2 = Vec3(packet.game_cars[i].physics.velocity) dist = (pos - pos2).length() on_course = False if dist > 40: if get_angle(pos2 - pos, vel) <= math.tan( math.sqrt(40**2 / (dist**2 - 40**2))): on_course = True else: on_course = True if on_course == True and dist <= 40 + (vel - vel2).length( ) / 2 and (vel.length() <= vel2.length() or packet.game_cars[i].team != self.team): self.jump_once(packet) # Modes def attack(): # Target target_ball = predict_ball(earliest_intersection) target_location = Vec3(target_ball.physics.location) target_location = target_location + ( target_location - send_location) / ( target_location - send_location).length() * 92.75 # Smoother wall transitions target_location = move_target_for_walls(car_location, target_location) jumping = jump_ready( (target_location - distance_from_surface(target_location)).length()) # Manage speed if velocity_from_surface( Vec3(target_ball.physics.location), Vec3(target_ball.physics.velocity)) >= 0 or (Vec3( target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length( ) <= 300 or target_ball.physics.location.y * sign( send_location.y) <= -self.map_size[0]: controls.throttle = 1 else: controls.throttle = 0 # Boost controls.boost = abs( steer_toward_target(my_car, target_location) ) <= 0.1 and car_velocity.length() < 2300 and ( (Vec3(target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length() <= 300 or velocity_from_surface(Vec3(target_ball.physics.location), Vec3(target_ball.physics.velocity)) >= 0) and car_index == 1 # Jump h = (Vec3(target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length() if jump_ready( (Vec3(target_ball.physics.location) - distance_from_surface(Vec3(target_ball.physics.location)) ).length()) >= earliest_intersection and steer_toward_target( my_car, target_location) < 1: controls.pitch = 0 controls.yaw = 0 controls.roll = 0 controls.jump = True controls.boost = False else: jump_attack() # Catch the ball when in the air if abs( target_location.z - car_location.z ) <= 92.75 * 0.75 and get_angle( target_location - car_location, car_velocity ) >= math.atan( 200 * safe_div(car_velocity.length()) ) and my_car.jumped == True and my_car.double_jumped == False and False: controls.yaw = sign( (target_location - car_location - Vec3(car_velocity.y, -car_velocity.x, car_velocity.z) ).length() - (target_location - car_location - Vec3(-car_velocity.y, car_velocity.x, car_velocity.z) ).length()) controls.jump = True # Draw self.renderer.draw_line_3d(car_location, target_location, self.renderer.red()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.red(), centered=True) return target_location def standby(): # Friendly/enemey if enemy_time >= friendly_time + 0.2: nearest_ref = nearest_friendly md = "friendly" else: nearest_ref = nearest_enemy md = "enemy" # Target if md == "enemy" or True: target_location = ball_location - ( Vec3(nearest_ref.physics.location) - ball_location) / ( Vec3(nearest_ref.physics.location) - ball_location).length() * (2500 + Vec3( nearest_ref.physics.velocity).length() * 5 / 2.3) target_location = Vec3( target_location.x, ball_location.y + (target_location.y - ball_location.y) * sign(target_location.y - ball_location.y) * -sign(send_location.y), target_location.z) else: target_location = ball_location - ( Vec3(nearest_ref.physics.location) - ball_location) / ( Vec3(nearest_ref.physics.location) - ball_location).length() * (2500 + Vec3( nearest_ref.physics.velocity).length() * 5 / 2.3) target_location = target_location + ( target_location - send_location) / ( target_location - send_location).length() * 927.5 # Walls if (distance_from_surface(target_location) - target_location).length() <= 300: target_location = distance_from_surface(target_location) target_location = move_target_for_walls( car_location, target_location) else: target_location = Vec3(target_location.x, target_location.y, 0) # Draw self.renderer.draw_line_3d(car_location, target_location, self.renderer.green()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.green(), centered=True) # Manage speed controls.boost = False controls.throttle = clamp( (target_location - car_location).length() / 1000, -1, 1) return target_location def refuel(): # Target target_location = find_best_boost_pads() # Draw self.renderer.draw_line_3d(car_location, target_location, self.renderer.green()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.green(), centered=True) # Speed controls.throttle = 1 controls.boost = False return target_location def goalie(): target_location = car_location # Roll back onto the wheels if abs(car_rotation.roll) >= math.pi * 3 / 4: override = self.jump_once(packet) # Prepare for a save if sign(car_location.y) == -sign(send_location.y) and abs( car_location.y) >= abs(send_location.y): target_location = car_location - Vec3(0, send_location.y, 0) if car_velocity.length() >= 850: controls.throttle = -1 else: if Vec3(car_velocity.x, car_velocity.y, 0).length() >= 250: override = self.reverse_flip(packet) else: controls.pitch = 0 controls.roll = 0 if (not math.pi * 0.4 <= abs(car_rotation.yaw) <= math.pi * 0.6 or sign(car_rotation.yaw) == -sign(send_location.y)) and abs( car_velocity.z) <= 1: override = self.jump_once(packet) controls.yaw = clamp( steer_toward_target(my_car, send_location) - my_car.physics.angular_velocity.z, -1, 1) controls.throttle = 0 # Drive into the goal unless it's already done so else: target_location = defend() return target_location def defend(): if not in_goal: target_ball = predict_ball(earliest_intersection) target_location = Vec3(target_ball.physics.location) nearest_surface = (target_location - car_location) / ( target_location - car_location).length() * 140 nearest_surface_r = Vec3(-nearest_surface.y, nearest_surface.x, nearest_surface.z) nearest_surface_l = Vec3(nearest_surface.y, -nearest_surface.x, nearest_surface.z) if False: side = -sign((nearest_surface_l - send_location).length() - (nearest_surface_r - send_location).length()) else: side = -sign(((nearest_surface_l - ball_location) - ball_velocity).length() - ((nearest_surface_r - ball_location) - ball_velocity).length()) nearest_surface = Vec3(-nearest_surface.y * side, nearest_surface.x * side, nearest_surface.z) if abs(target_location.x + nearest_surface.x) >= self.map_size[1] or get_angle( car_location - send_location, car_location - target_location ) > math.pi / 3 * 2 or ball_location.z > 130: target_location = -send_location else: target_location = target_location + nearest_surface / 140 * car_velocity.length( ) controls.boost = enemy_time < 1 and abs( steer_toward_target(my_car, target_location)) <= 0.1 # Jump h = (Vec3(target_ball.physics.location) - distance_from_surface(Vec3( target_ball.physics.location))).length() if jump_ready( h) >= earliest_intersection and steer_toward_target( my_car, target_location) < 1: controls.pitch = 0 controls.yaw = 0 controls.roll = 0 controls.jump = True controls.boost = False else: jump_attack() # Draw self.renderer.draw_line_3d(car_location, ball_location + nearest_surface, self.renderer.cyan()) self.renderer.draw_rect_3d(ball_location + nearest_surface, 8, 8, True, self.renderer.cyan(), centered=True) controls.throttle = 1 else: target_location = -send_location controls.throttle = 1 return target_location def recovery(): tx = (self.map_size[1] - car_location.x * sign(car_velocity.x)) * safe_div(car_velocity.x) ty = (self.map_size[0] - car_location.y * sign(car_velocity.y)) * safe_div(car_velocity.y) tt = 0 if car_location.z / 325 - (car_velocity.z / 650)**2 >= 0: tz = car_velocity.z / 650 + math.sqrt(car_location.z / 325 - (car_velocity.z / 650)**2) else: tz = car_velocity.z / 650 - math.sqrt(car_location.z / 325 + (car_velocity.z / 650)**2) if tx >= tz <= ty: controls.roll = clamp(-car_rotation.roll, -1, 1) controls.pitch = clamp(-car_rotation.pitch, -1, 1) tt = tz elif tx >= ty <= tz: point = (math.pi / 2 + sign(abs(car_rotation.yaw) - math.pi / 2) * math.pi / 2) * sign(car_rotation.yaw) controls.roll = clamp( math.pi / 2 * sign(car_velocity.y) * sign(abs(car_rotation.yaw) - math.pi / 2) - car_rotation.roll, -1, 1) controls.pitch = clamp(point - car_rotation.yaw, -1, 1) tt = ty draw_point = Vec3( car_location.x + car_velocity.x * tt, car_location.y + car_velocity.y * tt, car_location.z + car_velocity.z * tt - 325 * tt**2) self.renderer.draw_line_3d(car_location, draw_point, self.renderer.pink()) self.renderer.draw_rect_3d(draw_point, 8, 8, True, self.renderer.pink(), centered=True) # Variables my_car = packet.game_cars[self.index] car_location = Vec3(my_car.physics.location) car_velocity = Vec3(my_car.physics.velocity) car_rotation = my_car.physics.rotation car_direction = Vec3( math.cos(car_rotation.yaw) * math.cos(car_rotation.pitch), math.sin(car_rotation.yaw) * math.cos(car_rotation.pitch), math.sin(car_rotation.pitch)) ball_prediction = self.get_ball_prediction_struct() ball_location = Vec3(packet.game_ball.physics.location) ball_velocity = Vec3(packet.game_ball.physics.velocity) send_location = Vec3(0, sign(0.5 - self.team) * self.map_size[0], 0) earliest_intersection, easiest_intersection = intersect_time(True) team_size, car_index = distance_order(1) nearest_enemy, enemy_time = nearest_player(0, 460) nearest_friendly, friendly_time = nearest_player(0, 460) in_goal = (ball_location + send_location).length() > ( car_location + send_location).length() target_location = car_location mode = "" override = None # Controls controls = SimpleControllerState() # Half-flip to quickly turn if car_velocity.length() <= 500 and get_angle( car_velocity, target_location - car_location) >= math.pi / 3 * 2: override = self.reverse_flip(packet) # Assign role in the team if abs(send_location.y + Vec3(predict_ball(2).physics.location).y ) <= 1000 or abs(send_location.y + ball_location.y) <= 1000: if in_goal: mode = "Attack" else: mode = "Defense" else: if car_index == 1: if in_goal: mode = "Attack" else: mode = "Defense" elif car_index < team_size: if my_car.boost == 100 and car_index == 2: mode = "Standby" else: mode = "Refuel" else: mode = "Goalie" # Recovery if my_car.double_jumped: recovery() # Demolition if mode == "Demo": target_location = demo() # Attack the ball if mode == "Attack": avoid_bump() target_location = attack() controls.use_item = True # Stand by for hit if mode == "Standby": avoid_bump() target_location = standby() # Collect boost if mode == "Refuel": avoid_bump() target_location = refuel() # Retreat if mode == "Defense": avoid_bump() target_location = defend() # Goalie if mode == "Goalie": avoid_bump() target_location = goalie() controls.steer = steer_toward_target(my_car, target_location) # Draw if False: self.renderer.draw_string_2d( 800, 200, 1, 1, "X: " + str(packet.game_cars[1 - self.index].physics.location.x), self.renderer.white()) self.renderer.draw_string_2d( 800, 220, 1, 1, "Y: " + str(packet.game_cars[1 - self.index].physics.location.y), self.renderer.white()) self.renderer.draw_string_2d(1400, 200, 1, 1, "Map: " + str(self.map), self.renderer.white()) self.renderer.draw_string_2d( 50, 680 + car_index * 20 * (0.5 - self.team) * 2, 1, 1, "Noob Bot " + str(car_index) + ": " + str(mode), self.renderer.white()) self.renderer.draw_line_3d(target_location, distance_from_surface(target_location), self.renderer.yellow()) if override: return override else: return controls
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.boost_pad_tracker.update_boost_status(packet) if self.active_sequence is not None and not self.active_sequence.done: controls = self.active_sequence.tick(packet) if controls is not None: return controls def predict_ball(t): ball_in_future = find_slice_at_time( ball_prediction, packet.game_info.seconds_elapsed + t) if ball_in_future is not None: return ball_in_future else: return packet.game_ball def intersect_time(speed): best_spd = math.inf for i in range(1, 301): time_location = Vec3(predict_ball(i / 60).physics.location) if (time_location - car_location).length() * 60 / i <= speed: return i / 60 return 5 my_car = packet.game_cars[self.index] car_location = Vec3(my_car.physics.location) car_velocity = Vec3(my_car.physics.velocity) ball_location = Vec3(packet.game_ball.physics.location) ball_location_gs = Vector3(packet.game_ball.physics.location) ball_velocity = Vec3(packet.game_ball.physics.velocity) ball_prediction = self.get_ball_prediction_struct() target_location = ball_location send_location = Vec3(0, 10240 * (0.5 - self.team), 300) if car_location.z == 0: self.pos = car_location self.renderer.draw_line_3d(self.pos, (target_location - self.pos) / (target_location - self.pos).length() * self.travel_distance, self.renderer.white()) self.renderer.draw_string_3d(self.pos, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True) controls = SimpleControllerState() controls.steer = steer_toward_target(my_car, target_location) controls.throttle = 0 if packet.game_info.is_round_active == True: self.travel_distance += 2300 / 60 else: self.travel_distance = 0 if (self.pos - ball_location).length( ) <= self.travel_distance and ball_location.y / send_location.y <= 1: ball_velout = -ball_velocity v = -(ball_location - send_location) / ( ball_location - send_location).length() * 2300 tp = (ball_velout + v) / (ball_velout + v).length() * 2300 p = ball_location - tp / tp.length() * 100 self.travel_distance = 0 # Intentional weakness if random.random() <= 0.125: side = random.choice([1, -1]) p = ball_location + Vec3(-v.x * side, 0, v.z * side) / 2300 * 150 self.travel_distance = -11500 car_state = CarState( physics=Physics(location=Vector3(p.x, p.y, p.z), velocity=Vector3(v.x, v.y, v.z))) gs = GameState(cars={self.index: car_state}) self.set_game_state(gs) self.pos = Vec3(packet.game_cars[self.index].physics.location) elif packet.game_info.is_round_active == True and self.travel_distance >= 0: p = self.pos + (ball_location - self.pos) / ( ball_location - self.pos).length() * (self.travel_distance - 200) car_state = CarState(physics=Physics( location=Vector3(p.x, p.y, p.z), velocity=Vector3(0, 0, 0))) gs = GameState(cars={self.index: car_state}) self.set_game_state(gs) else: self.pos = Vec3(packet.game_cars[self.index].physics.location) if packet.game_info.is_round_active == False: self.send_quick_chat( team_only=False, quick_chat=QuickChatSelection.Compliments_WhatASave) return controls
def attack(): # Target target_ball = predict_ball(earliest_intersection) target_location = Vec3(target_ball.physics.location) target_location = target_location + ( target_location - send_location) / ( target_location - send_location).length() * 92.75 # Smoother wall transitions target_location = move_target_for_walls(car_location, target_location) jumping = jump_ready( (target_location - distance_from_surface(target_location)).length()) # Manage speed if velocity_from_surface( Vec3(target_ball.physics.location), Vec3(target_ball.physics.velocity)) >= 0 or (Vec3( target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length( ) <= 300 or target_ball.physics.location.y * sign( send_location.y) <= -self.map_size[0]: controls.throttle = 1 else: controls.throttle = 0 # Boost controls.boost = abs( steer_toward_target(my_car, target_location) ) <= 0.1 and car_velocity.length() < 2300 and ( (Vec3(target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length() <= 300 or velocity_from_surface(Vec3(target_ball.physics.location), Vec3(target_ball.physics.velocity)) >= 0) and car_index == 1 # Jump h = (Vec3(target_ball.physics.location) - distance_from_surface( Vec3(target_ball.physics.location))).length() if jump_ready( (Vec3(target_ball.physics.location) - distance_from_surface(Vec3(target_ball.physics.location)) ).length()) >= earliest_intersection and steer_toward_target( my_car, target_location) < 1: controls.pitch = 0 controls.yaw = 0 controls.roll = 0 controls.jump = True controls.boost = False else: jump_attack() # Catch the ball when in the air if abs( target_location.z - car_location.z ) <= 92.75 * 0.75 and get_angle( target_location - car_location, car_velocity ) >= math.atan( 200 * safe_div(car_velocity.length()) ) and my_car.jumped == True and my_car.double_jumped == False and False: controls.yaw = sign( (target_location - car_location - Vec3(car_velocity.y, -car_velocity.x, car_velocity.z) ).length() - (target_location - car_location - Vec3(-car_velocity.y, car_velocity.x, car_velocity.z) ).length()) controls.jump = True # Draw self.renderer.draw_line_3d(car_location, target_location, self.renderer.red()) self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.red(), centered=True) return target_location
def defend(): if not in_goal: target_ball = predict_ball(earliest_intersection) target_location = Vec3(target_ball.physics.location) nearest_surface = (target_location - car_location) / ( target_location - car_location).length() * 140 nearest_surface_r = Vec3(-nearest_surface.y, nearest_surface.x, nearest_surface.z) nearest_surface_l = Vec3(nearest_surface.y, -nearest_surface.x, nearest_surface.z) if False: side = -sign((nearest_surface_l - send_location).length() - (nearest_surface_r - send_location).length()) else: side = -sign(((nearest_surface_l - ball_location) - ball_velocity).length() - ((nearest_surface_r - ball_location) - ball_velocity).length()) nearest_surface = Vec3(-nearest_surface.y * side, nearest_surface.x * side, nearest_surface.z) if abs(target_location.x + nearest_surface.x) >= self.map_size[1] or get_angle( car_location - send_location, car_location - target_location ) > math.pi / 3 * 2 or ball_location.z > 130: target_location = -send_location else: target_location = target_location + nearest_surface / 140 * car_velocity.length( ) controls.boost = enemy_time < 1 and abs( steer_toward_target(my_car, target_location)) <= 0.1 # Jump h = (Vec3(target_ball.physics.location) - distance_from_surface(Vec3( target_ball.physics.location))).length() if jump_ready( h) >= earliest_intersection and steer_toward_target( my_car, target_location) < 1: controls.pitch = 0 controls.yaw = 0 controls.roll = 0 controls.jump = True controls.boost = False else: jump_attack() # Draw self.renderer.draw_line_3d(car_location, ball_location + nearest_surface, self.renderer.cyan()) self.renderer.draw_rect_3d(ball_location + nearest_surface, 8, 8, True, self.renderer.cyan(), centered=True) controls.throttle = 1 else: target_location = -send_location controls.throttle = 1 return target_location