class AerialStep(BaseStep): def __init__(self, agent: BeepBoop): super().__init__(agent) self.aerial = Aerial(self.agent.game_info.my_car, vec3(0, 0, 0), 0) self.cancellable: bool = False def handle_aerial_start(self) -> None: ball_prediction: BallPrediction = self.agent.get_ball_prediction_struct() # Find the first viable point on the ball path to aerial to for i in range(ball_prediction.num_slices): loc = ball_prediction.slices[i].physics.location self.aerial.target = vec3(loc.x, loc.y, loc.z) self.aerial.t_arrival = ball_prediction.slices[i].game_seconds if self.aerial.is_viable(): break def get_output(self, packet: GameTickPacket) -> Optional[SimpleControllerState]: self.agent.game_info.read_packet(packet) # RLUtilities doesn't check for equality properly between equal vec3 objects, so we have to use this ghetto way if self.aerial.target[0] == 0 and self.aerial.target[1] == 0 and self.aerial.target[2] == 0: self.handle_aerial_start() self.aerial.step(1 / 60) if not self.aerial.is_viable() or self.aerial.finished: self.cancellable = True return None else: return self.aerial.controls
def execute(self, bot): bot.renderer.draw_string_3d(bot.info.my_car.pos, 1, 1, "Aerial", bot.renderer.red()) self.aerial = Aerial(bot.info.my_car, vec3(0, 0, 0), 0) ball = DropshotBall(bot.info.ball) for i in range(60): ball.step_ds(0.016666) self.aerial.target = ball.pos self.aerial.t_arrival = ball.t # Check if we can reach it by an aerial if self.aerial.is_viable(): # One more step ball.step_ds(0.016666) self.aerial.target = ball.pos + vec3(0, 0, 15) self.aerial.t_arrival = ball.t break if self.aerial.is_viable(): bot.plan = AerialPlan(bot.info.my_car, self.aerial.target, self.aerial.t_arrival) self.drive = Drive(bot.info.my_car, bot.info.ball.pos, 2300) self.drive.step(0.016666) bot.controls = self.drive.controls
class QuickAerial: def __init__(self, bot): self.aerial = None self.drive = None pass def utility(self, bot): ball = bot.info.ball if ball.pos[2] < 1000: return 0 car = bot.info.my_car if car.boost < 30: return 0 car_to_ball = ball.pos - car.pos ctb_flat = vec3(car_to_ball[0], car_to_ball[1], 0) ang = angle_between(ctb_flat, car.forward()) if ang > 1: return 0 vf = norm(car.vel) if vf < 800: return 0 return 0.8 def execute(self, bot): bot.renderer.draw_string_3d(bot.info.my_car.pos, 1, 1, "Aerial", bot.renderer.red()) self.aerial = Aerial(bot.info.my_car, vec3(0, 0, 0), 0) ball = DropshotBall(bot.info.ball) for i in range(60): ball.step_ds(0.016666) self.aerial.target = ball.pos self.aerial.t_arrival = ball.t # Check if we can reach it by an aerial if self.aerial.is_viable(): # One more step ball.step_ds(0.016666) self.aerial.target = ball.pos + vec3(0, 0, 15) self.aerial.t_arrival = ball.t break if self.aerial.is_viable(): bot.plan = AerialPlan(bot.info.my_car, self.aerial.target, self.aerial.t_arrival) self.drive = Drive(bot.info.my_car, bot.info.ball.pos, 2300) self.drive.step(0.016666) bot.controls = self.drive.controls
def torus_flight_pattern(self, packet, drones: List[Drone], start_time) -> StepResult: # self.renderer.begin_rendering(drones[0].index) radian_spacing = 2 * math.pi / len(drones) if len(self.aerials) == 0: for index, drone in enumerate(drones): self.aerials.append( Aerial(self.game_info.cars[drone.index], vec3(0, 0, 0), 0)) self.angular_progress.append(index * radian_spacing) elapsed = packet.game_info.seconds_elapsed - start_time # radius = 4000 - elapsed * 100 if self.previous_seconds_elapsed == 0: time_delta = 0 else: time_delta = packet.game_info.seconds_elapsed - self.previous_seconds_elapsed radius = 900 * (1 + math.cos(elapsed * TORUS_RATE)) + 300 height = 450 * (1 + math.sin(elapsed * TORUS_RATE)) + 800 # self.renderer.draw_string_2d(10, 10, 2, 2, f"r {radius}", self.renderer.white()) # self.renderer.draw_string_2d(10, 30, 2, 2, f"z {drones[0].pos[2]}", self.renderer.white()) for index, drone in enumerate(drones): if "sniped" in drone.attributes: continue # This function was fit from the following data points, where I experimentally found deltas which # worked well with sampled radius values. # {2500, 0.7}, {1000, 0.9}, {500, 1.2}, {200, 2.0} # Originally was 2476 / (radius + 1038) # angular_delta = time_delta * (800 / radius + 0.2) angular_delta = time_delta * RADIUS_SPEED.lerp(radius) self.angular_progress[index] += angular_delta aerial = self.aerials[index] progress = self.angular_progress[index] target = Vec3(radius * math.sin(progress), radius * math.cos(progress), height) to_target = target - Vec3(drone.pos[0], drone.pos[1], drone.pos[2]) # self.renderer.draw_line_3d(drone.pos, target, self.renderer.yellow()) aerial.target = vec3(target.x, target.y, target.z) aerial.t_arrival = drone.time + to_target.length() / 2000 + 0.3 aerial.step(0.008) drone.ctrl.boost = aerial.controls.boost drone.ctrl.pitch = aerial.controls.pitch drone.ctrl.yaw = aerial.controls.yaw drone.ctrl.roll = aerial.controls.roll drone.ctrl.jump = aerial.controls.jump self.previous_seconds_elapsed = packet.game_info.seconds_elapsed # self.renderer.end_rendering() return StepResult(finished=elapsed > 160)
def tick(self, packet: GameTickPacket) -> StepResult: if self.game_info is None: self.game_info = GameInfo(self.index, packet.game_cars[self.index].team) self.game_info.read_packet(packet) if self.aerial is None: self.aerial = Aerial( self.game_info.my_car, vec3(self.target.x, self.target.y, self.target.z), self.arrival_time) self.aerial.step(SECONDS_PER_TICK) controls = SimpleControllerState() controls.boost = self.aerial.controls.boost controls.pitch = self.aerial.controls.pitch controls.yaw = self.aerial.controls.yaw controls.roll = self.aerial.controls.roll controls.jump = self.aerial.controls.jump return StepResult(controls, packet.game_info.seconds_elapsed > self.arrival_time)
class AerialStep(Step): """ This uses the Aerial controller provided by RLUtilities. Thanks chip! It will take care of jumping off the ground and flying toward the target. This will only work properly if you call tick repeatedly on the same instance. """ def __init__(self, target: Vec3, arrival_time: float, index: int): self.index = index self.aerial: Aerial = None self.game_info: GameInfo = None self.target = target self.arrival_time = arrival_time def tick(self, packet: GameTickPacket) -> StepResult: if self.game_info is None: self.game_info = GameInfo(self.index, packet.game_cars[self.index].team) self.game_info.read_packet(packet) if self.aerial is None: self.aerial = Aerial( self.game_info.my_car, vec3(self.target.x, self.target.y, self.target.z), self.arrival_time) self.aerial.step(SECONDS_PER_TICK) controls = SimpleControllerState() controls.boost = self.aerial.controls.boost controls.pitch = self.aerial.controls.pitch controls.yaw = self.aerial.controls.yaw controls.roll = self.aerial.controls.roll controls.jump = self.aerial.controls.jump return StepResult(controls, packet.game_info.seconds_elapsed > self.arrival_time)
def __init__(self, car: Car, ball_predictions, predicate: callable = None, power = 1000): self.ball: Ball = None self.is_viable = True #find the first reachable ball slice that also meets the predicate test_aerial = Aerial(car, vec3(0, 0, 0), 0) for ball in ball_predictions: test_aerial.target = ball.pos test_aerial.t_arrival = ball.t test_aerial.calculate_course() if test_aerial.B_avg < power and (predicate is None or predicate(car, ball)): self.ball = ball break #if no slice is found, use the last one if self.ball is None: self.ball = ball_predictions[-1] self.is_viable = False self.time = self.ball.t self.ground_pos = ground(self.ball.pos) self.pos = self.ball.pos
from RLUtilities.Simulation import Car, Ball from RLUtilities.LinearAlgebra import vec3, dot from RLUtilities.Maneuvers import AerialTurn, Aerial c = Car() b = Ball() b.pos = vec3(0, 0, 1000) b.vel = vec3(0, 0, 0) b.omega = vec3(0, 0, 0) b.t = 0 action = Aerial(c, b.pos, b.t) b.step(0.0166) print(action.t_arrival) print(action.target)
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.info.read_packet(packet) self.controls = SimpleControllerState() if self.timer == 0.0: self.csign = random.choice([-1, 1]) # this just initializes the car and ball # to different starting points each time c_position = Vector3(random.uniform(-1000, 1000), random.uniform(-4500, -4000), 25) car_state = CarState(physics=Physics( location=c_position, velocity=Vector3(0, 1000, 0), rotation=Rotator(0, 1.5 * self.csign, 0), angular_velocity=Vector3(0, 0, 0) )) self.bsign = random.choice([-1, 1]) b_position = Vector3(random.uniform(-3500, -3000) * self.bsign, random.uniform(-1500, 1500), random.uniform( 150, 500)) b_velocity = Vector3(random.uniform( 1000, 1500) * self.bsign, random.uniform(- 500, 500), random.uniform( 1000, 1500)) ball_state = BallState(physics=Physics( location=b_position, velocity=b_velocity, rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0) )) self.set_game_state(GameState( ball=ball_state, cars={self.index: car_state}) ) self.increment_timer = True if self.timer < 0.3: self.controls.throttle = 1 * self.csign else: if self.action == None: # set empty values for target and t_arrival initially self.action = Aerial(self.info.my_car, vec3(0,0,0), 0) # predict where the ball will be prediction = Ball(self.info.ball) self.ball_predictions = [vec3(prediction.pos)] for i in range(150): prediction.step(0.016666) prediction.step(0.016666) self.ball_predictions.append(vec3(prediction.pos)) # if the ball is in the air if prediction.pos[2] > 100: self.action.target = prediction.pos self.action.t_arrival = prediction.t # check if we can reach it by an aerial if self.action.is_viable(): break nsteps = 30 delta_t = self.action.t_arrival - self.info.my_car.time prediction = Car(self.info.my_car) self.car_predictions = [vec3(prediction.pos)] for i in range(nsteps): prediction.step(Input(), delta_t / nsteps) self.car_predictions.append(vec3(prediction.pos)) r = 200 self.renderer.begin_rendering() purple = self.renderer.create_color(255, 230, 30, 230) white = self.renderer.create_color(255, 230, 230, 230) x = vec3(r,0,0) y = vec3(0,r,0) z = vec3(0,0,r) target = self.action.target future = self.action.target - self.action.A self.renderer.draw_polyline_3d(self.ball_predictions, purple) self.renderer.draw_line_3d(target - x, target + x, purple) self.renderer.draw_line_3d(target - y, target + y, purple) self.renderer.draw_line_3d(target - z, target + z, purple) self.renderer.draw_polyline_3d(self.car_predictions, white) self.renderer.draw_line_3d(future - x, future + x, white) self.renderer.draw_line_3d(future - y, future + y, white) self.renderer.draw_line_3d(future - z, future + z, white) self.renderer.end_rendering() self.action.step(1.0 / 60.0) self.controls = self.action.controls if self.action.finished or self.timer > 10.0: self.timer = 0.0 self.action = None self.increment_timer = False self.predictions = [] if self.increment_timer: self.timer += 1.0 / 60.0 self.info.my_car.last_input.roll = self.controls.roll self.info.my_car.last_input.pitch = self.controls.pitch self.info.my_car.last_input.yaw = self.controls.yaw self.info.my_car.last_input.boost = self.controls.boost return self.controls
def __init__(self, agent: BeepBoop): super().__init__(agent) self.aerial = Aerial(self.agent.game_info.my_car, vec3(0, 0, 0), 0) self.cancellable: bool = False