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 follow_ball_on_ground(gi: GameInfo) -> Sequence: ball_loc = Vec3(gi.packet.game_ball.physics.location) ball_loc_flat = ball_loc.flat() ball_vel_flat = Vec3(gi.packet.game_ball.physics.velocity).flat() ball_ground_speed = ball_vel_flat.length() ideal_position = ball_loc_flat controls = SimpleControllerState( steer=gi.car.steer_toward_target(ideal_position) ) car_ground_speed = gi.car.velocity.flat().length() car_to_ball_dist = gi.car.location.flat().dist(ball_loc_flat) if car_to_ball_dist > 800: controls.throttle = 1.0 controls.boost = abs(controls.steer) < 0.2 and car_ground_speed < 2300 else: if car_ground_speed - ball_ground_speed > 525 and car_to_ball_dist < 500: controls.throttle = min(max((ball_ground_speed - car_ground_speed) / 3600, -1.0), 0) controls.boost = False else: controls.throttle = min(max((ball_ground_speed - car_ground_speed) / 525, 0), 1.0) controls.boost = ball_ground_speed - car_ground_speed > 992 if gi.car.location.flat().dist(ball_loc_flat) > 92.75 and ball_loc.z < 200: controls.throttle = min(1.0, controls.throttle + 0.1) return Sequence([SingleStep(controls)])
def go_nuts(gi: GameInfo) -> Sequence: ball_location = Vec3(gi.packet.game_ball.physics.location) if gi.car.location.flat().dist(ball_location.flat()) > 2000: # We're far away from the ball, let's try to lead it a little bit ball_prediction = gi.bot.get_ball_prediction_struct() # This can predict bounces, etc ball_in_future_location = Vec3(find_slice_at_time(ball_prediction, gi.packet.game_info.seconds_elapsed + 2).physics.location) target_location = ball_in_future_location.flat() + (ball_in_future_location.flat() - Vec3(gi.field.opponent_goal.location)).rescale(2200).flat() with Renderer(gi.bot.renderer) as r: r.draw_line_3d(ball_location, target_location, r.cyan()) else: target_location = ball_location + (ball_location - Vec3(gi.field.opponent_goal.location)).rescale(100) # Draw some things to help understand what the bot is thinking with Renderer(gi.bot.renderer) as r: r.draw_line_3d(gi.car.location, target_location, r.white()) r.draw_string_3d(gi.car.location, 1, 1, f'Speed: {gi.car.velocity.length():.1f}', r.white()) r.draw_rect_3d(target_location, 8, 8, True, r.cyan(), centered=True) controls = SimpleControllerState() controls.steer = gi.car.steer_toward_target(target_location) controls.throttle = 1.0 controls.boost = abs(controls.steer) < 0.2 and gi.car.velocity.length() < 2000 # controls.handbrake = abs(controls.steer) > 0.99 and gi.car.location.dist(ball_location) > 1000 return Sequence([SingleStep(controls)])
def left_diagonal_flip_kickoff(self, packet, ball_location): print("left diagonal kickoff") self.active_sequence = Sequence([ ControlStep(duration=.2, controls=SimpleControllerState(throttle=1, boost=True)), ControlStep(duration=.3, controls=SimpleControllerState(throttle=1, boost=1, steer=1)), ControlStep(duration=.15, controls=SimpleControllerState(throttle=1, boost=1, steer=-1)), ControlStep(duration=.05, controls=SimpleControllerState(jump=True, yaw=-1, boost=True)), ControlStep(duration=.05, controls=SimpleControllerState(yaw=-1, boost=True)), ControlStep(duration=.05, controls=SimpleControllerState(jump=True, yaw=-1, boost=True)), ]) return self.active_sequence.tick(packet)
def correct_direction(self, packet, dir): self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True, throttle=dir)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False, throttle=dir)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, throttle=dir, pitch=1)), ControlStep(duration=0.25, controls=SimpleControllerState(jump=False, throttle=dir, pitch=-1)), ControlStep(duration=0.3, controls=SimpleControllerState(roll=1, throttle=-dir, pitch=-1)), ControlStep(duration=0.05, controls=SimpleControllerState(throttle=-dir)), ]) return self.active_sequence.tick(packet)
def half_flip_sequence(self, packet): self.active_sequence = Sequence([ ControlStep(duration=0.3, controls=SimpleControllerState(throttle=-1)), ControlStep(duration=0.1, controls=SimpleControllerState(throttle=-1, jump=True, pitch=1)), ControlStep(duration=0.2, controls=SimpleControllerState(throttle=-1, jump=False, pitch=1)), ControlStep(duration=0.1, controls=SimpleControllerState(jump=True, pitch=1)), ControlStep(duration=0.1, controls=SimpleControllerState(throttle=1, boost=True, pitch=-1)), ControlStep(duration=0.5, controls=SimpleControllerState(throttle=1, boost=True, pitch=-1, roll=1)), ControlStep(duration=0.2, controls=SimpleControllerState(roll=0)), ControlStep(duration=0.5, controls=SimpleControllerState(throttle=1)), ]) return self.active_sequence.tick(packet)
def doublejump(packet,hold_time:float=0.02): active_sequence=Sequence([ ControlStep(duration=0.2,controls=SimpleControllerState(throttle=1,jump=True)), ControlStep(duration=0.02,controls=SimpleControllerState(throttle=1,jump=False)), ControlStep(duration=hold_time,controls=SimpleControllerState(throttle=1,jump=True)) ]) return active_sequence, active_sequence.tick(packet)
def jump_once(self, packet): self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)) ]) return self.active_sequence.tick(packet)
def wavedash(packet): active_sequence=Sequence([ ControlStep(duration=0.02,controls=SimpleControllerState(throttle=1,jump=True)), ControlStep(duration=0.95,controls=SimpleControllerState(throttle=1,jump=False,pitch=0.2)), ControlStep(duration=0.02,controls=SimpleControllerState(throttle=1,jump=True,pitch=-1)), ControlStep(duration=0.05,controls=SimpleControllerState(throttle=1)), ]) return active_sequence, active_sequence.tick(packet)
def begin_front_flip(self, packet): self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)), ControlStep(duration=0.8, controls=SimpleControllerState()), ]) # Return the controls associated with the beginning of the sequence so we can start right away. return self.active_sequence.tick(packet)
def front_flip(self, packet) -> Sequence: return Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)), ControlStep(duration=0.8, controls=SimpleControllerState()), ])
def begin_dright_flip(packet): #flip diagonal right active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, roll=1,pitch=-1)), ControlStep(duration=0.8, controls=SimpleControllerState()), ]) # Return the controls associated with the beginning of the sequence so we can start right away. return active_sequence, active_sequence.tick(packet)
def kickoff(gi: GameInfo) -> Sequence: with Renderer(gi.bot.renderer) as r: r.draw_string_3d(gi.car.location, 1, 1, 'kickoff!', r.white()) ball_location = Vec3(gi.packet.game_ball.physics.location) target_location = ball_location + (ball_location - Vec3(gi.field.opponent_goal.location)).rescale(92.75) return Sequence([SingleStep(SimpleControllerState( steer=gi.car.steer_toward_target(target_location), throttle=1.0, boost=gi.car.velocity.length() < 2300, ))])
def begin_half_flip(self, packet): self.active_sequence = Sequence([ ControlStep(duration=1.0, controls=SimpleControllerState(throttle=-1, boost=False)), ControlStep(duration=0.1, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=1)), ControlStep(duration=0.15, controls=SimpleControllerState(pitch=-1, boost=False)), ControlStep(duration=0.5, controls=SimpleControllerState(pitch=-1, boost=True, roll=1, throttle=1)), ControlStep(duration=0.5, controls=SimpleControllerState()), ]) return self.active_sequence.tick(packet)
def flip(self, packet, dir_x, dir_y, first_jump): self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=first_jump)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, yaw=dir_x, pitch=dir_y)), ControlStep(duration=0.8, controls=SimpleControllerState()), ]) return self.active_sequence.tick(packet)
def begin_front_flip(self, packet): # Send some quickchat just for fun self.send_quick_chat(team_only=False, quick_chat=QuickChatSelection.Information_IGotIt) # Do a front flip. We will be committed to this for a few seconds and the bot will ignore other # logic during that time because we are setting the active_sequence. self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)), ControlStep(duration=0.8, controls=SimpleControllerState()), ]) # Return the controls associated with the beginning of the sequence so we can start right away. return self.active_sequence.tick(packet)
def begin_front_flip(self, packet, angle=0.0, right=1): # Do a flip. We will be committed to this for a few seconds and the bot will ignore other # logic during that time because we are setting the active_sequence. mult = 1 if right < 0: mult = -1 rad = math.radians(0) # set to 0 for now self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.1, controls=SimpleControllerState(jump=True, pitch=-math.cos(rad), yaw=mult * math.sin(rad))), ControlStep(duration=0.8, controls=SimpleControllerState()), ]) # Return the controls associated with the beginning of the sequence so we can start right away. return self.active_sequence.tick(packet)
def reverse_flip(self, packet): self.active_sequence = Sequence([ ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=1)), ControlStep(duration=0.25, controls=SimpleControllerState(jump=False, pitch=-1)), ControlStep(duration=0.3, controls=SimpleControllerState(roll=1, pitch=-1)), ControlStep(duration=0.05, controls=SimpleControllerState()), ]) return self.active_sequence.tick(packet)
def left_diagonal(packet): #the kickoff active_sequence=Sequence([ ControlStep(duration=0.45, controls=SimpleControllerState(boost=True,throttle=1)), ControlStep(duration=0.10, controls=SimpleControllerState(boost=True,throttle=1,steer=-1)), ControlStep(duration=0.05, controls=SimpleControllerState(boost=True,throttle=1,jump=True)), ControlStep(duration=0.05, controls=SimpleControllerState(boost=True,throttle=1,jump=False)), ControlStep(duration=0.2, controls=SimpleControllerState(boost=True,throttle=1,jump=True,pitch=-1,roll=1)), ControlStep(duration=0.4, controls=SimpleControllerState(boost=True,throttle=1)), ControlStep(duration=0.49, controls=SimpleControllerState(throttle=1)), ControlStep(duration=0.05, controls=SimpleControllerState(throttle=1,pitch=1)), ControlStep(duration=0.09, controls=SimpleControllerState(jump=True,throttle=1)), ControlStep(duration=0.05, controls=SimpleControllerState(jump=False,throttle=1)), ControlStep(duration=0.2, controls=SimpleControllerState(jump=True,throttle=1,pitch=-1,roll=-1)), ControlStep(duration=0.8, controls=SimpleControllerState()) ]) # Return the controls associated with the beginning of the sequence so we can start right away. return active_sequence, active_sequence.tick(packet)
def push_ball_toward_target(gi: GameInfo, target: Vec3) -> Sequence: ball_loc = Vec3(gi.packet.game_ball.physics.location) ball_loc_flat = ball_loc.flat() ball_ground_speed = Vec3(gi.packet.game_ball.physics.velocity).flat().length() car_to_ball_dist = gi.car.location.flat().dist(ball_loc_flat) if ball_ground_speed > 300: future_seconds = car_to_ball_dist / 2000.0 ball_prediction = gi.bot.get_ball_prediction_struct() ball_loc_fut_flat = Vec3(find_slice_at_time(ball_prediction, gi.packet.game_info.seconds_elapsed + future_seconds).physics.location).flat() ideal_position = ball_loc_fut_flat + (ball_loc_fut_flat - target.flat()).rescale(80) # ideal_position = ball_loc_flat + (ball_loc_flat - target.flat()).rescale(80) else: future_seconds = -1 ideal_position = ball_loc_flat + (ball_loc_flat - target.flat()).rescale(80) with Renderer(gi.bot.renderer) as r: r.draw_line_3d(gi.car.location, ideal_position, r.white()) r.draw_string_3d(gi.car.location, 1, 1, f'Predicted Seconds: {future_seconds:.1f}', r.white()) r.draw_rect_3d(ideal_position, 8, 8, True, r.cyan(), centered=True) controls = SimpleControllerState( steer=gi.car.steer_toward_target(ideal_position) ) car_ground_speed = gi.car.velocity.flat().length() if ball_loc.z < 150 or car_to_ball_dist > 800: if abs(controls.steer) < 0.2: controls.throttle = 1.0 controls.boost = car_ground_speed < 2000 else: controls.throttle = 1.0 controls.handbrake = gi.car.angular_velocity.length() < 1 else: if car_ground_speed - ball_ground_speed > 525 and car_to_ball_dist < 500: controls.throttle = min(max((ball_ground_speed - car_ground_speed) / 3600, -1.0), 0) controls.boost = False else: controls.throttle = min(max((ball_ground_speed - car_ground_speed) / 525, 0), 1.0) controls.boost = ball_ground_speed - car_ground_speed > 992 or car_to_ball_dist > 800 return Sequence([SingleStep(controls)])
def right_speed_flip_kickoff(self, packet): print("right speed flip") self.active_sequence = Sequence([ ControlStep(duration=.4, controls=SimpleControllerState(throttle=1, boost=True)), ControlStep(duration=.2, controls=SimpleControllerState(throttle=1, boost=True, steer=.75)), ControlStep(duration=.05, controls=SimpleControllerState(jump=True, yaw=1, boost=True)), ControlStep(duration=.05, controls=SimpleControllerState(yaw=-1, pitch=-1, boost=True)), ControlStep(duration=.05, controls=SimpleControllerState(jump=True, yaw=-1, pitch=-1)), ControlStep(duration=.5, controls=SimpleControllerState(yaw=1, pitch=1, roll=-1)), ControlStep(duration=.25, controls=SimpleControllerState(roll=-1, boost=True, yaw=1)), ControlStep(duration=.25, controls=SimpleControllerState(throttle=1, boost=True, handbrake=True)), ControlStep(duration=3, controls=SimpleControllerState(throttle=1)), ]) return self.active_sequence.tick(packet)
def start_aerial(self, target: Vec3, arrival_time: float): self.active_sequence = Sequence([ LineUpForAerialStep(target, arrival_time, self.index), AerialStep(target, arrival_time, self.index) ])
def find_DSM_path(target: Vec3, pos_steps, velocity_steps, L_steps, controls_tracker, num_guess_paths, num_time_steps, time_step): turn_step = 2 / (num_guess_paths - 1) turn_inputs = [-1 + turn_step * x for x in range(num_guess_paths)] print(f"turn inputs = {turn_inputs}") delta_t = .1 print(f"time step = {time_step}") if time_step <= num_time_steps: test_velos = [0] * num_guess_paths test_positions = test_velos[:] test_lagrangians = test_velos[:] test_controls = test_velos[:] for t in range(len(turn_inputs)): # find travel arc at current speed over delta t, update car velocity and location # first find distance traveled and store new location for step turn_radius = turn_inputs[t] * find_turn_radius( velocity_steps[time_step - 1].length()) print(f"turn radius = {turn_radius}") if turn_radius == 0: theta = 0 d = velocity_steps[time_step - 1].length() * delta_t else: theta = velocity_steps[time_step - 1].length() * delta_t / abs(turn_radius) d = 2 * abs(turn_radius) * math.sin(theta / 2) print(f"step displacement = {d}") print(f"theta = {theta}") phi = .5 * (math.pi - theta) y_disp = d * math.sin(phi) if turn_radius < 0: x_disp = d * math.cos(phi) else: x_disp = -1 * d * math.cos(phi) # x and y displacement above relative to direction of travel, need relative to field xyz # let angle psi be between car velocity and true x_hat # and eta the angle between true x_hat and directly to the cars left, car_vx_hat # determine quadrant to get appropriate sign for eta psi = velocity_steps[time_step - 1].ang_to(Vec3(1, 0, 0)) if velocity_steps[time_step - 1].y >= 0: eta = math.pi / 2 - psi else: eta = 3 * math.pi / 2 - psi print(f"eta = {eta}") disp_vec = Vec3(x_disp, y_disp, 0) print(f"disp vec = {disp_vec}") field_disp = disp_vec.rotate_xy(eta) print(f"field disp = {field_disp}") test_positions[t] = pos_steps[time_step - 1] + field_disp # find and store velocity vector for step. first, update x,y components due to acceleration. # then, rotate velocity vector to correspond with new travel direction based on above turn. throttle_accel = find_throttle_accel(velocity_steps[time_step - 1].length()) accel_vec = Vec3(throttle_accel * math.cos(psi), throttle_accel * math.sin(psi), 0) new_velo = velocity_steps[time_step - 1] + accel_vec * delta_t # if new_velo is greater than achievable max throttle speed, fix if new_velo.length() > 1410: new_velo.rescale(1410) # rotate to correct orientation if turn_radius < 0: theta = theta * -1 test_velos[t] = new_velo.rotate_xy(theta) # store controls for step test_controls[t] = ControlStep(duration=delta_t, controls=SimpleControllerState( throttle=1.0, steer=turn_inputs[t])) # find and store lagrangian for step R = 2189235679380 r_vec = test_positions[t].__sub__(target) kinetic = .5 * 180 * test_velos[t].length()**2 potential = (.5 * 180 * 1410**2 - kinetic) + R / (r_vec.length()) test_lagrangians[t] = kinetic - potential print(f"test_velos = {test_velos}") print(f"Test Ls = {test_lagrangians}") idx = np.argmin(test_lagrangians) pos_steps[time_step] = test_positions[idx] velocity_steps[time_step] = test_velos[idx] L_steps[time_step] = test_lagrangians[idx] print(f"steer = {test_controls[idx].controls.steer}") controls_tracker[time_step - 1] = test_controls[idx] return find_DSM_path(target, pos_steps, velocity_steps, L_steps, controls_tracker, num_guess_paths, num_time_steps, time_step + 1) return Sequence(controls_tracker)
def kickoff_idle(packet): active_sequence=Sequence([ControlStep(duration=1,controls=SimpleControllerState(throttle=0.2))]) return active_sequence, active_sequence.tick(packet)