def get_controls(game_info, sub_state_machine): controls = SimpleControllerState() persistent = game_info.persistent if game_info.me.wheel_contact: #If still on ground, jump controls.jump = 1 else: #Once we've jumped, dodge towards the ball controls = AirDodge( car_coordinates_2d(game_info.me, game_info.ball.pos - game_info.me.pos), game_info.me.jumped_last_frame).input() return controls, persistent
def offcenter(game_info, old_game_info, opponent_distance, x_sign, persistent): controller_input = SimpleControllerState() current_state = game_info.me old_state = old_game_info.me ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) #Offset added to the ball position for our initial steer offset = Vec3(x_sign * 1200, 0, 0) first_boost = 7 wobble = Vec3(current_state.omega.x, current_state.omega.y, 0).magnitude() epsilon = 0.01 if abs(current_state.pos.y) > 3400: #If we're not near the center-line of the field, boost towards the first small boost controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos + offset)).input() controller_input.boost = 1 elif abs(current_state.pos.y) > 900 and current_state.wheel_contact: controller_input.jump = 1 controller_input.boost = 1 elif abs(current_state.pos.y) > 900 and not current_state.double_jumped: #If we're far away, fast dodge to speed up. dodge_direction = car_coordinates_2d( current_state, (game_info.ball.pos - Vec3(x_sign * 2500, 0, 0)) - current_state.pos) controller_input = CancelledFastDodge(current_state, dodge_direction).input() controller_input.boost = 1 elif abs(current_state.pos.y) < 250: #If both players are close to the ball, dodge into the ball. controller_input = AirDodge(Vec3(0, 1, 0), current_state.jumped_last_frame).input() controller_input.boost = 1 elif current_state.wheel_contact and wobble < epsilon: #If we're approaching the ball and stable enough to jump again, #jump turn into ball to prep for the dodge if current_state.rot.yaw > ball_angle: direction = -1 else: direction = 1 controller_input = JumpTurn(current_state, 0, direction).input() elif current_state.wheel_contact: controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos)).input() controller_input.boost = 1 else: vel_angle = atan2(current_state.vel.y, current_state.vel.x) target_rot = Orientation(pyr=[0, vel_angle, 0]) controller_input, persistent = aerial_rotation(target_rot, game_info.dt, persistent) controller_input.boost = 1 return controller_input, persistent
def far_back(game_info, old_game_info, opponent_distance, persistent): controller_input = SimpleControllerState() current_state = game_info.me old_state = old_game_info.me ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) #Set which boost we want based on team. if game_info.team_sign == 1: first_boost = 7 else: first_boost = 26 if abs(current_state.pos.y) > 4000: #Boost to start controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos)).input() controller_input.boost = 1 elif abs(current_state.pos.y) > 3817: #Turn to line up the dodge controller_input = QuickTurn(1, True).input() elif abs(current_state.pos.y) > 2500 and current_state.wheel_contact: #Jump to prep for the dodge controller_input.jump = 1 elif abs(current_state.pos.y) > 3400: #If we're far away, fast dodge to speed up dodge_direction = car_coordinates_2d( current_state, (game_info.ball.pos - Vec3(0, 0, 0)) - current_state.pos) controller_input = CancelledFastDodge(current_state, dodge_direction).input() elif abs(current_state.pos.y) < 400: # and opponent_distance < 1000: #Dodge into the ball. controller_input = AirDodge(Vec3(1, 0, 0), current_state.jumped_last_frame).input() elif current_state.wheel_contact and abs( current_state.pos.y) < 1000: # and opponent_distance < 1000: #If we're on the ground, close, and the opponent is also close, #jump and turn towards the ball to prep for the dodge. if current_state.rot.yaw > ball_angle: direction = -1 else: direction = 1 controller_input = JumpTurn(current_state, 0, direction).input() elif abs(current_state.pos.y) < 375: #If the opponent is far away and we're close to the ball, take a single jump shot controller_input.jump = 1 elif current_state.wheel_contact: #Otherwise if we're on the ground, boost and turn towards the ball controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos)).input() controller_input.boost = 1 else: #Otherwise turn towards the ball (this might not actually do anything) controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos)).input() return controller_input, persistent
def diagonal(game_info, old_game_info, opponent_distance, x_sign, persistent): controller_input = SimpleControllerState() current_state = game_info.me old_state = old_game_info.me ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) offset = Vec3(x_sign * 1500, -465, 0) if current_state.rot.yaw > ball_angle: direction = -1 else: direction = 1 wobble = Vec3(current_state.omega.x, current_state.omega.y, 0).magnitude() epsilon = 0.3 #Set which boost we want based on team and side. if x_sign == -1: first_boost = 11 else: first_boost = 10 if abs(current_state.pos.y) > 2440: #If we haven't taken the small boost yet, drive towards it controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos + offset)).input() controller_input.boost = 1 elif abs(current_state.pos.y) > 1100 and current_state.wheel_contact: controller_input.jump = 1 controller_input.boost = 1 elif abs(current_state.pos.y) > 500: #If we've taken the boost but are still far away, fast dodge to speed up dodge_direction = car_coordinates_2d( current_state, (game_info.ball.pos - Vec3(x_sign * 1000, 0, 0)) - current_state.pos) print(atan2(dodge_direction.y, dodge_direction.x)) controller_input = CancelledFastDodge(current_state, dodge_direction).input() controller_input.steer = direction elif abs(current_state.pos.y) < 350: #If both players are close to the ball, dodge into the ball. controller_input = AirDodge( car_coordinates_2d(current_state, game_info.ball.pos - current_state.pos), current_state.jumped_last_frame).input() elif current_state.wheel_contact: #If we're approaching the ball and the opponent is close, #jump turn into ball to prep for the dodge controller_input.steer = direction elif current_state.wheel_contact and abs(current_state.pos.y) < 520: controller_input.jump elif current_state.wheel_contact and wobble < epsilon: controller_input.handbrake = 1 else: vel_angle = atan2(current_state.vel.y, current_state.vel.x) target_rot = Orientation(pyr=[0, vel_angle - x_sign * pi / 4, 0]) controller_input, persistent = aerial_rotation(target_rot, game_info.dt, persistent) controller_input.boost = 1 controller_input.steer = x_sign return controller_input, persistent
def Cowculate(plan, game_info, ball_prediction, persistent): ''' The main control function for BAC, Cowculate() returns the final input. It takes a GameState object, a plan, and returns a controller_input object. Cowculate will be the framework of all decision making, and will be the highest level of abstraction. ''' controller_input = SimpleControllerState() current_state = game_info.me ############################################################################# if plan.layers[0] == "Boost": ''' Decide how to get the boost we want to go for. ''' #TODO: Optimize these, or phase them out for RLU or similar. wobble = Vec3(current_state.omega.x, current_state.omega.y, 0).magnitude() epsilon = 0.3 target_boost = None if type(plan.layers[1]) == int: target_boost = game_info.boosts[plan.layers[1]] elif plan.layers[1] == "Pads": #This will skip the target boost loop and follow the path pass if target_boost != None: angle_to_boost = atan2((target_boost.pos - current_state.pos).y, (target_boost.pos - current_state.pos).x) facing_boost = angles_are_close(angle_to_boost, current_state.rot.yaw, pi / 12) grounded_facing_boost = facing_boost and current_state.wheel_contact #Turn towards boostI controller_input = GroundTurn( current_state, current_state.copy_state(pos=target_boost.pos)).input() if 1000 < current_state.vel.magnitude( ) < 2250 and facing_boost and wobble < epsilon and ( current_state.pos - target_boost.pos ).magnitude() > 1000 and abs(current_state.omega.z) < epsilon: #If slow, not wobbling from a previous dodge, facing towards the boost, #and not already at the boost, dodge for speed controller_input = FrontDodge(current_state).input() elif current_state.vel.magnitude() < 2300 and ( grounded_facing_boost or current_state.rot.pitch < -pi / 12): controller_input.boost = 1 elif plan.path == None: #Copied the "go to net" code because I don't plan on really improving this for now. #This section will be greatly improved once I have ground recovery code in place. #TODO: Reocvery code into picking a path more intelligently. center_of_net = Vec3(0, -5120, 0) #Turn towards the center of our net controller_input = GroundTurn( current_state, current_state.copy_state(pos=center_of_net)).input() #Variables to check if we want to flip for speed. displacement_from_net = center_of_net - current_state.pos distance_to_net = displacement_from_net.magnitude() angle_to_net = atan2(displacement_from_net.y, displacement_from_net.x) facing_net = angles_are_close(angle_to_net, current_state.rot.yaw, pi / 12) speed = current_state.vel.magnitude() if distance_to_net > 1500 * ( (speed + 500) / 1410) and 1000 < speed < 2000 and facing_net: controller_input = FrontDodge(current_state).input() elif current_state.boost > 60 and facing_net and current_state.wheel_contact and speed < 2300: controller_input.boost = 1 #If we start to go up the wall on the way, turn back down. if current_state.wheel_contact: if current_state.rot.roll > 0.15: controller_input.steer = 1 elif current_state.rot.roll < -0.15: controller_input.steer = -1 else: controller_input = plan.path.input() ############################################################################# elif plan.layers[0] == "Goal": ''' Decide how to go to or wait in net ''' #Useful locations center_of_net = Vec3(0, -5120, 0) if game_info.ball.pos.x > 0: far_post = Vec3(-1150, -5120 + 300, 0) far_boost = game_info.boosts[3].pos else: far_post = Vec3(1150, -5120 + 300, 0) far_boost = game_info.boosts[4].pos if plan.layers[1] == "Go to net": #Turn towards the center of our net controller_input = GroundTurn( current_state, current_state.copy_state(pos=center_of_net)).input() #Variables to check if we want to flip for speed. displacement_from_net = center_of_net - current_state.pos distance_to_net = displacement_from_net.magnitude() angle_to_net = atan2(displacement_from_net.y, displacement_from_net.x) facing_net = angles_are_close(angle_to_net, current_state.rot.yaw, pi / 12) speed = current_state.vel.magnitude() if distance_to_net > 1500 and 1000 < speed < 2000 and facing_net: controller_input = FrontDodge(current_state).input() elif current_state.boost > 60 and facing_net and current_state.wheel_contact and speed < 2300: controller_input.boost = 1 #If we start to go up the wall on the way, turn back down. if current_state.wheel_contact: if current_state.rot.roll > 0.15: controller_input.steer = 1 elif current_state.rot.roll < -0.15: controller_input.steer = -1 elif plan.layers[1] == "Wait in net": if plan.layers[2] == "Prep for Aerial": controller_input = SimpleControllerState() else: ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) #Go to net, stop in the middle, then turn in place to face the ball. #TODO: Improve NavigateTo or replace completely rot = Orientation(pyr=[ current_state.rot.pitch, ball_angle, current_state.rot.roll ]) target_state = current_state.copy_state(pos=center_of_net, rot=rot) controller_input = NavigateTo(current_state, target_state).input() ############################################################################# elif plan.layers[0] == "Ball": ''' Calculate how to go for the ball as decided in planning. ''' if plan.layers[1] == "Challenge": #TODO: Intelligent challenges. if current_state.wheel_contact: #If still on ground, jump controller_input.jump = 1 else: #Once we've jumped, dodge towards the ball controller_input = AirDodge( car_coordinates_2d(current_state, game_info.ball.pos - current_state.pos), current_state.jumped_last_frame).input() ''' elif plan.layers[1] == "Save" and plan.layers[2] == "Backwards": controller_input = GroundTurn(current_state, current_state.copy_state(pos = game_info.ball.pos), can_reverse = True).input() ''' elif plan.layers[2] == "Aerial": controller_input, persistent = aerial(game_info.dt, game_info.team_sign, persistent) else: #TODO: Replace all of this with shooting/clearing/better code. #Need pathing to get to a reasonable spot, and intelligent dodges to place the ball properly. for i in range(100): #Adjust for Ball/Car radii ball_vel = ball_prediction.slices[i].vel try: #Evil magic numbers. TODO: Actual timing and arrival prediction. target_pos = ball_prediction.slices[ i].pos + ball_vel.normalize().scalar_multiply(150) except ZeroDivisionError: target_pos = ball_prediction.slices[i].pos car_target_vector = target_pos - current_state.pos turn_angle = abs( current_state.rot.yaw - atan2(car_target_vector.y, car_target_vector.x)) time_estimate = linear_time_to_reach( game_info, target_pos) - (ball_vel.magnitude() / 50) * (turn_angle) if ball_prediction.slices[i].time < time_estimate + 1 / 30: break if plan.layers[1] == "Shot": #If the opponent isn't close to the ball, reposition to shoot towards net #Find the center of the opponent's net center_of_net = Vec3(0, 5120, game_info.ball.pos.z) #If the ball is left, go right, and vice versa. if game_info.ball.pos.x > 0: shooting_correction = ( 60 * (5120 - abs(game_info.ball.pos.y))) / ( (game_info.ball.pos - center_of_net).magnitude()) else: shooting_correction = -( 60 * (5120 - abs(game_info.ball.pos.y))) / ( (game_info.ball.pos - center_of_net).magnitude()) target_pos = Vec3(target_pos.x + shooting_correction, target_pos.y, target_pos.z) #Make sure we don't try to go to a point outside the map target_pos = Vec3(cap_magnitude(target_pos.x, 4096), cap_magnitude(target_pos.y, 5120), target_pos.z) #Turn towards the target controller_input = GroundTurn( current_state, current_state.copy_state(pos=target_pos)).input() #If we're not supersonic, and we're facing roughly towards the ball, boost. ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) if current_state.vel.magnitude( ) < 2250 and current_state.wheel_contact and angles_are_close( current_state.rot.yaw, ball_angle, pi / 4): controller_input.boost = 1 ############################################################################# elif plan.layers[0] == "Recover": if plan.layers[1] == "Air": #If we're in the air, and not trying to hit the ball, recover. controller_input, persistent = aerial_rotation( game_info.dt, persistent) elif plan.layers[1] == "Ground": controller_input = GroundTurn( current_state, current_state.copy_state(pos=Vec3(0, -5120, 0))).input() #TODO: Work on have_steering_control, powersliding, etc. return controller_input, persistent
def Cowculate(plan, game_info, ball_prediction, persistent): ''' The main control function for BAC, Cowculate() returns the final input. It takes a GameState object, a plan, and returns a controller_input object. Cowculate will be the framework of all decision making, and will be the highest level of abstraction. ''' controller_input = SimpleControllerState() current_state = game_info.me ############################################################################# if plan.layers[0] == "Boost": ''' Decide how to get the boost we want to go for. ''' #TODO: Optimize these, or phase them out for RLU or similar. wobble = Vec3(current_state.omega.x, current_state.omega.y, 0).magnitude() epsilon = 0.3 target_boost = None if type(plan.layers[1]) == int: target_boost = game_info.boosts[plan.layers[1]] elif plan.layers[1] == "Pads": #This will skip the target boost loop and follow the path pass if target_boost != None: angle_to_boost = atan2((target_boost.pos - current_state.pos).y, (target_boost.pos - current_state.pos).x) facing_boost = angles_are_close(angle_to_boost, current_state.rot.yaw, pi / 12) grounded_facing_boost = facing_boost and current_state.wheel_contact #Turn towards boost controller_input = GroundTurn( current_state, current_state.copy_state(pos=target_boost.pos)).input() if 1000 < current_state.vel.magnitude( ) < 2250 and facing_boost and wobble < epsilon and ( current_state.pos - target_boost.pos ).magnitude() > 1000 and abs(current_state.omega.z) < epsilon: #If slow, not wobbling from a previous dodge, facing towards the boost, #and not already at the boost, dodge for speed controller_input = FrontDodge(current_state).input() elif current_state.vel.magnitude() < 2300 and ( grounded_facing_boost or current_state.rot.pitch < -pi / 12): controller_input.boost = 1 elif plan.path == None: #Copied the "go to net" code because I don't plan on really improving this for now. #This section will be greatly improved once I have ground recovery code in place. #TODO: Reocvery code into picking a path more intelligently. center_of_net = Vec3(0, -5120, 0) #Turn towards the center of our net controller_input = GroundTurn( current_state, current_state.copy_state(pos=center_of_net)).input() #Variables to check if we want to flip for speed. displacement_from_net = center_of_net - current_state.pos distance_to_net = displacement_from_net.magnitude() angle_to_net = atan2(displacement_from_net.y, displacement_from_net.x) facing_net = angles_are_close(angle_to_net, current_state.rot.yaw, pi / 12) speed = current_state.vel.magnitude() if distance_to_net > 1500 * ( (speed + 500) / 1410) and 1000 < speed < 2000 and facing_net: controller_input = FrontDodge(current_state).input() elif current_state.boost > 60 and facing_net and current_state.wheel_contact and speed < 2300: controller_input.boost = 1 #If we start to go up the wall on the way, turn back down. if current_state.wheel_contact: if current_state.rot.roll > 0.15: controller_input.steer = 1 elif current_state.rot.roll < -0.15: controller_input.steer = -1 else: controller_input = plan.path.input() ############################################################################# elif plan.layers[0] == "Goal": ''' Decide how to go to or wait in net ''' #Useful locations center_of_net = Vec3(0, -5120, 0) if game_info.ball.pos.x > 0: far_post = Vec3(-1150, -5120 + 300, 0) far_boost = game_info.boosts[3].pos else: far_post = Vec3(1150, -5120 + 300, 0) far_boost = game_info.boosts[4].pos if plan.layers[1] == "Go to net": #Turn towards the center of our net controller_input = GroundTurn( current_state, current_state.copy_state(pos=center_of_net)).input() #Variables to check if we want to flip for speed. displacement_from_net = center_of_net - current_state.pos distance_to_net = displacement_from_net.magnitude() angle_to_net = atan2(displacement_from_net.y, displacement_from_net.x) facing_net = angles_are_close(angle_to_net, current_state.rot.yaw, pi / 12) speed = current_state.vel.magnitude() if distance_to_net > 1500 and 1000 < speed < 2000 and facing_net: controller_input = FrontDodge(current_state).input() elif current_state.boost > 60 and facing_net and current_state.wheel_contact and speed < 2300: controller_input.boost = 1 #If we start to go up the wall on the way, turn back down. if current_state.wheel_contact: if current_state.rot.roll > 0.15: controller_input.steer = 1 elif current_state.rot.roll < -0.15: controller_input.steer = -1 elif plan.layers[1] == "Wait in net": if plan.layers[2] == "Prep for Aerial": controller_input = SimpleControllerState() else: ball_angle = atan2((game_info.ball.pos - current_state.pos).y, (game_info.ball.pos - current_state.pos).x) #Go to net, stop in the middle, then turn in place to face the ball. #TODO: Improve NavigateTo or replace completely rot = Orientation(pyr=[ current_state.rot.pitch, ball_angle, current_state.rot.roll ]) target_state = current_state.copy_state(pos=center_of_net, rot=rot) controller_input = NavigateTo(current_state, target_state).input() ############################################################################# elif plan.layers[0] == "Ball": ''' Calculate how to go for the ball as decided in planning. ''' if plan.layers[1] == "Challenge": #TODO: Intelligent challenges. if current_state.wheel_contact: #If still on ground, jump controller_input.jump = 1 else: #Once we've jumped, dodge towards the ball controller_input = AirDodge( car_coordinates_2d(current_state, game_info.ball.pos - current_state.pos), current_state.jumped_last_frame).input() elif plan.layers[1] == "Save": if persistent.path_follower.action != None: #Follow the ArcLineArc path persistent.path_follower.action.step(game_info.dt) controller_input = persistent.path_follower.action.controls #else: # controller_input = jump_turn() #TODO: When facing walls, all paths go about of bounds. Turn around first. elif plan.layers[2] == "Aerial": controller_input, persistent = aerial(game_info.dt, game_info.team_sign, persistent) elif (plan.layers[1] == "Shot" or plan.layers[1] == "Clear") and plan.layers[2] == "Path": if persistent.path_follower.action != None: #Follow the ArcLineArc path persistent.path_follower.action.step(game_info.dt) controller_input = persistent.path_follower.action.controls #else: # controller_input = jump_turn() #TODO: When facing walls, all paths go about of bounds. Turn around first. elif (plan.layers[1] == "Shot" or plan.layers[1] == "Clear") and plan.layers[2] == "Hit ball": if persistent.doddge.action == None: persistent.dodge.check = True dodge_simulation_results = moving_ball_dodge_contact(game_info) persistent.dodge.action = RLU_Dodge( game_info.utils_game.my_car) persistent.dodge.action.duration = dodge_simulation_results[0] persistent.dodge.action.delay = dodge_simulation_results[1] persistent.dodge.action.target = Vec3_to_vec3( game_info.ball.pos, game_info.team_sign) persistent.dodge.action.preorientation = roll_away_from_target( persistent.dodge.action.target, pi / 4, game_info) else: persistent.dodge.check = True persistent.dodge.action.step(game_info.dt) output = persistent.dodge.action.controls output.boost = 1 elif (plan.layers[1] == "Shot" or plan.layers[1] == "Clear") and plan.layers[2] == "Chase": controller_input = GroundTurn( current_state, current_state.copy_state(pos=game_info.ball.pos)).input() ############################################################################# elif plan.layers[0] == "Recover": if plan.layers[1] == "Air": #If we're in the air, and not trying to hit the ball, recover. controller_input, persistent = aerial_rotation( game_info.dt, persistent) elif plan.layers[1] == "Ground": controller_input = GroundTurn( current_state, current_state.copy_state(pos=Vec3(0, -5120, 0))).input() #TODO: Work on have_steering_control, powersliding, etc. return controller_input, persistent