def execute(self, bot): self.is_dribbling = True car = bot.info.my_car ball = bot.info.ball ball_landing = predict.next_ball_landing(bot) ball_to_goal = bot.info.enemy_goal - ball.pos # Decide on target pos and speed target = ball_landing.data["obj"].pos - self.offset_bias * normalize(ball_to_goal) dist = norm(target - bot.info.my_car.pos) speed = 1400 if ball_landing.time == 0 else dist / ball_landing.time # Do a flick? car_to_ball = ball.pos - car.pos dist = norm(car_to_ball) if dist <= self.required_distance_to_ball_for_flick: self.flick_timer += 0.016666 if self.flick_timer > self.wait_before_flick: bot.plan = DodgePlan(bot.info.enemy_goal) # use flick_init_jump_duration? else: self.flick_timer = 0 # dodge on far distances if dist > 2450 and speed > 1410: ctt_n = normalize(target - car.pos) vtt = dot(bot.info.my_car.vel, ctt_n) / dot(ctt_n, ctt_n) if vtt > 750: bot.plan = DodgePlan(target) controls = bot.drive.go_towards_point(bot, target, target_vel=speed, slide=False, boost=False, can_keep_speed=False, can_dodge=True, wall_offset_allowed=0) bot.controls = controls if bot.do_rendering: bot.renderer.draw_line_3d(car.pos, target, bot.renderer.pink())
def go_towards_point(self, bot, point: vec3, target_vel=1430, slide=False, boost=False, can_keep_speed=True, can_dodge=True, wall_offset_allowed=130) -> SimpleControllerState: REQUIRED_ANG_FOR_SLIDE = 1.65 REQUIRED_VELF_FOR_DODGE = 1100 car = bot.info.my_car # Dodge is finished if self.dodge is not None and self.dodge.finished: self.dodge = None self.last_dodge_end_time = bot.info.current_game_time # Continue dodge if self.dodge is not None: self.dodge.target = point self.dodge.execute(bot) return self.dodge.controls # Begin recovery if not car.on_ground: bot.plan = RecoverPlan() return self.controls # Get down from wall by choosing a point close to ground if not is_near_wall(point, wall_offset_allowed) and angle_between( car.up(), vec3(0, 0, 1)) > math.pi * 0.31: point = lerp(xy(car.pos), xy(point), 0.5) # If the car is in a goal, avoid goal posts self.avoid_goal_post(bot, point) car_to_point = point - car.pos # The vector from the car to the point in local coordinates: # point_local[X]: how far in front of my car # point_local[Y]: how far to the left of my car # point_local[Z]: how far above my car point_local = dot(point - car.pos, car.theta) # Angle to point in local xy plane and other stuff angle = math.atan2(point_local[Y], point_local[X]) dist = norm(point_local) vel_f = proj_onto_size(car.vel, car.forward()) vel_towards_point = proj_onto_size(car.vel, car_to_point) # Start dodge if can_dodge and abs(angle) <= 0.02 and vel_towards_point > REQUIRED_VELF_FOR_DODGE\ and dist > vel_towards_point + 500 + 700 and bot.info.current_game_time > self.last_dodge_end_time + self.dodge_cooldown: self.dodge = DodgePlan(point) # Is in turn radius deadzone? tr = turn_radius(abs(vel_f + 50)) # small bias tr_side = sign(angle) tr_center_local = vec3(0, tr * tr_side, 0) point_is_in_turn_radius_deadzone = norm(point_local - tr_center_local) < tr # Draw turn radius deadzone if car.on_ground and bot.do_rendering: tr_center_world = car.pos + dot(car.theta, tr_center_local) tr_center_world_2 = car.pos + dot(car.theta, -1 * tr_center_local) render.draw_circle(bot, tr_center_world, car.up(), tr, 22) render.draw_circle(bot, tr_center_world_2, car.up(), tr, 22) if point_is_in_turn_radius_deadzone: # Hard turn self.controls.steer = sign(angle) self.controls.boost = False self.controls.throttle = 0 if vel_f > 150 else 0.1 if point_local[X] < 25: # Brake or go backwards when the point is really close but not in front of us self.controls.throttle = clip((25 - point_local[X]) * -.5, 0, -0.6) self.controls.steer = 0 if vel_f > 300: self.controls.handbrake = True else: # Should drop speed or just keep up the speed? if can_keep_speed and target_vel < vel_towards_point: target_vel = vel_towards_point else: # Small lerp adjustment target_vel = lerp(vel_towards_point, target_vel, 1.2) # Turn and maybe slide self.controls.steer = clip(angle + (2.5 * angle)**3, -1.0, 1.0) if slide and abs(angle) > REQUIRED_ANG_FOR_SLIDE: self.controls.handbrake = True self.controls.steer = sign(angle) else: self.controls.handbrake = False # Overshoot target vel for quick adjustment target_vel = lerp(vel_towards_point, target_vel, 1.2) # Find appropriate throttle/boost if vel_towards_point < target_vel: self.controls.throttle = 1 if boost and vel_towards_point + 25 < target_vel and target_vel > 1400 \ and not self.controls.handbrake and is_heading_towards(angle, dist): self.controls.boost = True else: self.controls.boost = False else: vel_delta = target_vel - vel_towards_point self.controls.throttle = clip(0.2 + vel_delta / 500, 0, -1) self.controls.boost = False if self.controls.handbrake: self.controls.throttle = min(0.4, self.controls.throttle) # Saved if something outside calls start_dodge() in the meantime self.last_point = point return self.controls
def start_dodge(self): if self.dodge is None: self.dodge = DodgePlan(self.last_point)
class DriveController: def __init__(self): self.controls = SimpleControllerState() self.dodge = None self.last_point = None self.last_dodge_end_time = 0 self.dodge_cooldown = 0.26 self.recovery = None def start_dodge(self): if self.dodge is None: self.dodge = DodgePlan(self.last_point) def go_towards_point(self, bot, point: vec3, target_vel=1430, slide=False, boost=False, can_keep_speed=True, can_dodge=True, wall_offset_allowed=130) -> SimpleControllerState: REQUIRED_ANG_FOR_SLIDE = 1.65 REQUIRED_VELF_FOR_DODGE = 1100 car = bot.info.my_car # Dodge is finished if self.dodge is not None and self.dodge.finished: self.dodge = None self.last_dodge_end_time = bot.info.current_game_time # Continue dodge if self.dodge is not None: self.dodge.target = point self.dodge.execute(bot) return self.dodge.controls # Begin recovery if not car.on_ground: bot.plan = RecoverPlan() return self.controls # Get down from wall by choosing a point close to ground if not is_near_wall(point, wall_offset_allowed) and angle_between( car.up(), vec3(0, 0, 1)) > math.pi * 0.31: point = lerp(xy(car.pos), xy(point), 0.5) # If the car is in a goal, avoid goal posts self.avoid_goal_post(bot, point) car_to_point = point - car.pos # The vector from the car to the point in local coordinates: # point_local[X]: how far in front of my car # point_local[Y]: how far to the left of my car # point_local[Z]: how far above my car point_local = dot(point - car.pos, car.theta) # Angle to point in local xy plane and other stuff angle = math.atan2(point_local[Y], point_local[X]) dist = norm(point_local) vel_f = proj_onto_size(car.vel, car.forward()) vel_towards_point = proj_onto_size(car.vel, car_to_point) # Start dodge if can_dodge and abs(angle) <= 0.02 and vel_towards_point > REQUIRED_VELF_FOR_DODGE\ and dist > vel_towards_point + 500 + 700 and bot.info.current_game_time > self.last_dodge_end_time + self.dodge_cooldown: self.dodge = DodgePlan(point) # Is in turn radius deadzone? tr = turn_radius(abs(vel_f + 50)) # small bias tr_side = sign(angle) tr_center_local = vec3(0, tr * tr_side, 0) point_is_in_turn_radius_deadzone = norm(point_local - tr_center_local) < tr # Draw turn radius deadzone if car.on_ground and bot.do_rendering: tr_center_world = car.pos + dot(car.theta, tr_center_local) tr_center_world_2 = car.pos + dot(car.theta, -1 * tr_center_local) render.draw_circle(bot, tr_center_world, car.up(), tr, 22) render.draw_circle(bot, tr_center_world_2, car.up(), tr, 22) if point_is_in_turn_radius_deadzone: # Hard turn self.controls.steer = sign(angle) self.controls.boost = False self.controls.throttle = 0 if vel_f > 150 else 0.1 if point_local[X] < 25: # Brake or go backwards when the point is really close but not in front of us self.controls.throttle = clip((25 - point_local[X]) * -.5, 0, -0.6) self.controls.steer = 0 if vel_f > 300: self.controls.handbrake = True else: # Should drop speed or just keep up the speed? if can_keep_speed and target_vel < vel_towards_point: target_vel = vel_towards_point else: # Small lerp adjustment target_vel = lerp(vel_towards_point, target_vel, 1.2) # Turn and maybe slide self.controls.steer = clip(angle + (2.5 * angle)**3, -1.0, 1.0) if slide and abs(angle) > REQUIRED_ANG_FOR_SLIDE: self.controls.handbrake = True self.controls.steer = sign(angle) else: self.controls.handbrake = False # Overshoot target vel for quick adjustment target_vel = lerp(vel_towards_point, target_vel, 1.2) # Find appropriate throttle/boost if vel_towards_point < target_vel: self.controls.throttle = 1 if boost and vel_towards_point + 25 < target_vel and target_vel > 1400 \ and not self.controls.handbrake and is_heading_towards(angle, dist): self.controls.boost = True else: self.controls.boost = False else: vel_delta = target_vel - vel_towards_point self.controls.throttle = clip(0.2 + vel_delta / 500, 0, -1) self.controls.boost = False if self.controls.handbrake: self.controls.throttle = min(0.4, self.controls.throttle) # Saved if something outside calls start_dodge() in the meantime self.last_point = point return self.controls def avoid_goal_post(self, bot, point): car = bot.info.my_car car_to_point = point - car.pos # Car is not in goal, not adjustment needed if abs(car.pos[Y]) < FIELD_LENGTH / 2: return # Car can go straight, not adjustment needed if car_to_point[X] == 0: return # Do we need to cross a goal post to get to the point? goalx = GOAL_WIDTH / 2 - 100 goaly = FIELD_LENGTH / 2 - 100 t = max((goalx - car.pos[X]) / car_to_point[X], (-goalx - car.pos[X]) / car_to_point[X]) # This is the y coordinate when car would hit a goal wall. Is that inside the goal? crossing_goalx_at_y = abs(car.pos[Y] + t * car_to_point[Y]) if crossing_goalx_at_y > goaly: # Adjustment is needed point[X] = clip(point[X], -goalx, goalx) point[Y] = clip(point[Y], -goaly, goaly) if bot.do_rendering: bot.renderer.draw_line_3d(car.pos, point, bot.renderer.green()) def go_home(self, bot): car = bot.info.my_car home = bot.info.own_goal target = home closest_enemy, enemy_dist = bot.info.closest_enemy(bot.info.ball.pos) car_to_home = home - car.pos dist = norm(car_to_home) vel_f_home = proj_onto_size(car.vel, car_to_home) if vel_f_home * 2 > dist: target = bot.info.ball.pos boost = dist > 1500 or enemy_dist < dist dodge = dist > 1500 or enemy_dist < dist return self.go_towards_point(bot, target, 2300, True, boost=boost, can_dodge=dodge)