def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.game.read_game_information(packet, self.get_rigid_body_tick(), self.get_field_info()) self.controls = SimpleControllerState() if not self.action: self.action = Reorient(self.my_car) self.action.eps_phi = 0.01 self.action.eps_omega = 0.02 if self.timer == 0.0: # randomly generate a proper orthogonal matrix self.action.target_orientation = axis_to_rotation( vec3(random.uniform(-2, 2), random.uniform(-2, 2), random.uniform(-2, 2))) o = self.action.target_orientation f = vec3(o[0, 0], o[1, 0], o[2, 0]) position = Vector3(0, 0, 1000) velocity = Vector3(0, 0, 0) car_state = CarState( physics=Physics(location=position, velocity=velocity)) # spawn the ball in front of the desired orientation to visually indicate where we're trying to go ball_state = BallState( physics=Physics(location=Vector3(500 * f[0], 500 * f[1], 500 * f[2] + 1000), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) self.set_game_state(GameState(ball=ball_state, cars={0: car_state})) self.action.step(self.game.time_delta) self.controls = self.action.controls self.timer += self.game.time_delta if self.timer > 2.0: self.timer = 0.0 error = angle_between(self.my_car.orientation, self.action.target_orientation) self.renderer.begin_rendering("path") red = self.renderer.create_color(255, 230, 30, 30) self.renderer.draw_string_2d(50, 50, 3, 3, f"error: {error:.4f} radians", red) self.renderer.draw_string_2d(50, 100, 3, 3, f"Roll: {self.controls.roll:+.2f}", red) self.renderer.draw_string_2d(50, 150, 3, 3, f"Pitch: {self.controls.pitch:+.2f}", red) self.renderer.draw_string_2d(50, 200, 3, 3, f"Yaw: {self.controls.yaw:+.2f}", red) self.renderer.end_rendering() return self.controls
def __init__(self, car: Car, info: GameInfo, target=None): self.drive = Drive(car) self.reorient = Reorient(car) self.jumping = False self.time_for_jump = float("inf") self.timer = 0.0 super().__init__(car, info, target)
def __init__(self, car: Car, jump_when_upside_down=True): super().__init__(car) self.jump_when_upside_down = jump_when_upside_down self.landing = False self.reorient = Reorient(self.car) self.trajectory: List[vec3] = [] self.landing_pos: Optional[vec3] = None
class AimDodge(AirDodge): """ Execute a regular dodge, but also turn the car towards the target (and slightly more up) before dodging. Useful for dodging into the ball. """ def __init__(self, car: Car, duration: float, target: vec3): super().__init__(car, duration, target) self.reorient = Reorient(car) def step(self, dt): super().step(dt) if not self.jump.finished and not self.car.on_ground: target_direction = direction(self.car, self.target + vec3(0, 0, 200)) up = target_direction * (-1) up[2] = 1 up = normalize(up) self.reorient.target_orientation = look_at(target_direction, up) self.reorient.step(dt) self.controls.pitch = self.reorient.controls.pitch self.controls.yaw = self.reorient.controls.yaw self.controls.roll = self.reorient.controls.roll
class DoubleJumpStrike(Strike): def intercept_predicate(self, car, ball): return 250 < ball.position[2] < 550 def __init__(self, car: Car, info: GameInfo, target=None): self.drive = Drive(car) self.reorient = Reorient(car) self.jumping = False self.time_for_jump = float("inf") self.timer = 0.0 super().__init__(car, info, target) def configure(self, intercept: Intercept): super().configure(intercept) self.drive.target_pos = ground(intercept.position) self.time_for_jump = self.double_jump_time_needed( intercept.position[2]) def interruptible(self) -> bool: return not self.jumping and super().interruptible() def step(self, dt): if self.jumping: self.controls = Input() # first jump for full 0.2 sec if self.timer <= 0.2: self.controls.jump = True # single tick between jumps elif self.timer <= 0.2 + dt * JUMP_FALSE_TICKS: self.controls.jump = False # second jump else: self.controls.jump = True self.jumping = False self.timer += dt else: self.finished = self.intercept.time < self.info.time if self.car.on_ground: # manage speed before jump distance_to_target = ground_distance(self.car.position, self.intercept.position) if distance_to_target < MIN_DIST_BEFORE_SPEED_CONTROL: target_speed = distance_to_target / self.time_for_jump self.drive.target_speed = -target_speed if self._should_strike_backwards else target_speed self.drive.step(dt) self.controls = self.drive.controls else: super().step(dt) # decide when to jump ground_vel = ground(self.car.velocity) direction_to_target = ground_direction(self.car.position, self.intercept.position) alignment = dot(normalize(ground_vel), direction_to_target) # check alignment if alignment >= MIN_ALIGNMENT: # check that speed is correct speed_in_direction = dot(ground_vel, direction_to_target) time_to_target = distance_to_target / speed_in_direction if self.time_for_jump - ALLOWED_TIME_ERROR <= time_to_target <= self.time_for_jump + ALLOWED_TIME_ERROR: self.jumping = True # after jump (when the car is in the air) else: # face the ball for some additional height self.reorient.target_orientation = look_at( direction(self.car.position, self.info.ball), vec3(0, 0, 1)) self.reorient.step(dt) self.controls = self.reorient.controls @staticmethod def double_jump_time_needed(height): """Return the time needed for the double jump to reach a given height""" # polynomial approximation a = 1.872348977E-8 * height * height * height b = -1.126747937E-5 * height * height c = 3.560647225E-3 * height d = -7.446058499E-3 return a + b + c + d
def __init__(self, car: Car, duration: float, target: vec3): super().__init__(car, duration, target) self.reorient = Reorient(car)
class Recovery(Maneuver): """Boost down and try to land smoothly""" def __init__(self, car: Car, jump_when_upside_down=True): super().__init__(car) self.jump_when_upside_down = jump_when_upside_down self.landing = False self.reorient = Reorient(self.car) self.trajectory: List[vec3] = [] self.landing_pos: Optional[vec3] = None def interruptible(self) -> bool: return False def step(self, dt): self.simulate_landing() self.reorient.step(dt) self.controls = self.reorient.controls self.controls.boost = angle_between(self.car.forward(), vec3( 0, 0, -1)) < 1.5 and not self.landing self.controls.throttle = 1 # in case we're turtling # jump if the car is upside down and has wheel contact if (self.jump_when_upside_down and self.car.on_ground and dot(self.car.up(), vec3(0, 0, 1)) < -0.95): self.controls.jump = True self.landing = False else: self.finished = self.car.on_ground def simulate_landing(self): pos = vec3(self.car.position) vel = vec3(self.car.velocity) grav = vec3(0, 0, -650) self.trajectory = [vec3(pos)] self.landing = False collision_normal: Optional[vec3] = None dt = 1 / 60 simulation_duration = 0.8 for i in range(int(simulation_duration / dt)): pos += vel * dt vel += grav * dt if norm(vel) > 2300: vel = normalize(vel) * 2300 self.trajectory.append(vec3(pos)) collision_sphere = sphere(pos, 50) collision_ray = Field.collide(collision_sphere) collision_normal = collision_ray.direction if (norm(collision_normal) > 0.0 or pos[2] < 0) and i > 20: self.landing = True self.landing_pos = pos break if self.landing: u = collision_normal f = normalize(vel - dot(vel, u) * u) l = normalize(cross(u, f)) self.reorient.target_orientation = three_vec3_to_mat3(f, l, u) else: target_direction = normalize( normalize(self.car.velocity) - vec3(0, 0, 3)) self.reorient.target_orientation = look_at(target_direction, vec3(0, 0, 1)) def render(self, draw: DrawingTool): if self.landing: draw.color(draw.cyan) draw.polyline(self.trajectory) if self.landing_pos: draw.crosshair(self.landing_pos) draw.color(draw.green) draw.vector(self.car.position, forward(self.reorient.target_orientation) * 200) draw.color(draw.red) draw.vector(self.car.position, self.car.forward() * 200)