def run(self, agent): target = agent.ball.location + Vector(y=200 * side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) defaultThrottle(agent, 2300) distance = local_target.magnitude() agent.controller.throttle = 1 agent.controller.boost = True if distance < 650: if len(agent.foes ) > 0 and agent.predictions['closest_enemy'] > 1000: if distance < 100 or distance > 500: agent.pop() agent.kickoff_done = True defaultPD( agent, agent.ball.location - Vector(y=500 * side(agent.team))) elif distance < 450: agent.pop() agent.kickoff_done = True agent.push(flip(agent.me.local(agent.foe_goal.location)))
def run(self, agent): if self.start_time is None: self.start_time = agent.time if not self.wave_dash: time_elapsed = agent.time - self.start_time if time_elapsed > 0.75: self.wave_dash = True agent.push(wave_dash()) target = agent.ball.location + Vector(y=200 * side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 650: if len(agent.foes ) > 0 and agent.predictions['closest_enemy'] > 1000: if distance < 100 or distance > 700: agent.pop() agent.kickoff_done = True else: agent.pop() agent.kickoff_done = True agent.push( flip( agent.me.local(agent.foe_goal.location - agent.me.location)))
def run(self, agent): local_target = agent.me.local((agent.ball.location - agent.me.location).flatten()) defaultPD(agent, local_target) agent.controller.throttle = 1 if not agent.me.airborne: agent.pop()
def run(self, agent): if self.target is not None: local_target = agent.me.local((self.target - agent.me.location).flatten()) else: local_target = agent.me.local(agent.me.velocity.flatten()) defaultPD(agent, local_target) agent.controller.throttle = 1 if not agent.me.airborne: agent.pop()
def run(self, agent): if agent.me.boost == 0: agent.pop() agent.push(self.face) target = agent.me.local(agent.me.forward.flatten() * 100 - Vector(z=100)) defaultPD(agent, target) if not agent.me.airborne: agent.pop() elif abs(Vector(x=1).angle(target)) < 0.5: agent.controller.boost = True
def run(self, agent): local_target = agent.me.local(agent.me.velocity.flatten( )) if self.target is None else agent.me.local( (self.target - agent.me.location).flatten()) agent.dbg_2d(f"Recovering towards {self.target}") recover_on_ceiling = agent.me.velocity.z > 0 and agent.me.location.z > 1500 if recover_on_ceiling: agent.dbg_2d(f"Recovering on the ceiling") defaultPD(agent, local_target, upside_down=recover_on_ceiling) agent.controller.throttle = 1 if not agent.me.airborne: agent.pop()
def run(self, agent): target = agent.ball.location car_to_target = target - agent.me.location distance_remaining = car_to_target.flatten().magnitude() angle_to_target = abs( Vector(x=1).angle2D(agent.me.local_location(target))) direction = 1 if angle_to_target < 2.2 else -1 local_target = agent.me.local_location(target) # Some adjustment to the final target to ensure it's inside the field and we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5120 - (agent.me.hitbox.width / 2): local_target.x = cap(local_target.x, -750, 750) angles = defaultPD(agent, local_target) defaultThrottle(agent, 1400) agent.controller.handbrake = angle_to_target > 1.54 velocity = agent.me.local_velocity().x if distance_remaining < self.exit_distance: agent.pop() if self.exit_flip: agent.push(flip(local_target)) elif angle_to_target < 0.05 and velocity > 600 and velocity < 1400 and distance_remaining / velocity > 3: agent.push(flip(local_target)) elif angle_to_target >= 2 and distance_remaining > 1000 and velocity < 200 and distance_remaining / abs( velocity) > 2: agent.push(flip(local_target, True)) elif agent.me.airborne: agent.push(recovery(local_target))
def run(self, agent): target = agent.ball.location car_to_target = target - agent.me.location distance_remaining = car_to_target.flatten().magnitude() # Some adjustment to the final target to ensure it's inside the field and we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5150: target.x = cap(target.x, -750, 750) local_target = agent.me.local(target - agent.me.location) angles = defaultPD(agent, local_target) defaultThrottle(agent, 1400) agent.controller.boost = False agent.controller.handbrake = True if abs( angles[1]) > 2.3 else agent.controller.handbrake velocity = 1 + agent.me.velocity.magnitude() if distance_remaining < self.exit_distance: agent.pop() if self.exit_flip: agent.push(flip(local_target)) elif abs( angles[1] ) < 0.05 and velocity > 600 and velocity < 2150 and distance_remaining / velocity > 2.0: agent.push(flip(local_target)) elif abs(angles[1]) > 2.8 and velocity < 200: agent.push(flip(local_target, True)) elif agent.me.airborne: agent.push(recovery(target))
def run(self, agent: VirxERLU): print("running speedflip routine") if self.stage == 0: agent.controller.boost = True if agent.me.boost > self.old_boost: self.stage = 1 agent.print(f"Next stage: {self.stage}") else: self.old_boost = agent.me.boost elif self.stage == 1: angles = defaultPD( agent, agent.me.local_location(Vector(110 * sign(agent.me.location.x)))) if abs(angles[1]) < 0.1: self.stage = 2 agent.print(f"Next stage: {self.stage}") elif self.stage == 2: agent.push(speed_flip()) self.stage = 3 agent.print(f"Next stage: {self.stage}") elif self.stage == 3: # TODO do a second flip is the opponent is speedflipping as well if False: agent.push( flip( agent.me.local_location( Vector(120 * sign(agent.me.location.x))))) self.stage = 4 agent.print(f"Next stage: {self.stage}") elif self.stage == 4: agent.pop()
def run(self, agent): if self.flip: agent.kickoff_done = True agent.pop() return target = agent.ball.location + Vector(y=200*side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 550: self.flip = True agent.push(flip(agent.me.local(agent.foe_goal.location - agent.me.location)))
def run(self, agent): self.step += 1 target_switch = { 0: agent.me.forward.flatten() * 100 + Vector(z=50), 1: agent.me.forward.flatten() * 100, 2: agent.me.forward.flatten() * 100 - Vector(z=50), 3: agent.me.forward.flatten() * 100 } target_up = { 0: agent.me.local(Vector(z=1)), 1: agent.me.local(Vector(y=-50, z=1)), 2: agent.me.local(Vector(z=1)), 3: agent.me.local(Vector(y=50, z=1)) } defaultPD(agent, agent.me.local(target_switch[self.direction]), up=target_up[self.direction]) if self.direction == 0: agent.controller.throttle = 1 elif self.direction == 2: agent.controller.throttle = -1 else: agent.controller.handbrake = True if self.step < 1: agent.controller.jump = True elif self.step < 4: pass elif not agent.me.airborne: agent.pop() elif agent.me.location.z + (agent.me.velocity.z * 0.2) < 5: agent.controller.jump = True agent.controller.yaw = 0 if self.direction in {0, 2}: agent.controller.roll = 0 agent.controller.pitch = -1 if self.direction is 0 else 1 else: agent.controller.roll = -1 if self.direction is 1 else 1 agent.controller.pitch = 0
def run(self, agent): agent.shooting = True if self.start_time is None: self.start_time = agent.time car_to_ball, distance = (agent.ball.location - agent.me.location).normalize(True) ball_to_target = (self.target - agent.ball.location).normalize() relative_velocity = car_to_ball.dot(agent.me.velocity - agent.ball.velocity) if relative_velocity != 0: eta = cap(distance / cap(relative_velocity, 400, 2300), 0, 1.5) else: eta = 1.5 # If we are approaching the ball from the wrong side the car will try to only hit the very edge of the ball left_vector = car_to_ball.cross(Vector(z=1)) right_vector = car_to_ball.cross(Vector(z=-1)) target_vector = -ball_to_target.clamp(left_vector, right_vector) final_target = agent.ball.location + (target_vector * (distance / 2)) # Some adjustment to the final target to ensure we don't try to dirve through any goalposts to reach it if abs(agent.me.location.y) > 5150: final_target.x = cap(final_target.x, -750, 750) agent.line(final_target - Vector(z=100), final_target + Vector(z=100), [255, 255, 255]) angles = defaultPD(agent, agent.me.local(final_target - agent.me.location)) defaultThrottle( agent, 2300 if distance > 1600 else 2300 - cap(1600 * abs(angles[1]), 0, 2050)) agent.controller.boost = False if agent.me.airborne or abs( angles[1]) > 0.3 else agent.controller.boost agent.controller.handbrake = True if abs( angles[1]) > 2.3 else agent.controller.handbrake if abs(angles[1]) < 0.05 and (eta < 0.45 or distance < 150): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(flip(agent.me.local(car_to_ball))) elif agent.time - self.start_time > 3: agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1
def run(self, agent): if self.ball: target = (agent.ball.location - agent.me.location).flatten() else: target = agent.me.velocity.flatten() if self.target is None else ( self.target - agent.me.location).flatten() if agent.gravity.z < -550 and agent.gravity.z > -750: if self.counter == 0 and abs(Vector(x=1).angle(target)) <= 0.05: agent.pop() return if self.counter < 3: self.counter += 1 target = agent.me.local(target) if self.counter < 3: agent.controller.jump = True elif agent.me.airborne and abs(Vector(x=1).angle(target)) > 0.05: defaultPD(agent, target) else: agent.pop() else: target = agent.me.local(target) angle_to_target = abs(Vector(x=1).angle2D(target)) if angle_to_target > 0.1: if self.start_loc is None: self.start_loc = agent.me.location direction = -1 if angle_to_target < 1.57 else 1 agent.controller.steer = cap(target.y / 100, -1, 1) * direction agent.controller.throttle = 0.5 * direction agent.controller.handbrake = True else: agent.pop() if self.start_loc is not None: agent.push(goto(self.start_loc, target, True))
def run(self, agent): if self.start_time is None: self.start_time = agent.time car_to_boost = self.boost.location - agent.me.location distance_remaining = car_to_boost.flatten().magnitude() agent.line(self.boost.location - Vector(z=500), self.boost.location + Vector(z=500), [0, 255, 0]) if self.target is not None: vector = (self.target - self.boost.location).normalize() side_of_vector = sign(vector.cross(Vector(z=1)).dot(car_to_boost)) car_to_boost_perp = car_to_boost.cross( Vector(z=side_of_vector)).normalize() adjustment = car_to_boost.angle(vector) * distance_remaining / 3.14 final_target = self.boost.location + (car_to_boost_perp * adjustment) car_to_target = (self.target - agent.me.location).magnitude() else: adjustment = 9999 car_to_target = 0 final_target = self.boost.location # Some adjustment to the final target to ensure it's inside the field and we don't try to dirve through any goalposts to reach it if abs(agent.me.location.y) > 5150: final_target.x = cap(final_target.x, -750, 750) local_target = agent.me.local(final_target - agent.me.location) angles = defaultPD(agent, local_target) defaultThrottle(agent, 2300) agent.controller.boost = self.boost.large if abs( angles[1]) < 0.3 else False agent.controller.handbrake = True if abs( angles[1]) > 2.3 else agent.controller.handbrake velocity = 1 + agent.me.velocity.magnitude() if not self.boost.active or agent.me.boost >= 99.0 or distance_remaining < 350: agent.pop() elif agent.me.airborne: agent.push(recovery(self.target)) elif abs(angles[1]) < 0.05 and velocity > 600 and velocity < 2150 and ( distance_remaining / velocity > 2.0 or (adjustment < 90 and car_to_target / velocity > 2.0)): agent.push(flip(local_target)) elif agent.time - self.start_time > 6 and not agent.stack[ -1].__class__.__name__ == "flip": agent.pop()
def run(self, agent): if self.start_time == -1: self.start_time = agent.time if self.flip or agent.time - self.start_time > 3: agent.kickoff_done = True agent.pop() return target = agent.ball.location + Vector(y=( 200 if agent.gravity.z < -600 and agent.gravity.z > -700 else 50) * side(agent.team)) local_target = agent.me.local_location(target) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 550: self.flip = True agent.push(flip(agent.me.local_location(agent.foe_goal.location)))
def run(self, agent, manual=False): car_to_target = self.target - agent.me.location distance_remaining = car_to_target.flatten().magnitude() agent.dbg_2d(distance_remaining) agent.line(self.target - Vector(z=500), self.target + Vector(z=500), [255, 0, 255]) if (not self.brake and distance_remaining < 350) or (self.brake and distance_remaining < (agent.me.local(agent.me.velocity).x ** 2 * -1) / (2 * brake_accel.x)): if not manual: agent.pop() if self.brake: agent.push(brake()) return if self.vector != None: # See commends for adjustment in jump_shot or aerial for explanation side_of_vector = sign(self.vector.cross(Vector(z=1)).dot(car_to_target)) car_to_target_perp = car_to_target.cross(Vector(z=side_of_vector)).normalize() adjustment = car_to_target.angle(self.vector) * distance_remaining / 3.14 final_target = self.target + (car_to_target_perp * adjustment) else: final_target = self.target # Some adjustment to the final target to ensure it's inside the field and we don't try to dirve through any goalposts to reach it if abs(agent.me.location.y) > 5150: final_target.x = cap(final_target.x, -750, 750) local_target = agent.me.local(final_target - agent.me.location) angles = defaultPD(agent, local_target, self.direction) defaultThrottle(agent, 2300, self.direction) if len(agent.friends) > 0 and agent.me.local(agent.me.velocity).x < 250 and agent.controller.throttle > 0.75 and min(agent.me.location.flat_dist(car.location) for car in agent.friends) < 251: agent.push(flip(Vector(y=250))) return if agent.me.boost < 30 or (agent.playstyle is agent.playstyles.Defensive and agent.predictions['self_from_goal'] < 4000): agent.controller.boost = False agent.controller.handbrake = True if abs(angles[1]) >= 2.3 or (agent.me.local(agent.me.velocity).x >= 1400 and abs(angles[1]) > 1.5) else agent.controller.handbrake velocity = 1+agent.me.velocity.magnitude() if abs(angles[1]) < 0.05 and velocity > 600 and velocity < 2150 and distance_remaining / velocity > 2: agent.push(flip(local_target)) elif abs(angles[1]) > 2.8 and velocity < 200 and distance_remaining / velocity > 2: agent.push(flip(local_target, True)) elif agent.me.airborne: agent.push(recovery(self.target))
def run(self, agent): agent.shooting = True agent.shot_weight = agent.max_shot_weight - 1 if self.ball_location is None or not shot_valid(agent, self, threshold=75): self.ball_location, self.intercept_time, self.direction = self.get_intercept(agent) if self.ball_location is None: agent.shooting = False agent.shot_weight = -1 agent.pop() return agent.shot_time = self.intercept_time t = self.intercept_time - agent.time # if we ran out of time, just pop # this can be because we were successful or not - we can't tell if t < -0.3: agent.shooting = False agent.shot_weight = -1 agent.pop() return if self.brake: if agent.ball.location.dist(agent.me.location) < 250 and agent.ball.location.y * side(agent.team) + 10 < agent.me.location.y and agent.ball.location.z < 190: agent.pop() agent.flip(agent.me.local(agent.ball.location)) else: # current velocity u = agent.me.local(agent.me.velocity).x a = brake_accel.x # calculate how much distance we need to slow down x = (u ** 2 * -1) / (2 * a) if self.ball_location.dist(agent.me.location) <= x: self.brake = True agent.push(brake()) return agent.line(self.ball_location.flatten(), self.ball_location.flatten() + Vector(z=250), color=[255, 0, 255]) angles = defaultPD(agent, agent.me.local(self.ball_location - agent.me.location), self.direction) # We want to get there before the ball does, so take the time we have and get 3 fifths of it required_speed = cap(agent.me.location.dist(self.ball_location) / ((self.intercept_time - agent.time) * (3/5)), 600, 2275) defaultThrottle(agent, required_speed, self.direction) agent.controller.boost = False if abs(angles[1]) > 0.3 else agent.controller.boost agent.controller.handbrake = True if abs(angles[1]) >= 2.3 or (agent.me.local(agent.me.velocity).x >= 1400 and abs(angles[1]) > 1.5) and self.direction == 1 else False
def run(self, agent): if not agent.shooting: agent.shooting = True if self.start_time is None: self.start_time = agent.time car_to_ball, distance = (agent.ball.location - agent.me.location).normalize(True) ball_to_target = (self.target - agent.ball.location).normalize() angle_to_target = abs(Vector(x=1).angle2D(agent.me.local(car_to_ball))) relative_velocity = car_to_ball.dot(agent.me.velocity - agent.ball.velocity) eta = cap(distance / cap(relative_velocity, 400, 1400), 0, 1.5) if relative_velocity != 0 else 1.5 # If we are approaching the ball from the wrong side the car will try to only hit the very edge of the ball left_vector = car_to_ball.cross(Vector(z=1)) right_vector = car_to_ball.cross(Vector(z=-1)) target_vector = -ball_to_target.clamp2D(left_vector, right_vector) final_target = agent.ball.location + (target_vector * (distance / 2)) # Some adjustment to the final target to ensure we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5130: final_target.x = cap(final_target.x, -750, 750) agent.line(final_target - Vector(z=100), final_target + Vector(z=100), (255, 255, 255)) angles = defaultPD(agent, agent.me.local_location(final_target)) defaultThrottle(agent, 1400) agent.controller.handbrake = angle_to_target > 1.54 if abs(angles[1]) < 0.05 and (eta < 0.45 or distance < 150): agent.pop() agent.shooting = False agent.push(flip(agent.me.local(car_to_ball))) elif agent.time - self.start_time > 0.24: # This will run for 3 ticks, then pop agent.pop() agent.shooting = False
def run(self, agent, manual=False): car_to_target = self.target - agent.me.location distance_remaining = car_to_target.flatten().magnitude() angle_to_target = abs( Vector(x=1).angle2D(agent.me.local(car_to_target))) direction = 1 if angle_to_target <= 2 or ( agent.gravity.z > -450 and distance_remaining >= 1000) else -1 agent.dbg_2d(f"Angle to target: {angle_to_target}") agent.dbg_2d(f"Distance to target: {distance_remaining}") agent.line(self.target - Vector(z=500), self.target + Vector(z=500), (255, 0, 255)) if (not self.brake and distance_remaining < 350) or ( self.brake and distance_remaining * 0.95 < (agent.me.local_velocity().x**2 * -1) / (2 * brake_accel.x)): if not manual: agent.pop() if self.brake: agent.push(brake()) return final_target = self.target.copy() # Some adjustment to the final target to ensure it's inside the field and we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5120 - (agent.me.hitbox.length / 2): final_target.x = cap(final_target.x, -750, 750) if self.vector is not None: # See comments for adjustment in jump_shot for explanation side_of_vector = sign( self.vector.cross(Vector(z=1)).dot(car_to_target)) car_to_target_perp = car_to_target.cross( Vector(z=side_of_vector)).normalize() adjustment = car_to_target.angle2D( self.vector) * distance_remaining / 3.14 final_target += car_to_target_perp * adjustment local_target = agent.me.local_location(final_target) defaultPD(agent, local_target) target_speed = 2300 if distance_remaining > 640 else 1400 defaultThrottle(agent, target_speed * direction) # this is to break rule 1's with TM8'S ONLY # 251 is the distance between center of the 2 longest cars in the game, with a bit extra if len(agent.friends) > 0 and agent.me.local_velocity( ).x < 50 and agent.controller.throttle == 1 and min( agent.me.location.flat_dist(car.location) for car in agent.friends) < 251: if self.rule1_timer == -1: self.rule1_timer = agent.time elif agent.time - self.rule1_timer > 1.5: agent.push(flip(Vector(y=250))) return elif self.rule1_timer != -1: self.rule1_timer = -1 if distance_remaining < 320: agent.controller.boost = False agent.controller.handbrake = angle_to_target > 1.54 if direction == 1 else angle_to_target < 2.2 velocity = agent.me.local_velocity().x if agent.boost_amount != 'unlimited' and angle_to_target < 0.03 and distance_remaining > 1920 and velocity > 600 and velocity < 2150 and distance_remaining / velocity > 2: if agent.gravity.z < -450: agent.push(wave_dash()) else: agent.push(flip(local_target)) elif direction == -1 and distance_remaining > 1000 and velocity < 200: agent.push(flip(local_target, True)) elif agent.me.airborne: agent.push(recovery(self.target))
def run(self, agent): agent.shooting = True if self.time is -1: elapsed = 0 self.time = agent.time agent.print( f"Enter aerial - Hit ball {round(agent.me.location.dist(self.target) * 1000) / 1000}uu's away in {round((self.intercept_time - self.time) * 1000) / 1000}s" ) else: elapsed = agent.time - self.time T = self.intercept_time - agent.time xf = agent.me.location + agent.me.velocity * T + 0.5 * agent.gravity * T**2 vf = agent.me.velocity + agent.gravity * T if self.jumping: if self.jump_time == -1: jump_elapsed = 0 self.jump_time = agent.time else: jump_elapsed = agent.time - self.jump_time tau = jump_max_duration - jump_elapsed if jump_elapsed == 0: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * T vf += agent.me.up * jump_acc * tau xf += agent.me.up * jump_acc * tau * (T - 0.5 * tau) vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * (T - tau) if jump_elapsed < jump_max_duration: agent.controller.jump = True elif elapsed >= jump_max_duration and self.counter < 3: agent.controller.jump = False self.counter += 1 elif elapsed < 0.3: agent.controller.jump = True else: self.jumping = jump_elapsed <= 0.3 # jump_max_duration else: agent.controller.jump = False delta_x = self.target - xf direction = delta_x.normalize() agent.line(agent.me.location, self.target, agent.renderer.white()) agent.line(self.target - Vector(z=100), self.target + Vector(z=100), agent.renderer.red()) agent.line(agent.me.location, direction, agent.renderer.green()) if delta_x.norm() > 50: defaultPD(agent, agent.me.local(delta_x)) else: defaultPD(agent, agent.me.local(self.target)) if jump_max_duration <= elapsed and elapsed < 0.3 and self.counter**3: agent.controller.roll = agent.controller.pitch = agent.controller.yaw = agent.controller.steer = 0 if agent.me.forward.angle3D(direction) < 0.3: if delta_x.norm() > 50: agent.controller.boost = 1 agent.controller.throttle = 0 else: agent.controller.boost = 0 agent.controller.throttle = cap(0.5 * throttle_accel * T * T, 0, 1) else: agent.controller.boost = agent.controller.throttle = 0 still_valid = shot_valid(agent, self, threshold=250, target=self.target) if T <= 0 or not still_valid: if not still_valid: agent.print("Aerial is no longer valid") agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(recovery(agent.friend_goal.location))
def run(self, agent): # This routine is the same as jump_shot, but it's designed to hit the ball above 250uus (and below 551uus or so) without any boost if not agent.shooting: agent.shooting = True T = self.intercept_time - agent.time # Capping T above 0 to prevent division problems time_remaining = cap(T, 0.000001, 6) slice_n = round(T * 60) agent.dbg_2d(f"Shot slice #: {slice_n}") if T > 0.3 or self.ball_location is None: ball = agent.ball_prediction_struct.slices[ slice_n].physics.location self.ball_location = Vector(ball.x, ball.y, ball.z) self.dodge_point = self.ball_location - (self.shot_vector * agent.best_shot_value) if self.dodge_point.z > 490 or self.dodge_point.z < 380: agent.pop() return car_to_ball = self.ball_location - agent.me.location # whether we should go forwards or backwards angle_to_target = abs( Vector(x=1).angle2D(agent.me.local_location(self.dodge_point))) # whether we are to the left or right of the shot vector side_of_shot = sign( self.shot_vector.cross(Vector(z=1)).dot(car_to_ball)) final_target = self.dodge_point.copy() # Some adjustment to the final target to ensure it's inside the field and we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5120 - (agent.me.hitbox.length / 2): final_target.x = cap(final_target.x, -750, 750) car_to_dodge_point = final_target - agent.me.location car_to_dodge_perp = car_to_dodge_point.cross( Vector(z=side_of_shot)) # perpendicular distance_remaining = car_to_dodge_point.flatten().magnitude() acceleration_required = backsolve( self.dodge_point, agent.me, time_remaining, Vector() if not self.jumping else agent.gravity) local_acceleration_required = agent.me.local_velocity( acceleration_required) # The adjustment causes the car to circle around the dodge point in an effort to line up with the shot vector # The adjustment slowly decreases to 0 as the bot nears the time to jump adjustment = car_to_dodge_point.angle2D( self.shot_vector) * distance_remaining / 2 # size of adjustment # controls how soon car will jump based on acceleration required # we set this based on the time remaining # bigger = later, which allows more time to align with shot vector # smaller = sooner jump_threshold = cap(T * 200, 250, 584) # factoring in how close to jump we are adjustment *= (cap(jump_threshold - (acceleration_required.z), 0, jump_threshold) / jump_threshold) # we don't adjust the final target if we are already jumping final_target += ((car_to_dodge_perp.normalize() * adjustment) if not self.jumping else 0) + Vector(z=50) distance_remaining = (final_target - agent.me.location).flatten().magnitude() local_final_target = agent.me.local_location(final_target) # drawing debug lines to show the dodge point and final target (which differs due to the adjustment) agent.line(agent.me.location, self.dodge_point, agent.renderer.white()) agent.line(self.dodge_point - Vector(z=100), self.dodge_point + Vector(z=100), agent.renderer.green()) vf = agent.me.velocity + agent.gravity * T distance = agent.me.local_location( self.dodge_point).x if agent.me.airborne else distance_remaining speed_required = 2300 if distance_remaining > 2560 else distance / time_remaining agent.dbg_2d(f"Speed required: {speed_required}") if not self.jumping: velocity = agent.me.local_velocity().x local_dodge_point = agent.me.local_location( self.dodge_point.flatten()) local_vf = agent.me.local(vf.flatten()) if T <= 0 or not virxrlcu.double_jump_shot_is_viable( T + 0.3, agent.boost_accel, agent.me.location.dist( self.ball_location), self.shot_vector.tuple(), agent.me.forward.tuple(), agent.me.boost if agent.boost_amount != 'unlimited' else 100000, velocity): # If we're out of time or the ball was hit away or we just can't get enough speed, pop agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 if agent.me.airborne: agent.push(ball_recovery()) elif abs(local_dodge_point.y ) < 92 and local_vf.x >= local_dodge_point.x: # Switch into the jump when the upward acceleration required reaches our threshold, and our lateral acceleration is negligible, and we're close enough to the point in time where the ball will be at the given location self.jumping = True elif agent.boost_amount != 'unlimited' and angle_to_target < 0.03 and velocity > 600 and velocity < speed_required - 500 and distance_remaining / velocity > 3: if agent.gravity.z < -450: agent.push(wave_dash()) else: agent.push(flip(local_final_target)) elif agent.boost_amount != 'unlimited' and angle_to_target >= 2 and distance_remaining > 1000 and velocity < 200: agent.push(flip(local_final_target, True)) elif agent.me.airborne: agent.push(recovery(local_final_target)) else: defaultPD(agent, local_final_target) defaultThrottle(agent, speed_required) agent.controller.handbrake = angle_to_target > 1.54 else: # Mark the time we started jumping so we know when to dodge if self.jump_time == -1: self.jump_time = agent.time jump_elapsed = agent.time - self.jump_time tau = jump_max_duration - jump_elapsed xf = agent.me.location + agent.me.velocity * T + 0.5 * agent.gravity * T * T if jump_elapsed == 0: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * T vf += agent.me.up * jump_acc * tau xf += agent.me.up * jump_acc * tau * (T - 0.5 * tau) vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * (T - tau) delta_x = self.dodge_point - xf direction = delta_x.normalize() if abs(agent.me.forward.dot(direction)) > 0.5: delta_v = delta_x.dot(agent.me.forward) / T if agent.me.boost > 0 and delta_v >= agent.boost_accel * min_boost_time: agent.controller.boost = True else: agent.controller.throttle = cap( delta_v / (throttle_accel * min_boost_time), -1, 1) if T <= -0.4 or (not agent.me.airborne and self.counter > 0): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(ball_recovery()) elif jump_elapsed < jump_max_duration and vf.z <= self.dodge_point.z: agent.controller.jump = True elif self.counter < 4: self.counter += 1 if self.counter == 3: agent.controller.jump = True elif self.counter == 4: defaultPD(agent, agent.me.local_location(self.dodge_point), upside_down=True) if self.counter < 3: defaultPD( agent, agent.me.local( (self.dodge_point - agent.me.location).flatten())) l_vf = vf + agent.me.location agent.line(l_vf - Vector(z=100), l_vf + Vector(z=100), agent.renderer.red())
def run(self, agent): agent.shooting = True raw_time_remaining = self.intercept_time - agent.time # Capping raw_time_remaining above 0 to prevent division problems time_remaining = cap(raw_time_remaining, 0.001, 10.0) car_to_ball = self.ball_location - agent.me.location # whether we are to the left or right of the shot vector side_of_shot = sign( self.shot_vector.cross(Vector(z=1)).dot(car_to_ball)) car_to_dodge_point = self.dodge_point - agent.me.location car_to_dodge_perp = car_to_dodge_point.cross( Vector(z=side_of_shot)) # perpendicular distance_remaining = car_to_dodge_point.magnitude() speed_required = distance_remaining / time_remaining acceleration_required = backsolve( self.dodge_point, agent.me, time_remaining, 0 if not self.jumping else agent.gravity.z) local_acceleration_required = agent.me.local(acceleration_required) # The adjustment causes the car to circle around the dodge point in an effort to line up with the shot vector # The adjustment slowly decreases to 0 as the bot nears the time to jump adjustment = car_to_dodge_point.angle( self.shot_vector) * distance_remaining / 2.0 # size of adjustment # factoring in how close to jump we are adjustment *= (cap(self.jump_threshold - (acceleration_required.z), 0, self.jump_threshold) / self.jump_threshold) # we don't adjust the final target if we are already jumping final_target = self.dodge_point + ( (car_to_dodge_perp.normalize() * adjustment) if not self.jumping else 0) + Vector(z=50) # Ensuring our target isn't too close to the sides of the field, where our car would get messed up by the radius of the curves # Some adjustment to the final target to ensure it's inside the field and we don't try to dirve through any goalposts to reach it if abs(agent.me.location.y) > 5150: final_target.x = cap(final_target.x, -750, 750) local_final_target = agent.me.local(final_target - agent.me.location) # drawing debug lines to show the dodge point and final target (which differs due to the adjustment) agent.line(agent.me.location, self.dodge_point, agent.renderer.white()) agent.line(self.dodge_point - Vector(z=100), self.dodge_point + Vector(z=100), agent.renderer.red()) agent.line(final_target - Vector(z=100), final_target + Vector(z=100), agent.renderer.green()) # Calling our drive utils to get us going towards the final target angles = defaultPD(agent, local_final_target, self.direction) defaultThrottle(agent, speed_required, self.direction) agent.line(agent.me.location, agent.me.location + (self.shot_vector * 200), agent.renderer.white()) agent.controller.boost = False if abs( angles[1]) > 0.3 or agent.me.airborne else agent.controller.boost agent.controller.handbrake = True if abs( angles[1] ) > 2.3 and self.direction == 1 else agent.controller.handbrake if not self.jumping: if raw_time_remaining <= 0 or ( speed_required - 2300) * time_remaining > 45 or not shot_valid(agent, self): # If we're out of time or not fast enough to be within 45 units of target at the intercept time, we pop agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 if agent.me.airborne: agent.push(recovery()) elif local_acceleration_required.z > self.jump_threshold and local_acceleration_required.z > local_acceleration_required.flatten( ).magnitude(): # Switch into the jump when the upward acceleration required reaches our threshold, and our lateral acceleration is negligible self.jumping = True else: if (raw_time_remaining > 0.2 and not shot_valid(agent, self, 150) ) or raw_time_remaining <= -0.9 or (not agent.me.airborne and self.counter > 0): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(recovery()) elif self.counter == 0 and local_acceleration_required.z > 0 and raw_time_remaining > 0.083: # Initial jump to get airborne + we hold the jump button for extra power as required agent.controller.jump = True elif self.counter < 3: # make sure we aren't jumping for at least 3 frames agent.controller.jump = False self.counter += 1 elif raw_time_remaining <= 0.1 and raw_time_remaining > -0.9: # dodge in the direction of the shot_vector agent.controller.jump = True if not self.dodging: vector = agent.me.local(self.shot_vector) self.p = abs(vector.x) * -sign(vector.x) self.y = abs(vector.y) * sign(vector.y) * self.direction self.dodging = True # simulating a deadzone so that the dodge is more natural agent.controller.pitch = self.p if abs(self.p) > 0.2 else 0 agent.controller.yaw = self.y if abs(self.y) > 0.3 else 0
def run(self, agent): if not agent.shooting: agent.shooting = True if self.time == -1: self.time = agent.time elapsed = agent.time - self.time T = self.intercept_time - agent.time xf = agent.me.location + agent.me.velocity * T + 0.5 * agent.gravity * T * T vf = agent.me.velocity + agent.gravity * T slice_n = math.ceil(T * 60) agent.dbg_2d(f"Shot slice #: {slice_n}") if T > 0.1 or self.target is None: ball = agent.ball_prediction_struct.slices[ slice_n].physics.location self.ball = Vector(ball.x, ball.y, ball.z) self.target = self.ball - (self.shot_vector * agent.best_shot_value * 0.8) if agent.me.location.z > 2044 - agent.me.hitbox.height * 1.1: self.ceiling = True self.target -= Vector(z=92) if not self.ceiling and (self.jumping or not agent.me.airborne): agent.dbg_2d("Jumping") if not self.jumping or not agent.me.airborne: self.jumping = True self.jump_time = agent.time self.counter = 0 jump_elapsed = agent.time - self.jump_time tau = jump_max_duration - jump_elapsed if jump_elapsed == 0: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * T vf += agent.me.up * jump_acc * tau xf += agent.me.up * jump_acc * tau * (T - 0.5 * tau) if self.fast_aerial: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * (T - tau) if jump_elapsed < jump_max_duration: agent.controller.jump = True elif self.counter < 6: self.counter += 1 if self.counter == 3: agent.controller.jump = True self.dodging = True elif self.counter == 6: self.dodging = self.jumping = False elif jump_elapsed < jump_max_duration: agent.controller.jump = True else: self.jumping = False if self.ceiling: agent.dbg_2d(f"Ceiling shot") delta_x = self.target - xf direction = delta_x.normalize() agent.line(agent.me.location, self.target, agent.renderer.white()) c_vf = vf + agent.me.location agent.line(c_vf - Vector(z=100), c_vf + Vector(z=100), agent.renderer.blue()) agent.line(xf - Vector(z=100), xf + Vector(z=100), agent.renderer.red()) agent.line(self.target - Vector(z=100), self.target + Vector(z=100), agent.renderer.green()) if not self.dodging: target = delta_x if delta_x.magnitude() > 50 else ( self.target - agent.me.location) if self.jumping: target = target.flatten() target = agent.me.local(target) if abs(Vector(x=1).angle(target)) > 0.005: defaultPD(agent, target, upside_down=self.shot_vector.z < 0 and not self.jumping) if abs(agent.me.forward.dot(direction)) > 0.5: delta_v = delta_x.dot(agent.me.forward) / T if agent.me.boost > 0 and delta_v >= agent.boost_accel * min_boost_time: agent.controller.boost = True else: agent.controller.throttle = cap( delta_v / (throttle_accel * min_boost_time), -1, 1) if T <= 0 or (not self.jumping and not agent.me.airborne) or ( not self.jumping and T > 2 and self.fast_aerial and not virxrlcu.aerial_shot_is_viable( T + 0.3, 144, agent.boost_accel, agent.gravity.tuple(), agent.me.location.tuple(), agent.me.velocity.tuple(), agent.me.up.tuple(), agent.me.forward.tuple(), 1 if agent.me.airborne else -1, agent.me.boost if agent.boost_amount != 'unlimited' else 100000, self.ball.tuple())): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(ball_recovery()) elif (self.ceiling and self.target.dist(agent.me.location) < 92 + agent.me.hitbox.length and not agent.me.doublejumped and agent.me.location.z < agent.ball.location.z + 92 and self.target.y * side(agent.team) > -4240) or ( not self.ceiling and not self.fast_aerial and self.target.dist(agent.me.location) < 92 + agent.me.hitbox.length and not agent.me.doublejumped): agent.dbg_2d("Flipping") agent.controller.jump = True local_target = agent.me.local_location(self.target) agent.controller.pitch = abs( local_target.x) * -sign(local_target.x) agent.controller.yaw = abs(local_target.y) * sign(local_target.y)
def run(self, agent): agent.shooting = True raw_time_remaining = self.intercept_time - agent.time # Capping raw_time_remaining above 0 to prevent division problems time_remaining = cap(raw_time_remaining, 0.001, 10.0) car_to_ball = self.ball_location - agent.me.location # whether we are to the left or right of the shot vector side_of_shot = sign( self.shot_vector.cross(Vector(z=1)).dot(car_to_ball)) car_to_intercept = self.intercept - agent.me.location car_to_intercept_perp = car_to_intercept.cross( Vector(z=side_of_shot)) # perpendicular distance_remaining = car_to_intercept.flatten().magnitude() speed_required = distance_remaining / time_remaining # When still on the ground we pretend agent.gravity doesn't exist, for better or worse acceleration_required = backsolve( self.intercept, agent.me, time_remaining, 0 if self.jump_time == 0 else agent.gravity.z) local_acceleration_required = agent.me.local(acceleration_required) # The adjustment causes the car to circle around the dodge point in an effort to line up with the shot vector # The adjustment slowly decreases to 0 as the bot nears the time to jump adjustment = car_to_intercept.angle( self.shot_vector) * distance_remaining / 1.57 # size of adjustment # factoring in how close to jump we are adjustment *= cap(self.jump_threshold - (acceleration_required.z), 0, self.jump_threshold) / self.jump_threshold # we don't adjust the final target if we are already jumping final_target = self.intercept + ( (car_to_intercept_perp.normalize() * adjustment) if self.jump_time == 0 else 0) # Some extra adjustment to the final target to ensure it's inside the field and we don't try to dirve through any goalposts to reach it if abs(agent.me.location.y) > 5150: final_target.x = cap(final_target.x, -750, 750) local_final_target = agent.me.local(final_target - agent.me.location) # drawing debug lines to show the dodge point and final target (which differs due to the adjustment) agent.line(agent.me.location, self.intercept, agent.renderer.white()) agent.line(self.intercept - Vector(z=100), self.intercept + Vector(z=100), agent.renderer.red()) agent.line(final_target - Vector(z=100), final_target + Vector(z=100), agent.renderer.green()) angles = defaultPD(agent, local_final_target) if self.jump_time == 0: defaultThrottle(agent, speed_required) agent.controller.boost = False if abs( angles[1] ) > 0.3 or agent.me.airborne else agent.controller.boost agent.controller.handbrake = True if abs( angles[1]) > 2.3 else agent.controller.handbrake if acceleration_required.z > self.jump_threshold: # Switch into the jump when the upward acceleration required reaches our threshold, hopefully we have aligned already... self.jump_time = agent.time else: time_since_jump = agent.time - self.jump_time # While airborne we boost if we're within 30 degrees of our local acceleration requirement if agent.me.airborne and local_acceleration_required.magnitude( ) * time_remaining > 100: angles = defaultPD(agent, local_acceleration_required) if abs(angles[0]) + abs(angles[1]) < 0.5: agent.controller.boost = True if self.counter == 0 and (time_since_jump <= 0.2 and local_acceleration_required.z > 0): # hold the jump button up to 0.2 seconds to get the most acceleration from the first jump agent.controller.jump = True elif time_since_jump > 0.2 and self.counter < 3: # Release the jump button for 3 ticks agent.controller.jump = False self.counter += 1 elif local_acceleration_required.z > 300 and self.counter == 3: # the acceleration from the second jump is instant, so we only do it for 1 frame agent.controller.jump = True agent.controller.pitch = 0 agent.controller.yaw = 0 agent.controller.roll = 0 self.counter += 1 if raw_time_remaining < -0.25 or not shot_valid(agent, self): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(recovery())
def run(self, agent): if not agent.shooting: agent.shooting = True T = self.intercept_time - agent.time # Capping T above 0 to prevent division problems time_remaining = cap(T, 0.000001, 6) slice_n = round(T * 60) agent.dbg_2d(f"Shot slice #: {slice_n}") if T > 0.3 or self.ball_location is None: ball = agent.ball_prediction_struct.slices[ slice_n].physics.location self.ball_location = Vector(ball.x, ball.y, ball.z) self.dodge_point = self.ball_location - (self.shot_vector * agent.best_shot_value) if self.dodge_point.z > 300: agent.pop() return car_to_ball = self.ball_location - agent.me.location # whether we should go forwards or backwards angle_to_target = abs(Vector(x=1).angle2D(agent.me.local(car_to_ball))) # whether we are to the left or right of the shot vector side_of_shot = sign( self.shot_vector.cross(Vector(z=1)).dot(car_to_ball)) final_target = self.dodge_point.copy() # Some adjustment to the final target to ensure it's inside the field and we don't try to drive through any goalposts to reach it if abs(agent.me.location.y) > 5120 - (agent.me.hitbox.length / 2): final_target.x = cap(final_target.x, -750, 750) car_to_dodge_point = final_target - agent.me.location car_to_dodge_perp = car_to_dodge_point.cross( Vector(z=side_of_shot)) # perpendicular acceleration_required = backsolve( self.dodge_point, agent.me, time_remaining, Vector() if not self.jumping else agent.gravity) local_acceleration_required = agent.me.local(acceleration_required) distance_remaining = car_to_dodge_point.flatten().magnitude() # The adjustment causes the car to circle around the dodge point in an effort to line up with the shot vector # The adjustment slowly decreases to 0 as the bot nears the time to jump adjustment = car_to_dodge_point.angle2D( self.shot_vector) * distance_remaining / 2 # size of adjustment # controls how soon car will jump based on acceleration required # we set this based on the time remaining # bigger = later, which allows more time to align with shot vector # smaller = sooner jump_threshold = cap(T * 200, 250, 584) # factoring in how close to jump we are adjustment *= (cap(jump_threshold - (acceleration_required.z), 0, jump_threshold) / jump_threshold) # we don't adjust the final target if we are already jumping final_target += ((car_to_dodge_perp.normalize() * adjustment) if not self.jumping else 0) + Vector(z=50) distance_remaining = (final_target - agent.me.location).flatten().magnitude() direction = 1 if angle_to_target < 2.1 or ( agent.gravity.z > -450 and distance_remaining >= 1000) else -1 local_final_target = agent.me.local_location(final_target) # drawing debug lines to show the dodge point and final target (which differs due to the adjustment) agent.line(agent.me.location, self.dodge_point, agent.renderer.white()) agent.line(self.dodge_point - Vector(z=100), self.dodge_point + Vector(z=100), agent.renderer.green()) agent.line(final_target - Vector(z=100), final_target + Vector(z=100), agent.renderer.blue()) vf = agent.me.velocity + agent.gravity * T xf = agent.me.location + agent.me.velocity * T + 0.5 * agent.gravity * T * T ball_l = agent.me.local_location(agent.ball.location) speed_required = 2300 if ( self.ball_location.z < 92 + agent.me.hitbox.height / 2 and abs(ball_l.y) < 46 and ball_l.x > agent.me.hitbox.length ) or distance_remaining > 2560 else distance_remaining * 0.975 / time_remaining agent.dbg_2d(f"Speed required: {speed_required}") if not self.jumping: defaultPD(agent, local_final_target) defaultThrottle(agent, speed_required * direction) agent.controller.handbrake = angle_to_target > 1.54 if direction == 1 else angle_to_target < 2.2 local_dodge_point = agent.me.local_location( self.dodge_point.flatten()) # use algebra to get the required jump time min_jump_time = self.dodge_point - agent.me.location min_jump_time -= agent.me.velocity * T min_jump_time -= 0.5 * agent.gravity * T * T min_jump_time -= agent.me.up * jump_speed * T min_jump_time /= jump_acc # This leaves us with xf = dT - 0.5d^2, so we use the quadratic formula to solve it min_jump_time = max(quadratic(-0.5, T, sum(min_jump_time) / 3)) min_jump_time += 0.05 f_vf = vf + (agent.me.up * (jump_speed + jump_acc * min_jump_time)) local_vf = agent.me.local(f_vf.flatten()) velocity = agent.me.local_velocity().x if T <= 0 or not virxrlcu.jump_shot_is_viable( T + 0.3, agent.boost_accel, agent.me.location.dist( self.ball_location), self.shot_vector.tuple(), agent.me.forward.tuple(), agent.me.boost if agent.boost_amount != 'unlimited' else 100000, velocity): # If we're out of time or not fast enough to be within 45 units of target at the intercept time, we pop agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 if agent.me.airborne: agent.push(recovery()) elif self.dodge_point.z > 92 + agent.me.hitbox.height / 2 and ( (T <= min_jump_time and self.dodge_point.z >= 175) or (T <= 0.3 and self.dodge_point.z < 175)) and abs(local_dodge_point.y) < ( 92 if find_slope(self.shot_vector, car_to_ball) > 2 or self.dodge_point.z <= 92 + agent.me.hitbox.height / 2 else math.ceil(92 + agent.me.hitbox.width / 2)) and local_vf.x >= local_dodge_point.x: # Switch into the jump when the upward acceleration required reaches our threshold, and our lateral acceleration is negligible self.jumping = True elif agent.boost_amount != 'unlimited' and angle_to_target < 0.03 and velocity > 600 and velocity < speed_required - 150 and distance_remaining / velocity > 3: if agent.gravity.z < -450: agent.push(wave_dash()) else: agent.push(flip(local_final_target)) elif direction == -1 and velocity < 200 and distance_remaining / abs( velocity) > 2: agent.push(flip(local_final_target, True)) elif agent.me.airborne: agent.push(recovery(local_final_target)) else: if self.jump_time == -1: self.jump_time = agent.time jump_elapsed = agent.time - self.jump_time tau = jump_max_duration - jump_elapsed if jump_elapsed == 0: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * T vf += agent.me.up * jump_acc * tau xf += agent.me.up * jump_acc * tau * (T - 0.5 * tau) delta_x = self.dodge_point - xf d_direction = delta_x.normalize() if abs(agent.me.forward.dot( d_direction)) > 0.5 and self.counter < 3: delta_v = delta_x.dot(agent.me.forward) / T if agent.me.boost > 0 and delta_v >= agent.boost_accel * min_boost_time: agent.controller.boost = True else: agent.controller.throttle = cap( delta_v / (throttle_accel * min_boost_time), -1, 1) if T <= -0.4 or (not agent.me.airborne and self.counter >= 3): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(recovery()) return else: if self.counter == 3 and agent.me.location.dist( self.dodge_point) < (92.75 + agent.me.hitbox.length) * 1.05: # Get the required pitch and yaw to flip correctly vector = agent.me.local(self.shot_vector) self.p = abs(vector.x) * -sign(vector.x) self.y = abs(vector.y) * sign(vector.y) * direction # simulating a deadzone so that the dodge is more natural self.p = cap(self.p, -1, 1) if abs(self.p) > 0.1 else 0 self.y = cap(self.y, -1, 1) if abs(self.y) > 0.1 else 0 agent.controller.pitch = self.p agent.controller.yaw = self.y # Wait 1 more frame before dodging self.counter += 1 elif self.counter == 4: # Dodge agent.controller.jump = True agent.controller.pitch = self.p agent.controller.yaw = self.y else: # Face the direction we're heading in, with the z of our target target = agent.me.local(agent.me.velocity.flatten()) target.z = agent.me.local_location(self.dodge_point).z defaultPD(agent, target) if jump_elapsed < jump_max_duration and vf.z < self.dodge_point.z: # Initial jump to get airborne + we hold the jump button for extra power as required agent.controller.jump = True elif self.counter < 3: # Make sure we aren't jumping for at least 3 frames self.counter += 1 l_vf = vf + agent.me.location agent.line(l_vf - Vector(z=100), l_vf + Vector(z=100), agent.renderer.red())