def update_status(self, info: GameInfo): if norm(info.ball.pos) > 140 and norm( info.ball.vel) > 9: # this only works for soccar if norm(info.ball.pos - info.my_car.pos) < 240: self.finished = True else: self.failed = True
def step(self, dt): max_throttle_speed = 1410 max_boost_speed = 2300 # get the local coordinates of where the ball is, relative to the car # delta_local[0]: how far in front # delta_local[1]: how far to the left # delta_local[2]: how far above delta_local = dot(self.target_pos - self.car.pos, self.car.theta) # angle between car's forward direction and target position phi = math.atan2(delta_local[1], delta_local[0]) if phi < -math.radians(10): # If the target is more than 10 degrees right from the centre, steer left self.controls.steer = -1 elif phi > math.radians(10): # If the target is more than 10 degrees left from the centre, steer right self.controls.steer = 1 else: # If the target is less than 10 degrees from the centre, steer straight self.controls.steer = phi / math.radians(10) if abs(phi) < math.radians(3) and not self.car.supersonic: self.controls.boost = True else: self.controls.boost = False if abs(phi) > 1.75: self.controls.handbrake = 1 else: self.controls.handbrake = 0 # forward velocity vf = dot(self.car.vel, self.car.forward()) if vf < self.target_speed: self.controls.throttle = 1.0 if self.target_speed > max_throttle_speed: self.controls.boost = 1 else: self.controls.boost = 0 else: self.controls.throttle = -1 self.controls.boost = 0 if norm(delta_local) < 20: self.controls.throttle = -norm(delta_local) / 20 if norm(delta_local) < 10: self.controls.throttle = -norm(delta_local) / 10 if self.car.supersonic: self.controls.boost = False if norm(self.car.pos - self.target_pos) < 100: self.finished = True
def closest_available_boost(my_pos: vec3, boost_pads: list) -> BoostPad: """ Returns the closest available boost pad to my_pos""" closest_boost = None for boost in boost_pads: distance = norm(boost.pos - my_pos) if boost.is_active or distance / 2300 > 10 - boost.timer: if closest_boost is None: closest_boost = boost closest_distance = norm(closest_boost.pos - my_pos) else: if distance < closest_distance: closest_boost = boost closest_distance = norm(closest_boost.pos - my_pos) return closest_boost
def turn_circles(self): """renders turning circles in cyan""" speed = norm(self.info.my_car.vel) r = -6.901E-11 * speed**4 + 2.1815E-07 * speed**3 - 5.4437E-06 * speed**2 + 0.12496671 * speed + 157 k = self.turn_c_quality circleR = [] centreR = vec3(0, r, 0) for i in range(k): theta = (2 / k) * math.pi * i point = centreR + vec3(r * math.sin(theta), -r * math.cos(theta), 0) point = self.info.my_car.pos + dot(self.info.my_car.theta, point) circleR.append(point) circleL = [] centreL = vec3(0, -r, 0) for i in range(k): theta = (2 / k) * math.pi * i point = centreL + vec3(r * math.sin(theta), r * math.cos(theta), 0) point = self.info.my_car.pos + dot(self.info.my_car.theta, point) circleL.append(point) self.renderer.begin_rendering("turn circles") self.renderer.draw_polyline_3d(circleR, self.renderer.cyan()) self.renderer.draw_polyline_3d(circleL, self.renderer.cyan()) self.renderer.end_rendering()
def can_dodge(agent, target): bot_to_target = target - agent.info.my_car.pos local_bot_to_target = dot(bot_to_target, agent.info.my_car.theta) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) distance_bot_to_target = norm(vec2(bot_to_target)) good_angle = math.radians(-10) < angle_front_to_target < math.radians(10) on_ground = agent.info.my_car.on_ground and agent.info.my_car.pos[2] < 100 going_fast = velocity_2d(agent.info.my_car.vel) > 1250 target_not_in_goal = not agent.info.my_goal.inside(target) return good_angle and distance_bot_to_target > 2000 and on_ground and going_fast and target_not_in_goal
def convboost(self): for guide in self.guides: for pad in self.active_pads: if pad not in self.plan_pads and norm( guide - pad.pos ) <= 300: #number not final, distance from guide to potential convenient boost has to be less or equal to this number self.plan_pads.append(pad) self.targets.insert(0, pad.pos) self.pathplan() self.convboost() break else: continue break
def bounce_off(self, normal): # See https://samuelpmish.github.io/notes/RocketLeague/ball_bouncing/ # For dropshot the slip velocity becomes zero after the first bounce, so chips model is slightly tweaked MU = 0.285 CR = 0.605 v_perp = normal * dot(self.vel, normal) v_para = self.vel - v_perp v_spin = cross(normal, self.omega) * DropshotBall.RADIUS s = v_para - v_spin delta_v_para = vec3(0, 0, 0) if norm(s) != 0: delta_v_para = -MU * s delta_v_perp = v_perp * -(1.0 + CR) self.vel += delta_v_perp + delta_v_para self.omega = cross(self.vel, normal) * (1. / DropshotBall.RADIUS) return self
def get_controls(self): if self.step == "Steer" or self.step == "Dodge2": self.step = "Catching" if self.step == "Catching": target = get_bounce(self) if target is None: self.step = "Defending" else: self.catching.target_pos = target[0] self.catching.target_speed = (distance_2d( self.info.my_car.pos, target[0]) + 50) / target[1] self.catching.step(self.FPS) self.controls = self.catching.controls ball = self.info.ball car = self.info.my_car if distance_2d(ball.pos, car.pos) < 150 and 65 < abs(ball.pos[2] - car.pos[2]) < 127: self.step = "Dribbling" self.dribble = Dribbling(self.info.my_car, self.info.ball, self.info.their_goal) if self.defending: self.step = "Defending" if not self.info.my_car.on_ground: self.step = "Recovery" ball = self.info.ball if abs(ball.vel[2]) < 100 and sign( self.team) * ball.vel[1] < 0 and sign( self.team) * ball.pos[1] < 0: self.step = "Shooting" elif self.step == "Dribbling": self.dribble.step(self.FPS) self.controls = self.dribble.controls ball = self.info.ball car = self.info.my_car bot_to_opponent = self.info.opponents[0].pos - self.info.my_car.pos local_bot_to_target = dot(bot_to_opponent, self.info.my_car.theta) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) opponent_is_near = norm(vec2(bot_to_opponent)) < 2000 opponent_is_in_the_way = math.radians( -10) < angle_front_to_target < math.radians(10) if not (distance_2d(ball.pos, car.pos) < 150 and 65 < abs(ball.pos[2] - car.pos[2]) < 127): self.step = "Catching" if self.defending: self.step = "Defending" if opponent_is_near and opponent_is_in_the_way: self.step = "Dodge" self.dodge = AirDodge(self.info.my_car, 0.25, self.info.their_goal.center) if not self.info.my_car.on_ground: self.step = "Recovery" elif self.step == "Defending": defending(self) elif self.step == "Dodge": self.dodge.step(self.FPS) self.controls = self.dodge.controls self.controls.boost = 0 if self.dodge.finished and self.info.my_car.on_ground: self.step = "Catching" elif self.step == "Recovery": self.recovery.step(self.FPS) self.controls = self.recovery.controls if self.info.my_car.on_ground: self.step = "Catching" elif self.step == "Shooting": shooting(self)
def get_output(self, packet: GameTickPacket): self.time = packet.game_info.seconds_elapsed dt = self.time - self.prev_time if packet.game_info.is_kickoff_pause and not isinstance(self.maneuver, Kickoff): self.maneuver = None self.prev_time = self.time if self.ticks < 6: self.ticks += 1 self.info.read_packet(packet) self.strategy.packet = packet #reset maneuver when another car hits the ball touch = packet.game_ball.latest_touch if (( touch.time_seconds > self.last_touch_time and touch.player_name != packet.game_cars[self.index].name ) or ( touch.player_name == '' and # if latest touch info is missing any([distance(self.info.ball, car) < 300 for car in self.info.opponents + self.info.teammates]) )): self.last_touch_time = touch.time_seconds if ( self.info.my_car.on_ground and (not isinstance(self.maneuver, ShadowDefense) or self.maneuver.travel._driving) ): self.maneuver = None #self.reset_time = self.time # choose maneuver if self.maneuver is None and self.time > self.reset_time + 0.01 and self.ticks > 5: if self.RENDERING: self.draw.clear() self.info.predict_ball(self.PREDICTION_RATE * self.PREDITION_DURATION, 1 / self.PREDICTION_RATE) self.maneuver = self.strategy.choose_maneuver() name = str(type(self.maneuver).__name__) self.last_ball_vel = norm(self.info.ball.vel) # execute maneuver if self.maneuver is not None: self.maneuver.step(dt) # I have to convert from RLU Input to SimpleControllerState, because Input doesnt have 'use_item' self.controls.steer = self.maneuver.controls.steer self.controls.throttle = self.maneuver.controls.throttle self.controls.jump = self.maneuver.controls.jump self.controls.pitch = self.maneuver.controls.pitch self.controls.yaw = self.maneuver.controls.yaw self.controls.roll = self.maneuver.controls.roll self.controls.handbrake = self.maneuver.controls.handbrake self.controls.boost = self.maneuver.controls.boost if self.RENDERING: self.maneuver.render(self.draw) if self.maneuver.finished: self.maneuver = None if self.RENDERING: self.draw.execute() self.maybe_chat(packet) self.chat.step(packet) return self.controls
def ground_distance(obj1, obj2) -> float: return norm(ground(obj1) - ground(obj2))
def distance(obj1, obj2) -> float: return norm(loc(obj1) - loc(obj2))
def get_output(self, packet): self.info.read_packet(packet) #additional processing not done by RLU self.kickoff_pause = packet.game_info.is_kickoff_pause self.round_active = packet.game_info.is_round_active self.dt = self.info.time - self.last_time self.last_time = self.info.time self.last_touch = packet.game_ball.latest_touch.player_name #trashtalk if packet.game_cars[self.index].score_info.goals == self.goals + 1: self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Reactions_Calculated) self.goals = packet.game_cars[self.index].score_info.goals #resets controls each tick self.controls = SimpleControllerState() #choose state if not self.round_active: self.state = None elif not self.state == "kickoff": if self.kickoff_pause: self.kickoff_pos = None self.action = None self.timer = 0.0 self.state = "kickoff" elif not self.info.my_car.on_ground and not isinstance(self.action, AirDodge): self.state = "recovery" self.action = self.action = AerialTurn(self.info.my_car) elif norm(self.info.my_goal.center - self.info.my_car.pos) > norm(self.info.my_goal.center - self.info.ball.pos) + self.def_extra_dist: self.action = None self.target_speed = 2300 self.state = "defence" if self.team == 0: sign = -1 else: sign = 1 #temporary 2v2 for Cow if len(self.info.teammates) > 0: if self.info.ball.pos[1] > 0: self.target = vec3(3000,sign*4000,0) else: self.target = vec3(-3000,sign*4000,0) else: self.target = vec3(0,sign*4000,0) elif self.info.my_car.pos[1] > 5120 or self.info.my_car.pos[1] < -5120: self.target = vec3(0,5000,0) if self.info.my_car.pos[1] > 5120 else vec3(0,-5000,0) self.action = self.action = Drive(self.info.my_car,self.target,1000) self.state = "goal escape" elif self.state == None: self.action = None self.target = None self.target_speed = 2300 self.state = "offence" #kickoff state if self.state == "kickoff": Kickoff.kickoff(self) #exit kickoff state if self.timer >= 2.6 or self.last_touch != '': self.state = None self.action = None #recovery state elif self.state == "recovery": self.action.step(self.dt) self.controls = self.action.controls self.controls.throttle = 1.0 #exit recovery state if self.info.my_car.on_ground == True: self.state = None self.action = None #defence state and offence state elif self.state == "defence" or self.state == "offence": #select target if self.target == None: #large boost if self.info.my_car.boost <= self.low_boost and norm(self.info.my_car.pos - self.info.ball.pos) > self.max_ball_dist: active_pads = [] for pad in self.info.boost_pads: if pad.is_active: active_pads.append(pad) if len(active_pads) != 0: closest_pad = active_pads[0] for pad in active_pads: if norm(pad.pos - self.info.ball.pos) < norm(closest_pad.pos - self.info.ball.pos): closest_pad = pad self.target = closest_pad.pos else: self.target = self.info.ball.pos #ball else: self.target = self.info.ball.pos forward_target = dot(self.target - self.info.my_car.pos, self.info.my_car.theta)[0] right_target = dot(self.target - self.info.my_car.pos, self.info.my_car.theta)[1] angle_to_target = math.atan2(right_target, forward_target) forward_goal = dot(self.info.their_goal.center - self.info.my_car.pos, self.info.my_car.theta)[0] right_goal = dot(self.info.their_goal.center - self.info.my_car.pos, self.info.my_car.theta)[1] angle_to_goal = math.atan2(right_goal, forward_goal) #select maneuver if not isinstance(self.action, AirDodge): #shooting if norm(self.info.ball.pos - self.info.my_car.pos) < self.dodge_dist and (angle_to_target - (math.pi/10.0) <= angle_to_goal <= angle_to_target + (math.pi/10.0)): self.action = AirDodge(self.info.my_car,0.2,self.info.their_goal.center) self.timer = 0.0 #dodging elif (-math.pi/24.0) <= angle_to_target <= (math.pi/24.0) and norm(self.info.my_car.vel) > 700 and norm(self.info.ball.pos - self.info.my_car.pos) > 1000 and not self.state == "defence": self.action = AirDodge(self.info.my_car,0.2,self.target) self.timer = 0.0 #Drive else: self.action = Drive(self.info.my_car,self.target,self.target_speed) #exit AirDodge else: self.timer += self.dt if self.timer >= 0.5: self.action = None #Drive if isinstance(self.action, Drive): speed = norm(self.info.my_car.vel) r = -6.901E-11 * speed**4 + 2.1815E-07 * speed**3 - 5.4437E-06 * speed**2 + 0.12496671 * speed + 157 #handbrake self.drift = False if (math.pi/2.0) <= angle_to_target or angle_to_target <= (-math.pi/2.0): self.drift = True #target speed elif (norm(self.target - (self.info.my_car.pos + dot(self.info.my_car.theta,vec3(0,r,0)))) < r or norm(self.target - (self.info.my_car.pos + dot(self.info.my_car.theta,vec3(0,-r,0)))) < r) and not self.target_speed < self.min_target_s: self.target_speed += -50 self.action = Drive(self.info.my_car,self.target,self.target_speed) elif self.target_speed < 1800: self.target_speed += 50 self.action = Drive(self.info.my_car,self.target,self.target_speed) #maneuver tick if self.action != None: self.action.step(self.dt) self.controls = self.action.controls self.controls.handbrake = self.drift #exit either state if (self.state == "defence" and norm(self.info.my_goal.center - self.info.my_car.pos) < norm(self.info.my_goal.center - self.info.ball.pos)) or (norm(self.target - self.info.my_car.pos) < self.target_range): self.state = None #goal escape state if self.state == "goal escape": self.action.step(self.dt) self.controls = self.action.controls #exit goal escape state if not (self.info.my_car.pos[1] > 5120 or self.info.my_car.pos[1] < -5120): self.state = None self.action = None if 'win32gui' in sys.modules: #finding the size of the Rocket League window def callback(hwnd, win_rect): if "Rocket League" in win32gui.GetWindowText(hwnd): rect = win32gui.GetWindowRect(hwnd) win_rect[0] = rect[0] win_rect[1] = rect[1] win_rect[2] = rect[2] - rect[0] win_rect[3] = rect[3] - rect[1] self.RLwindow = [0] * 4 win32gui.EnumWindows(callback, self.RLwindow) #Rendering Render.debug(self) Render.turn_circles(self) if not self.target == None: Render.target(self) return self.controls
def turn_radius(self): # https://docs.google.com/spreadsheets/d/1Hhg1TJqVUCcKIRmwvO2KHnRZG1z8K4Qn-UnAf5-Pt64/edit?usp=sharing car_speed = norm(self.info.my_car.vel) return (+156 + 0.1 * car_speed + 0.000069 * car_speed**2 + 0.000000164 * car_speed**3 - 5.62 * 10**(-11) * car_speed**4)
def solid_angle(self, p): Omega = 0.0 a = self.corners[0] - p b = self.corners[1] - p c = self.corners[2] - p numerator = abs(dot(a, cross(b, c))) denominator = norm(a) * norm(b) * norm(c) + \ dot(a, b) * norm(c) + \ dot(b, c) * norm(a) + \ dot(c, a) * norm(b) angle = 2 * math.atan(numerator / denominator) if angle < 0: angle += 2 * math.pi Omega += angle a = self.corners[2] - p b = self.corners[3] - p c = self.corners[0] - p numerator = abs(dot(a, cross(b, c))) denominator = norm(a) * norm(b) * norm(c) + \ dot(a, b) * norm(c) + \ dot(b, c) * norm(a) + \ dot(c, a) * norm(b) angle = 2 * math.atan(numerator / denominator) if angle < 0: angle += 2 * math.pi Omega += angle return Omega
def distance_2d(a, b): return norm(vec2(a - b))
def velocity_2d(vel): return norm(vec2(vel))
def spherical(vec: vec3) -> vec3: """Converts from cartesian to spherical coordinates.""" radius = norm(vec) + 1e-9 inclination = math.acos(vec[2] / radius) azimuth = math.atan2(vec[1], vec[0]) return vec3(radius, Range180(PI / 2 - inclination), azimuth)
def estimate_max_car_speed(car: Car): return clamp(max(norm(car.vel), 1300) + car.boost * 30, 1400, 2300)