def step(self, packet: GameTickPacket, drone: Drone, index: int): # Get centre of small circle. direction_angle = (math.pi / 4) + ((math.pi / 2) * (index // 16)) centre = vec3(dot(rotation(direction_angle), vec2( 1, 0))) * self.big_radius centre[2] = self.height # Angle for the small circle. # Wraps nicely around the small circle. t = self.time_since_start + 2.5 if t > 2 * math.pi: t = 2 * math.pi angle = (t / 16) * (index % 16 - 8) angle += (2 * math.pi / 4) * (index // 16) + (math.pi / 4) target = vec3(dot(rotation(angle), vec2(self.small_radius, 0))) target += centre # Hover controls. drone.hover.up = normalize(drone.position - centre) drone.hover.target = target drone.hover.step(self.dt) drone.controls = drone.hover.controls # If any bot got lost, now they have a chance to recover. if drone.on_ground: drone.controls.jump = True else: drone.controls.jump = False
def step(self, packet: GameTickPacket, drone: Drone, index: int): self.finished = (100 + self.big_radius - self.time_since_start * self.speed) <= 0 # Get centre of small circle. direction_angle = (math.pi / 4) + ((math.pi / 2) * (index // 16)) centre = vec3(dot(rotation(direction_angle), vec2(1, 0))) # Crossing action. centre *= (self.big_radius - self.time_since_start * self.speed) centre[2] = self.height # Angle for the small circle. angle = (2 * math.pi / 16) * (index % 16) angle += (2 * math.pi / 4) * (index // 16 - 1) angle += self.time_since_start * self.spin target = vec3(dot(rotation(angle), vec2(self.small_radius, 0))) target += centre # Different heights. target[2] += (index // 16 - 2) * self.height_diff # Hover controls. drone.hover.up = normalize(drone.position - centre) drone.hover.target = target drone.hover.step(self.dt) drone.controls = drone.hover.controls
def step(self, dt): if not self.flicking: self.carry.step(dt) self.controls = self.carry.controls self.finished = self.carry.finished car = self.car ball = self.info.ball # check if it's a good idea to flick dir_to_target = ground_direction(car, self.target) if (distance(car, ball) < 150 and ground_distance(car, ball) < 100 and dot(car.forward(), dir_to_target) > 0.7 and norm(car.velocity) > clamp( distance(car, self.target) / 3, 1000, 1700) and dot(dir_to_target, ground_direction(car, ball)) > 0.9): self.flicking = True # flick if opponent is close for opponent in self.info.get_opponents(): if (distance(opponent.position + opponent.velocity, car) < max( 300.0, norm(opponent.velocity) * 0.5) and dot(opponent.velocity, direction(opponent, self.info.ball)) > 0.5): if distance(car.position, self.info.ball.position) < 200: self.flicking = True else: self.finished = True else: self.flick.target = self.info.ball.position + self.info.ball.velocity * 0.2 self.flick.step(dt) self.controls = self.flick.controls self.finished = self.flick.finished
def tick(self, packet: GameTickPacket) -> bool: if self.agent.car.on_ground: self.controller.jump = not self.controller.jump self.controller.throttle = 1 return True else: self.controller.jump = self.agent.car.velocity[2] > 100 self.controller.boost = dot(self.agent.car.forward(), vec3( 0, 0, -1)) * dot(self.agent.car.velocity, vec3(0, 0, -1)) < 0 self.controller.throttle = self.controller.boost and self.agent.car.position[ 2] > 150 hitbox = self.agent.car.hitbox() target = normalize( flatten(dot(self.agent.car.orientation, hitbox.half_width))) tmp = vec3(-hitbox.half_width[1], 0, 0) target = dot(self.agent.car.orientation, tmp) + vec3( 0, 0, -hitbox.half_width[0]) # self.agent.draw.vector(self.agent.car.position, target) self.agent.reorientML.target_orientation = look_at( target, self.direction * self.agent.car.left() if abs(self.agent.car.velocity[2]) < 20 else self.agent.car.velocity) self.agent.reorientML.step(1 / self.agent.FPS) self.controller.yaw = self.agent.reorientML.controls.yaw self.controller.pitch = self.agent.reorientML.controls.pitch self.controller.roll = self.agent.reorientML.controls.roll return True
def align(pos: vec3, ball: Ball, goal: vec3): return max( dot(ground_direction(pos, ball), ground_direction(ball, goal)), dot(ground_direction(pos, ball), ground_direction(ball, goal + vec3(800, 0, 0))), dot(ground_direction(pos, ball), ground_direction(ball, goal - vec3(800, 0, 0))))
def t_nearest(self, pos: vec3) -> float: t = 0.5 for i in range(6): r = self.position(t) - pos dr = self.tangent(t) if abs(dot(r, normalize(dr))) < 10.0: break t -= dot(r, dr) / dot(dr, dr) return t
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
def step(self, dt): recovery_time = 0.0 if (self.target is None) else 0.4 if not self.jump.finished: self.jump.step(dt) self.controls = self.jump.controls else: if self.counter == 0: # double jump if self.target is None: self.controls.roll = 0 self.controls.pitch = 0 self.controls.yaw = 0 # air dodge else: target_local = dot(self.target - self.car.position, self.car.orientation) target_local[2] = 0 target_direction = normalize(target_local) self.controls.roll = 0 self.controls.pitch = -target_direction[0] self.controls.yaw = clamp11( sgn(self.car.orientation[2, 2]) * target_direction[1]) if target_local[0] > 0 and dot(self.car.velocity, self.car.forward()) > 500: self.controls.pitch = self.controls.pitch * 0.8 self.controls.yaw = clamp11(self.controls.yaw * 5) elif self.counter == 2: self.controls.jump = 1 elif self.counter >= 4: self.controls.roll = 0 self.controls.pitch = 0 self.controls.yaw = 0 self.controls.jump = 0 self.counter += 1 self.state_timer += dt self.finished = self.jump.finished and self.state_timer > recovery_time and self.counter >= 6
def step(self, dt: float): self.speed = abs(self.speed) car_to_target = (self.target - self.car.location) local_target = dot(car_to_target, self.car.rotation) angle = atan2(local_target[1], local_target[0]) vel = norm(self.car.velocity) in_air = (not self.car.on_ground) on_wall = (self.car.location[2] > 250 and not in_air) reverse = (cos(angle) < 0 and not (on_wall or in_air or self.kickoff)) get_off_wall = (on_wall and local_target[2] > 450) if get_off_wall: car_to_target[2] = -self.car.location[2] local_target = dot(car_to_target, self.car.rotation) angle = atan2(local_target[1], local_target[0]) max_speed = self.determine_max_speed(local_target) self.update_rlu_drive(reverse, max_speed) self.rlu_drive.step(dt) self.finished = self.rlu_drive.finished self.controls = self.rlu_drive.controls self.controls.handbrake = False if reverse: angle = -invert_angle(angle) if self.power_turn and not on_wall: angle *= -1 self.controls.handbrake = (vel > 200) self.controls.steer = cap(angle * 3, -1, 1) self.controls.boost = False if not self.controls.handbrake: self.controls.handbrake = (abs(angle) > radians(70) and vel > 500 and not on_wall) if self.controls.handbrake: self.controls.handbrake = (dot(self.car.velocity, car_to_target) > -150) if in_air: self.aerial_turn.target = look_at(xy(car_to_target), vec3(0, 0, 1)) self.aerial_turn.step(dt) aerial_turn_controls = self.aerial_turn.controls self.controls.pitch = aerial_turn_controls.pitch self.controls.yaw = aerial_turn_controls.yaw self.controls.roll = aerial_turn_controls.roll self.controls.boost = False
def step(self, packet: GameTickPacket, drone: Drone, index: int): if drone.position[2] < 25: drone.since_jumped = 0.0 # Go forward drone.controls.throttle = 1.0 if abs( drone.velocity[1]) < 500 else 0.01 # If near half-line if abs(drone.position[1]) < 200: drone.controls.jump = True else: drone.since_jumped += self.dt height = 50 + drone.since_jumped * 150 angle = 1.0 + drone.since_jumped * 1.2 if index % 2 == 0: angle += math.pi rot = rotation(angle) v = vec3(dot(rot, vec2(1, 0))) drone.hover.target = v * self.radius drone.hover.target[2] = height drone.hover.up = normalize(drone.position) drone.hover.step(self.dt) drone.controls = drone.hover.controls
def pick_easiest_target(self, car: Car, ball: Ball, targets: List[vec3]) -> vec3: to_goal = ground_direction(ball, self.info.their_goal.center) return max(targets, key=lambda target: dot( ground_direction(car, ball) + to_goal * 0.5, ground_direction(ball, target)))
def simulate_landing(self): dummy = Car(self.car) self.trajectory = [vec3(dummy.position)] self.landing = False collision_normal: Optional[vec3] = None dt = 1 / 60 simulation_duration = 0.8 for i in range(int(simulation_duration / dt)): dummy.step(Input(), dt) self.trajectory.append(vec3(dummy.position)) collision_sphere = sphere(dummy.position, 50) collision_ray = Field.collide(collision_sphere) collision_normal = collision_ray.direction if (norm(collision_normal) > 0.0 or dummy.position[2] < 0) and i > 20: self.landing = True self.landing_pos = dummy.position break if self.landing: u = collision_normal f = normalize(dummy.velocity - dot(dummy.velocity, u) * u) l = normalize(cross(u, f)) self.aerial_turn.target = mat3(f[0], l[0], u[0], f[1], l[1], u[1], f[2], l[2], u[2]) else: target_direction = normalize( normalize(self.car.velocity) - vec3(0, 0, 3)) self.aerial_turn.target = look_at(target_direction, vec3(0, 0, 1))
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.aerial_turn.target = three_vec3_to_mat3(f, l, u) else: target_direction = normalize( normalize(self.car.velocity) - vec3(0, 0, 3)) self.aerial_turn.target = look_at(target_direction, vec3(0, 0, 1))
def step(self, dt): car = self.car target = ground(self.target) car_speed = norm(car.velocity) time_left = (ground_distance(car, target) - self.finish_distance) / max(car_speed + 500, 1400) forward_speed = dot(car.forward(), car.velocity) if self.driving and car.on_ground: self.action.target_pos = target self._time_on_ground += dt # check if it's a good idea to dodge, wavedash or halfflip if (self._time_on_ground > 0.2 and car.position[2] < 200 and angle_to(car, target, forward_speed < 0) < 0.1): # if going forward, use a dodge or a wavedash if forward_speed > 0: use_boost_instead = self.waste_boost and car.boost > 20 if car_speed > 1200 and not use_boost_instead: if time_left > self.DODGE_DURATION: dodge = Dodge(car) dodge.duration = 0.05 dodge.direction = vec2(direction(car, target)) self.action = dodge self.driving = False elif time_left > self.WAVEDASH_DURATION: wavedash = Wavedash(car) wavedash.direction = vec2(direction(car, target)) self.action = wavedash self.driving = False # if going backwards, use a halfflip elif time_left > self.HALFFLIP_DURATION and car_speed > 800: self.action = HalfFlip(car, self.waste_boost and time_left > 3) self.driving = False self.action.step(dt) self.controls = self.action.controls # make sure we're not boosting airborne if self.driving and not car.on_ground: self.controls.boost = False # make sure we're not stuck turtling if not car.on_ground: self.controls.throttle = 1 if self.action.finished and not self.driving: self.driving = True self._time_on_ground = 0 self.action = self.drive self.drive.backwards = False if ground_distance(car, target) < self.finish_distance and self.driving: self.finished = True
def nearest_point(box, point, local=False): ''' Takes in an RLU oriented bounding box (obb) object and an RLU vec3. Returns an RLU vec3 for the closest point on box to point. local = True returns the vec3 in box's local coordinates ''' point_local = dot(point - box.center, box.orientation) closest_point_local = vec3( min(max(point_local[0], -box.half_width[0]), box.half_width[0]), min(max(point_local[1], -box.half_width[1]), box.half_width[1]), min(max(point_local[2], -box.half_width[2]), box.half_width[2])) if local: return closest_point_local return dot(box.orientation, closest_point_local) + box.center
def predict_car_drive(self, index, time_limit=2.0, dt=1 / 60) -> List[vec3]: """Simple prediction of a driving car assuming no acceleration.""" car = self.cars[index] time_steps = int(time_limit / dt) speed = norm(car.velocity) ang_vel_z = car.angular_velocity[2] # predict circular path if ang_vel_z != 0 and car.on_ground: radius = speed / ang_vel_z centre = car.position - cross(normalize(xy(car.velocity)), vec3(0, 0, 1)) * radius centre_to_car = vec2(car.position - centre) return [ vec3(dot(rotation(ang_vel_z * dt * i), centre_to_car)) + centre for i in range(time_steps) ] # predict straight path return [ car.position + car.velocity * dt * i for i in range(time_steps) ]
def estimate_time(car: Car, target, dd=1) -> float: turning_radius = 1 / Drive.max_turning_curvature(norm(car.velocity) + 500) turning = angle_between(car.forward() * dd, direction( car, target)) * turning_radius / 1800 if turning < 0.5: turning = 0 dist = ground_distance(car, target) - 200 if dist < 0: return turning speed = dot(car.velocity, car.forward()) time = 0 result = None if car.boost > 0 and dd > 0: boost_time = car.boost / 33.33 result = BOOST.simulate_until_limit(speed, distance_limit=dist, time_limit=boost_time) dist -= result.distance_traveled time += result.time_passed speed = result.speed_reached if dist > 0 and speed < 1410: result = THROTTLE.simulate_until_limit(speed, distance_limit=dist) dist -= result.distance_traveled time += result.time_passed speed = result.speed_reached if result is None or not result.distance_limit_reached: time += dist / speed return time * 1.05 + turning
def shooting_target(agent): """"Method that gives the target for the shooting strategy""" ball = agent.info.ball car = agent.info.my_car car_to_ball = ball.location - car.location backline_intersect = line_backline_intersect(agent.their_goal.center[1], vec2(car.location), vec2(car_to_ball)) if abs(backline_intersect) < 700: goal_to_ball = normalize(car.location - ball.location) error = 0 else: # Right of the ball if -500 > backline_intersect: target = agent.their_goal.corners[3] + vec3(400, 0, 0) # Left of the ball elif backline_intersect > 500: target = agent.their_goal.corners[2] - vec3(400, 0, 0) goal_to_ball = normalize(ball.location - target) # Subtract the goal to car vector difference = goal_to_ball - normalize(car.location - target) error = cap(abs(difference[0]) + abs(difference[1]), 0, 5) goal_to_ball_2d = vec2(goal_to_ball[0], goal_to_ball[1]) test_vector_2d = dot(rotation(0.5 * math.pi), goal_to_ball_2d) test_vector = vec3(test_vector_2d[0], test_vector_2d[1], 0) distance = cap( (40 + distance_2d(ball.location, car.location) * (error**2)) / 1.8, 0, 4000) location = ball.location + vec3( (goal_to_ball[0] * distance), goal_to_ball[1] * distance, 0) # this adjusts the target based on the ball velocity perpendicular # to the direction we're trying to hit it multiplier = cap(distance_2d(car.location, location) / 1500, 0, 2) distance_modifier = cap( dot(test_vector, ball.velocity) * multiplier, -1000, 1000) location += vec3(test_vector[0] * distance_modifier, test_vector[1] * distance_modifier, 0) # another target adjustment that applies if the ball is close to the wall extra = 3850 - abs(location[0]) if extra < 0: location[0] = cap(location[0], -3850, 3850) location[1] = location[1] + (-sign(agent.team) * cap(extra, -800, 800)) return location
def step(self, packet: GameTickPacket, drone: Drone, index: int): drone.hover.up = normalize(drone.position) clockwise_rotation = axis_to_rotation(vec3(0, 0, 0.5)) position_on_circle = normalize(xy(drone.position)) * 2000 drone.hover.target = dot(clockwise_rotation, position_on_circle) drone.hover.target[2] = 1000 drone.hover.step(self.dt) drone.controls = drone.hover.controls
def step(self, dt): vf = dot(self.car.forward(), self.car.velocity) if vf > 100: self.controls.throttle = -1 elif vf < -100: self.controls.throttle = 1 else: self.controls.throttle = 0 self.finished = True
def set_drone_states(self, drones: List[Drone]): for i, drone in enumerate(drones): angle = (2 * math.pi / 64) * i drone.position = vec3(dot(rotation(angle), vec2(self.radius, 0))) drone.position[2] = self.height drone.velocity = vec3(0, 0, 0) drone.orientation = euler_to_rotation( vec3(math.pi / 2, angle, math.pi)) drone.angular_velocity = vec3(0, 0, 0)
def step(self, car: Car, target: vec3, dt) -> SimpleControllerState: self.car = car self.target = target local_pos = dot(self.target, self.car.rotation) local_pos_spherical = spherical(local_pos) local_omega = dot(self.car.angular_velocity, self.car.rotation) theta_error = math.sqrt(local_pos_spherical[1]**2 + local_pos_spherical[2]**2) omega_error = math.sqrt(local_omega[1]**2 + local_omega[2]**2) if omega_error < 0.1 and theta_error < 0.1: self.finished = True else: self.finished = False return self.rotate(car, target, dt)
def get_speed(agent, location): """Returns the target speed given a certain location""" car = agent.info.my_car local = dot(location - car.location, car.rotation) angle = cap(math.atan2(local[1], local[0]), -3, 3) distance = distance_2d(car.location, location) if distance > 2.5 * velocity_2d(car.velocity): return 2250 return 2250 - (400 * (angle**2))
def set_drone_states(self, drones: List[Drone]): for i, drone in enumerate(drones): angle = i * math.pi * 2 / len(drones) rot = rotation(angle) v = vec3(dot(rot, vec2(1, 0))) drone.position = v * self.radius + self.center drone.orientation = look_at(v * -1, vec3(0, 0, 1)) drone.velocity = vec3(0, 0, 0) drone.angular_velocity = vec3(0, 0, 0)
def step(self, packet: GameTickPacket, drone: Drone, index: int): # Calculate shift direction. direction_angle = (math.pi / 4) + ((math.pi / 2) * (index // 16)) direction = vec3(dot(rotation(direction_angle), vec2(1, 0))) # Shift in one direction. angle = (2 * math.pi / 64) * index target = vec3(dot(rotation(angle), vec2(self.start_radius, 0))) target += direction * (self.end_radius - self.start_radius) * ( self.time_since_start / self.duration) target[2] = self.height target = (target + drone.position) / 2 # Hover controls. drone.hover.up = normalize(drone.position) drone.hover.target = target drone.hover.step(self.dt) drone.controls = drone.hover.controls
def estimate_time(car: Car, target, speed, dd=1) -> float: dist = distance(car, target) if dist < 100: return 0 travel = dist / speed turning = angle_between(car.forward() * dd, direction(car, target)) / math.pi * 2 if turning < 1: turning **= 2 acceleration = (speed * dd - dot(car.velocity, car.forward())) / 2100 * 0.2 * dd / max(car.boost / 20, 1) return travel + acceleration + turning * 0.7
def step(self, packet: GameTickPacket, drone: Drone, index: int): radius = 1050 + 150 * self.time_since_start angle = math.pi + self.time_since_start * (math.pi / 5) angle += (2 * math.pi / 64) * index target = vec3(dot(rotation(angle), vec2(radius, 0))) target[2] = self.height drone.hover.up = normalize(-1 * xy(drone.position)) drone.hover.target = target drone.hover.step(self.dt) drone.controls = drone.hover.controls
def should_dodge(agent): return norm(agent.info.ball.location - agent.info.my_car.location) < 300 and max( dot(agent.info.my_car.velocity, agent.info.ball.location - agent.info.my_car.location), dot(agent.info.my_car.forward(), agent.info.ball.location - agent.info.my_car.location)) > 1300 # Go for it! """"Method that checks if we should dodge""" car = agent.info.my_car their_goal = agent.their_goal close_to_goal = distance_2d(car.location, their_goal.center) < 4000 aiming_for_goal = abs( line_backline_intersect(their_goal.center[1], vec2(car.location), vec2(car.forward()))) < 850 bot_to_target = agent.info.ball.location - car.location local_bot_to_target = dot(bot_to_target, agent.info.my_car.rotation) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) close_to_ball = norm(vec2(bot_to_target)) < 750 good_angle = abs(angle_front_to_target) < math.radians(15) return close_to_ball and close_to_goal and aiming_for_goal and good_angle
def get_output(self, info: Game) -> SimpleControllerState: ball = info.ball car = info.my_car local_coords = dot(ball.location - car.location, car.rotation) self.controls.steer = math.copysign(1.0, local_coords[1]) # just set the throttle to 1 so the car is always moving forward self.controls.throttle = 1.0 return self.controls
def toPoint(car: Car, target: vec3): direction = normalize(target - car.position) turnAngleAmount = math.acos( max(-1, min(1, dot(car.forward(), direction)))) rotateToZeroAngle = -atan2(direction) towardsZeroVector = rotate2(car.forward(), rotateToZeroAngle) turnDirection = math.copysign(1, -towardsZeroVector[1]) return PID.fromAngle(car, turnAngleAmount * turnDirection)