def step(self, dt): ball = Ball(self.ball) car = self.car # simulate ball until it gets near the floor while (ball.position[2] > 120 or ball.velocity[2] > 0) and ball.time < car.time + 10: ball.step(1/60) ball_local = local(car, ground(ball.position)) target = local(car, self.target) shift = ground(direction(ball_local, target)) shift[1] *= 1.8 shift = normalize(shift) max_turn = clamp(norm(car.velocity) / 800, 0, 1) max_shift = normalize(vec3(1 - max_turn, max_turn * sign(shift[1]), 0)) if abs(shift[1]) > abs(max_shift[1]) or shift[0] < 0: shift = max_shift shift *= clamp(car.boost, 40, 60) shift[1] *= clamp(norm(car.velocity)/1000, 1, 2) self._shift_direction = normalize(world(car, shift) - car.position) target = world(car, ball_local - shift) speed = distance(car.position, target) / max(0.001, ball.time - car.time) self.drive.target_speed = speed self.drive.target_pos = target self.drive.step(dt) self.controls = self.drive.controls self.finished = self.ball.position[2] < 100 or ground_distance(self.ball, self.car) > 2000
def get_closest_point_on_trajectory(b: Ball, target: vec3): closest = vec3(target) while True: b.step(1.0 / 120.0) if abs(veclen(target - b.location)) > abs(veclen(target - closest)): return closest closest = vec3(b.location)
def predict_ball(self, duration=5.0, dt=1 / 120): self.about_to_score = False self.about_to_be_scored_on = False self.time_of_goal = -1 self.ball_predictions = [] prediction = Ball(self.ball) # nearest_opponent = Car(min(self.get_opponents(), key=lambda opponent: distance(opponent, prediction))) while prediction.time < self.time + duration: # if prediction.time < self.time + 1.0: # nearest_opponent.step(Input(), dt) # nearest_opponent.velocity[2] = 0 # prediction.step(dt, nearest_opponent) # else: prediction.step(dt) self.ball_predictions.append(Ball(prediction)) if self.time_of_goal == -1: if self.my_goal.inside(prediction.position): self.about_to_be_scored_on = True self.time_of_goal = prediction.time if self.their_goal.inside(prediction.position): self.about_to_score = True self.time_of_goal = prediction.time
def simulate(self): ball_prediction = self.get_ball_prediction_struct() duration_estimate = math.floor( get_time_at_height(self.game.ball.location[2], 0.2) * 10) / 10 for i in range(6): car = Car(self.game.my_car) ball = Ball(self.game.ball) batmobile = obb() batmobile.half_width = vec3(64.4098892211914, 42.335182189941406, 14.697200775146484) batmobile.center = car.location + dot(car.rotation, vec3(9.01, 0, 12.09)) batmobile.orientation = car.rotation dodge = Dodge(car) dodge.duration = duration_estimate + i / 60 dodge.target = ball.location for j in range(round(60 * dodge.duration)): dodge.target = ball.location dodge.step(1 / 60) car.step(dodge.controls, 1 / 60) prediction_slice = ball_prediction.slices[j] physics = prediction_slice.physics ball_location = vec3(physics.location.x, physics.location.y, physics.location.z) dodge.target = ball_location batmobile.center = car.location + dot(car.rotation, vec3(9.01, 0, 12.09)) batmobile.orientation = car.rotation if intersect(sphere(ball_location, 93.15), batmobile) and abs( ball_location[2] - car.location[2] ) < 25 and car.location[2] < ball_location[2]: return True, j / 60, ball_location return False, None, None
def __init__(self, car: Car, ball_predictions, predicate: callable = None, backwards=False): self.ball: Optional[Ball] = None self.car: Car = car self.is_viable = True # find the first reachable ball slice that also meets the predicate speed = 1000 if backwards else estimate_max_car_speed(car) for i in range(0, len(ball_predictions)): ball = ball_predictions[i] time = estimate_time(car, ball.position, speed, -1 if backwards else 1) if time < ball.time - car.time and (predicate is None or predicate(car, ball)): self.ball = ball break # if no slice is found, use the last one if self.ball is None: if not ball_predictions: self.ball = Ball() self.ball.time = math.inf else: self.ball = ball_predictions[-1] self.is_viable = False self.time = self.ball.time self.ground_pos = ground(self.ball.position) self.position = self.ball.position
def __init__(self, car: Car, ball_predictions: List[Ball]): self.car: Car = car self.ball: Ball = None self.is_viable = True test_aerial = Aerial(car) for i in range(0, len(ball_predictions)): ball_slice = ball_predictions[i] test_aerial.target = ball_slice.position test_aerial.arrival_time = ball_slice.time if test_aerial.is_viable(): self.ball = ball_slice break # if no slice is found, use the last one if self.ball is None: if not ball_predictions: self.ball = Ball() self.ball.time = math.inf else: self.ball = ball_predictions[-1] self.is_viable = False self.time = self.ball.time self.position = self.ball.position
def __init__(self, car: Car, ball_predictions, predicate: callable = None, backwards=False): self.ball: Optional[Ball] = None self.car: Car = car self.is_viable = True self.predicate_later_than_time = False # whether the time constraint was satisfied sooner than the predicate for i in range(0, len(ball_predictions), 3): ball = ball_predictions[i] time = estimate_time(car, ball.position, -1 if backwards else 1) if time < ball.time - car.time: if predicate is None or predicate(car, ball): self.ball = ball break self.predicate_later_than_time = True else: self.predicate_later_than_time = False # if no slice is found, use the last one if self.ball is None: if not ball_predictions: self.ball = Ball() self.ball.time = math.inf else: self.ball = ball_predictions[-1] self.is_viable = False self.time = self.ball.time self.ground_pos = ground(self.ball.position) self.position = self.ball.position
def predict_ball(self, time_limit=6.0, dt=1 / 120): self.about_to_score = False self.about_to_be_scored_on = False self.time_of_goal = -1 self.ball_predictions = [] prediction = Ball(self.ball) while prediction.time < self.ball.time + time_limit: prediction.step(dt) self.ball_predictions.append(Ball(prediction)) if self.time_of_goal == -1: if self.my_goal.inside(prediction.position): self.about_to_be_scored_on = True self.time_of_goal = prediction.time if self.their_goal.inside(prediction.position): self.about_to_score = True self.time_of_goal = prediction.time
def predict_ball(self, num_steps, dt): self.about_to_score = False self.about_to_be_scored_on = False self.time_of_goal = -1 self.ball_predictions = [] prediction = Ball(self.ball) for _ in range(0, num_steps): prediction.step(dt) self.ball_predictions.append(Ball(prediction)) if self.time_of_goal == -1: if self.my_goal.inside(prediction.position): self.about_to_be_scored_on = True self.time_of_goal = prediction.time if self.their_goal.inside(prediction.position): self.about_to_score = True self.time_of_goal = prediction.time
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.game.read_game_information(packet, self.get_rigid_body_tick(), self.get_field_info()) # make a copy of the ball's info that we can change b = Ball(self.game.ball) ball_predictions = [] for i in range(360): # simulate the forces acting on the ball for 1 frame b.step(1.0 / 120.0) # and add a copy of new ball position to the list of predictions ball_predictions.append(vec3(b.location)) self.renderer.begin_rendering() red = self.renderer.create_color(255, 255, 30, 30) self.renderer.draw_polyline_3d(ball_predictions, red) self.renderer.end_rendering() return controller.get_output()
def reset_gamestate(self): print('> reset_gamestate()') # Initialize inputs self.reset_for_ground_shots() t = self.target b = Ball(self.game.ball) c = Car(self.game.cars[self.index]) b.location = to_vec3(self.initial_ball_location) b.velocity = to_vec3(self.initial_ball_velocity) c.location = to_vec3(self.initial_car_location) c.velocity = to_vec3(self.initial_car_velocity) # Point car at ball c.rotation = look_at( vec3(b.location[0] - c.location[0], b.location[1] - c.location[1], 0), vec3(0, 0, 1)) rotator = rotation_to_euler(c.rotation) # Reset self.aerial = None self.dodge = None self.rotation_input = None self.timer = 0.0 # Set gamestate car_state = CarState(boost_amount=100, physics=Physics( location=self.initial_car_location, velocity=self.initial_car_velocity, rotation=rotator, angular_velocity=Vector3(0, 0, 0))) ball_state = BallState( Physics(location=self.initial_ball_location, velocity=self.initial_ball_velocity, rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) game_state = GameState(ball=ball_state, cars={self.index: car_state}) self.set_game_state(game_state)
def get_hit_frame_numbers(df: pd.DataFrame): ball_df = df[DF_BALL_PREFIX] hit_frame_numbers = get_hit_frame_numbers_by_ball_ang_vel(df) # Filter by hit_team_no hit_frame_numbers = ball_df.loc[hit_frame_numbers].index[~ball_df.loc[ hit_frame_numbers, "hit_team_no"].isna()].tolist() logger.info(f"hit: {hit_frame_numbers}") delta_df = df.loc[:, (DF_GAME_PREFIX, 'delta')] RLUGame.set_mode("soccar") filtered_hit_frame_numbers = [] for frame_number in hit_frame_numbers: previous_frame_number = frame_number - 1 ball_previous_frame = ball_df.loc[previous_frame_number, :] initial_ang_vel = ball_previous_frame.loc[[ 'ang_vel_x', 'ang_vel_y', 'ang_vel_z' ]].values ball = Ball() # noinspection PyPropertyAccess ball.location = vec3( *ball_previous_frame.loc[['pos_x', 'pos_y', 'pos_z']]) # noinspection PyPropertyAccess ball.velocity = vec3( *ball_previous_frame.loc[['vel_x', 'vel_y', 'vel_z']]) # noinspection PyPropertyAccess ball.angular_velocity = vec3(*initial_ang_vel) frame_delta = delta_df[frame_number] delta_simulated = 0 while delta_simulated < frame_delta: dt = 1 / 120 time_to_simulate = min(dt, frame_delta - delta_simulated) ball.step(time_to_simulate) delta_simulated += time_to_simulate simulated_ball_ang_vel = np.array([ ball.angular_velocity[0], ball.angular_velocity[1], ball.angular_velocity[2] ]) actual_ball_ang_vel = ball_df.loc[ frame_number, ['ang_vel_x', 'ang_vel_y', 'ang_vel_z']].values actual_ang_vel_change = ((actual_ball_ang_vel - initial_ang_vel)**2).sum()**0.5 end_ang_vel_difference = ((simulated_ball_ang_vel - actual_ball_ang_vel)**2).sum()**0.5 relative_ang_vel_difference = end_ang_vel_difference / actual_ang_vel_change if relative_ang_vel_difference > 0.8: filtered_hit_frame_numbers.append(frame_number) return filtered_hit_frame_numbers
def simulate(self, bot) -> vec3: # print('simulate intercept') # Init vars c = Car(bot.game.my_car) b = Ball(bot.game.ball) t = vec3(bot.target) intercept = self.location dt = 1.0 / 60.0 hit = False min_error = None # Drive towards intercept (moving in direction of c.forward()) c.rotation = look_at(intercept, c.up()) direction = normalize(intercept - c.location) #c.forward() advance_distance = norm(intercept - c.location) - c.hitbox( ).half_width[0] - b.collision_radius translation = direction * advance_distance sim_start_state: ThrottleFrame = BoostAnalysis().travel_distance( advance_distance, norm(c.velocity)) c.velocity = direction * sim_start_state.speed c.location += translation c.time += sim_start_state.time bot.ball_predictions = [vec3(b.location)] while b.time < c.time: b.step(dt) bot.ball_predictions.append(vec3(b.location)) # print(c.time, b.time) # print(c.location, b.location) # Simulate the collision and resulting for i in range(60 * 3): c.location += c.velocity * dt b.step(dt, c) # Check if we hit the ball yet if norm(b.location - c.location) < (c.hitbox().half_width[0] + b.collision_radius) * 1.05: hit = True # print('hit') # Measure dist from target error = t - b.location if hit and (min_error == None or norm(error) < norm(min_error)): min_error = error # Record trajectory bot.ball_predictions.append(vec3(b.location)) if not hit: return None return min_error
def __init__(self, car: Car, ball_predictions, predicate: callable = None, backwards=False): self.ball: Ball = None self.is_viable = True #find the first reachable ball slice that also meets the predicate speed = 1000 if backwards else estimate_max_car_speed(car) # for ball in ball_predictions: for ball in ball_predictions: if estimate_time(car, ball.position, speed, -1 if backwards else 1) < ball.time - car.time \ and (predicate is None or predicate(car, ball)): self.ball = ball break #if no slice is found, use the last one if self.ball is None: if not ball_predictions: self.ball = Ball() else: self.ball = ball_predictions[-1] self.is_viable = False self.time = self.ball.time self.ground_pos = ground(self.ball.position) self.position = self.ball.position
def set_shots(hits_by_goal_number: Dict[int, Hit], game: Game, df: pd.DataFrame): ball_df = df[DF_BALL_PREFIX] player_id_to_team = { player.id.id: player.is_orange for player in game.players } for hits_list in hits_by_goal_number.values(): for hit in hits_list: direction_factor = -1**player_id_to_team[ hit.player_id.id] # -1 if orange, 1 if blue ball_data = ball_df.loc[hit.frame_number] ball = Ball() # noinspection PyPropertyAccess ball_location = ball_data.loc[['pos_x', 'pos_y', 'pos_z']] ball.location = vec3(*ball_location) # noinspection PyPropertyAccess ball_velocity = ball_data.loc[['vel_x', 'vel_y', 'vel_z']] ball.velocity = vec3(*ball_velocity) # noinspection PyPropertyAccess ball_angular_velocity = ball_data.loc[[ 'ang_vel_x', 'ang_vel_y', 'ang_vel_z' ]] ball.angular_velocity = vec3(*ball_angular_velocity) delta_simulated = 0 while delta_simulated < SHOT_SECONDS_SIMULATED: dt = 1 / 120 ball.step(min(dt, SHOT_SECONDS_SIMULATED - delta_simulated)) delta_simulated += dt ball_y = ball.location[1] if ball_y * direction_factor > FIELD_Y_LIM: hit.shot = True break
def calculate(car: Car, ball: Ball, target: vec3, ball_predictions=None): # Init vars b = Ball(ball) dt = 1.0 / 60.0 # Generate predictions of ball path if ball_predictions is None: ball_predictions = [] for i in range(60 * 5): b.step(dt) ball_predictions.append(vec3(b.location)) # Gradually converge on ball location by aiming at a location, checking time to that location, # and then aiming at the ball's NEW position. Guaranteed to converge (typically in <10 iterations) # unless the ball is moving away from the car faster than the car's max boost speed intercept = Intercept(b.location) intercept.purpose = 'ball' intercept.boost = True intercept_ball_position = vec3(b.location) collision_achieved = False last_horizontal_error = None last_horizontal_offset = None i = 0 max_tries = 101 analyzer = BoostAnalysis() if intercept.boost else ThrottleAnalysis() while i < max_tries: i += 1 fake_car = Car(car) direction = normalize(intercept.location - car.location) fake_car.rotation = look_at(direction, fake_car.up()) for t in range(60 * 5): # Step car location with throttle/boost analysis data # Not super efficient but POITROAE frame = analyzer.travel_time(dt, norm(fake_car.velocity)) # print('in 1 frame I travel', frame.time, frame.distance, frame.speed) fake_car.location += direction * frame.distance fake_car.velocity = direction * frame.speed fake_car.time += dt ball_location = ball_predictions[t] # Check for collision p = closest_point_on_obb(fake_car.hitbox(), ball_location) if norm(p - ball_location) <= ball.collision_radius: direction_vector = p - (fake_car.location - normalize( fake_car.forward()) * 13.88) # octane center of mass direction_vector[2] = 0 target_direction_vector = target - ball_location target_direction_vector[2] = 0 intercept_ball_position = ball_location direction = atan2(direction_vector[1], direction_vector[0]) ideal_direction = atan2(target_direction_vector[1], target_direction_vector[0]) horizontal_error = direction - ideal_direction # intercept.location = vec3(ball_location) # intercept.time = fake_car.time # return intercept # Now descend the hit direction gradient # Kick off the gradient descent with an arbitrary seed value if last_horizontal_error is None: last_horizontal_error = horizontal_error last_horizontal_offset = 0 if horizontal_error > 0: horizontal_offset = 25 else: horizontal_offset = 25 intercept.location = ball_location - normalize( fake_car.left()) * horizontal_offset break # Recursive case of gradient descent if horizontal_offset == last_horizontal_offset: gradient = 0 else: gradient = (horizontal_error - last_horizontal_error ) / (horizontal_offset - last_horizontal_offset) if gradient == 0: predicted_horizontal_offset = horizontal_offset else: predicted_horizontal_offset = horizontal_offset - horizontal_error / gradient # Base case (convergence) if abs(gradient) < 0.0005: print(f'convergence in {i} iterations') print(f'gradient = {gradient}') print( f'last_horizontal_offset = {last_horizontal_offset}' ) print(f'direction = {degrees(direction)}') print(f'ideal direction = {degrees(ideal_direction)}') print(f'target = {target}') print(f'ball_location = {ball_location}') return intercept # Edge case exit: offset maxed out max_horizontal_offset = car.hitbox( ).half_width[1] + ball.collision_radius if predicted_horizontal_offset > max_horizontal_offset: predicted_horizontal_offset = max_horizontal_offset elif predicted_horizontal_offset < -max_horizontal_offset: predicted_horizontal_offset = -max_horizontal_offset last_horizontal_offset = horizontal_offset last_horizontal_error = horizontal_error horizontal_offset = predicted_horizontal_offset # Return the latest intercept location and continue descending the gradient intercept.location = ball_location - normalize( fake_car.left()) * predicted_horizontal_offset print(f'iteration {i}') print(f'gradient = {gradient}') print(f'horizontal_offset = {horizontal_offset}') print(f'horizontal_error = {degrees(horizontal_error)}') # print(f'ideal direction = {degrees(ideal_direction)}') break # Check for arrival if norm(fake_car.location - intercept.location) < ball.collision_radius / 2: intercept.location = ball_location break if i >= max_tries: print( f'Warning: max tries ({max_tries}) exceeded for calculating intercept' ) return intercept
def set_ball_state(self, ball: Ball): ball.position = vec3(0, 0, 3000) ball.velocity = vec3(0, 0, 0) ball.angular_velocity = vec3(0, 0, 0)
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: # Update the game values and set the state self.game.read_game_information(packet, self.get_rigid_body_tick(), self.get_field_info()) self.controls = SimpleControllerState() next_state = self.state # Reset everything if self.state == State.RESET: self.timer = 0.0 self.set_state_stationary() next_state = State.WAIT # Wait so everything can settle in, mainly for ball prediction if self.state == State.WAIT: if self.timer > 0.2: next_state = State.INITIALIZE # Initialize the drive mechanic if self.state == State.INITIALIZE: self.drive = Drive(self.game.my_car) self.drive.target = self.game.ball.position + 200 * normalize( vec3(vec2(self.game.ball.position - vec3(0, 5120, 0)))) self.drive.speed = 1400 next_state = State.DRIVING # Start driving towards the target and check whether an aerial is possible, if so initialize the dodge if self.state == State.DRIVING: self.drive.target = self.game.ball.position + 200 * normalize( vec3(vec2(self.game.ball.position - vec3(0, 5120, 0)))) self.drive.step(self.game.time_delta) self.controls = self.drive.controls # Initialize the aerial and aerial turn self.aerial = Aerial(self.game.my_car) self.turn = AerialTurn(self.game.my_car) # predict where the ball will be prediction = Ball(self.game.ball) self.ball_predictions = [vec3(prediction.location)] # Loop over 87 frames which results in a time limit of 1.45 # Seeing we jump once and hold it for 0.2s we keep our second dodge until that moment a = time.time() for i in range(87): # Step the ball prediction and add it to the array for rendering prediction.step(0.016666) self.ball_predictions.append(vec3(prediction.location)) # TODO dont hardcode the goal vector! # Set the target to a slight offset of the ball so we will hit it towards the target or goal # Set the arrival time to the time the ball will be in that location # Set the preorientation so we will look at the goal goal = vec3(0, 5120, 0) # self.aerial.target = prediction.location + 200 * normalize(prediction.location - goal) self.aerial.target = vec3( 0, 0, ball_z) + 200 * normalize(prediction.location - goal) self.aerial.arrival_time = prediction.time print(prediction.time) # self.aerial.target_rotation = look_at(goal - self.aerial.target, vec3(0, 0, 1)) self.aerial.target_rotation = look_at( goal - self.game.my_car.position, vec3(0, 0, 1)) # Simulate the aerial and see whether its doable or not simulation = self.aerial.simulate # # check if we can reach it by an aerial if norm(simulation.location - self.aerial.target) < 100 and angle_between( simulation.rotation, self.aerial.target_rotation) < 0.01: print(i) print(prediction.location) print(self.game.my_car.orientation) print("predicted rotation") print(simulation.rotation) next_state = State.RUNNING break print("time:") print(time.time() - a) # Perform the aerial mechanic if self.state == State.RUNNING: self.aerial.step(self.game.time_delta) self.controls = self.aerial.controls if self.game.time == packet.game_ball.latest_touch.time_seconds: print(self.game.my_car.double_jumped) self.controls.jump = True print("actual rotation") print(self.game.my_car.orientation) if self.timer > self.timeout: next_state = State.RESET self.aerial = None self.turn = None self.timer += self.game.time_delta self.state = next_state # Render the target for the aerial self.renderer.begin_rendering() purple = self.renderer.create_color(255, 230, 30, 230) if self.aerial: r = 200 x = vec3(r, 0, 0) y = vec3(0, r, 0) z = vec3(0, 0, r) target = self.aerial.target self.renderer.draw_line_3d(target - x, target + x, purple) self.renderer.draw_line_3d(target - y, target + y, purple) self.renderer.draw_line_3d(target - z, target + z, purple) # self.renderer.draw_line_3d(self.game.my_car.position, # 1000 * dot(self.aerial.target_rotation, self.game.my_car.forward()), purple) # Render ball prediction if self.ball_predictions: self.renderer.draw_polyline_3d(self.ball_predictions, purple) self.renderer.end_rendering() return self.controls
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.game.read_game_information(packet, self.get_rigid_body_tick(), self.get_field_info()) if self.game.ball.location[2] > 250: if self.state == "Aerial": self.aerial.step(self.game.time_delta) if self.aerial.finished: self.state = "Not Aerial" return self.aerial.controls else: self.aerial = Aerial(self.game.my_car) self.aerial.up = normalize( vec3(random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1))) # predict where the ball will be prediction = Ball(self.game.ball) for i in range(100): prediction.step(0.016666) if prediction.location[2] > 500: self.aerial.target = prediction.location self.aerial.arrival_time = prediction.time if self.aerial.is_viable(): self.aerial.target = prediction.location self.aerial.arrival_time = prediction.time self.target_ball = Ball(prediction) self.state = "Aerial" break ball_location = Vector2(packet.game_ball.physics.location.x, packet.game_ball.physics.location.y) my_car = packet.game_cars[self.index] car_location = Vector2(my_car.physics.location.x, my_car.physics.location.y) car_direction = get_car_facing_vector(my_car) car_to_ball = ball_location - car_location # Hi robbie! # The,type;of,punctuation;matters! true = shreck is love, shreck is life main(9) if not true: print("https://www.twitch.tv/TehRedox is the best twitch channel") y.yeet() self.WHOOPITYScooPTI = 0 for i in range(packet.num_cars): self.WHOOPITYScooPTI += packet.game_cars[i].score_info.goals if self.WHOOPITYScooPTI > self.CountyTHIS_ALSOdonttuch: self.CountyTHIS_ALSOdonttuch = self.WHOOPITYScooPTI self.renderer.begin_rendering(str(y)) # commented out due to performance concerns # self.renderer.draw_polyline_3d([[car_location.x+triforce(-20,20), car_location.y+triforce(-20,20), triforce(shreck(200),200)] for i in range(40)], self.renderer.cyan()) self.renderer.draw_rect_2d( 0, 0, 3840, 2160, True, self.renderer.create_color( 64, 246, 74, 138)) # first bot that supports 4k resolution! self.renderer.draw_string_2d(triforce(0, 100), triforce(0, 10), 8, 8, 'BANIME', self.renderer.lime()) self.renderer.draw_string_2d( triforce(0, 100), triforce(100, 110), 8, 8, 'SCRATCH IS \n ASSEMBLY \n (also banormies) \n https://www.twitch.tv/donutkiller_pro', self.renderer.red()) self.renderer.end_rendering() steer_correction_radians = car_direction.correction_to(car_to_ball) turn = clamp11(steer_correction_radians * -3) if self.flippityThe_CAR < 1: self.howDoIUse_this[self.howDoIUse_this[0][5]] = True self.flippityThe_CAR = 1 elif self.flippityThe_CAR < 2: self.howDoIUse_this[self.howDoIUse_this[0][5]] = False self.flippityThe_CAR = 2 elif self.flippityThe_CAR < 3: self.howDoIUse_this[self.howDoIUse_this[0][5]] = True self.flippityThe_CAR = 3 elif self.flippityThe_CAR < 666: self.howDoIUse_this[self.howDoIUse_this[0][5]] = False self.flippityThe_CAR += 6 elif self.flippityThe_CAR >= 666: self.flippityThe_CAR = 0 self.howDoIUse_this[self.howDoIUse_this[0][0]] = 1 self.howDoIUse_this[self.howDoIUse_this[0][1]] = turn self.howDoIUse_this[self.howDoIUse_this[0][6]] = ( abs(turn) < 0.2 and not my_car.is_super_sonic) self.howDoIUse_this[self.howDoIUse_this[0][7]] = ( abs(turn) > 1.5 and not my_car.is_super_sonic) return getSensible_thingToCONTROL(self.howDoIUse_this)
from rlutilities.linear_algebra import vec3, mat3 from rlutilities.simulation import Game, Car, Ball, intersect Game.set_mode("dropshot") c = Car() c.location = vec3(-164.13, 0, 88.79) c.velocity = vec3(1835.87, 0, 372.271) c.angular_velocity = vec3(0, 3.78721, 0) c.rotation = mat3(0.9983, -5.23521e-6, 0.0582877, 5.5498e-6, 1.0, -5.23521e-6, -0.0582877, 5.5498e-6, 0.9983) b = Ball() b.location = vec3(0, 0, 150) b.velocity = vec3(0, 0, 0) b.angular_velocity = vec3(0, 0, 0) print("before:") print(b.location) print(b.velocity) print(b.angular_velocity) print("overlapping: ", intersect(c.hitbox(), b.hitbox())) print() b.step(0.008333, c) print("after:") print(b.location)
def calculate_old(car: Car, ball: Ball, target: vec3, ball_predictions=None): # Init vars fake_car = Car(car) b = Ball(ball) # Generate predictions of ball path if ball_predictions is None: ball_predictions = [vec3(b.location)] for i in range(60 * 5): b.step(1.0 / 60.0) ball_predictions.append(vec3(b.location)) # Gradually converge on ball location by aiming at a location, checking time to that location, # and then aiming at the ball's NEW position. Guaranteed to converge (typically in <10 iterations) # unless the ball is moving away from the car faster than the car's max boost speed intercept = Intercept(b.location) intercept.purpose = 'ball' intercept.boost = True intercept_ball_position = vec3(b.location) i = 0 max_tries = 100 analyzer = BoostAnalysis() if intercept.boost else ThrottleAnalysis() while i < max_tries: # Find optimal spot to hit the ball optimal_hit_vector = normalize( target - intercept_ball_position) * b.collision_radius optimal_hit_location = intercept_ball_position - optimal_hit_vector # Find ideal rotation, unless it intersects with ground optimal_rotation = look_at( optimal_hit_vector, vec3(0, 0, 1) ) #axis_to_rotation(optimal_hit_vector) # this might be wrong fake_car.rotation = optimal_rotation # print(f'fake_car.location {fake_car.location}') # print(f'get_car_front_center(fake_car) {get_car_front_center(fake_car)}') fake_car.location += optimal_hit_location - get_car_front_center( fake_car ) # try to position the car's front center directly on top of the best hit vector euler = rotation_to_euler(optimal_rotation) # todo put some super precise trigonometry in here to find the max angle allowed at given height if fake_car.location[2] <= fake_car.hitbox().half_width[0]: euler.pitch = 0 fake_car.rotation = euler_to_rotation( vec3(euler.pitch, euler.yaw, euler.roll)) fake_car.location += optimal_hit_location - get_car_front_center( fake_car ) # try to position the car's front center directly on top of the best hit vector # Adjust vertical position if it (still) intersects with ground if fake_car.location[2] < 17.0: fake_car.location[2] = 17.0 intercept.location = get_car_front_center(fake_car) # Calculate jump time needed jump_height_time = JumpAnalysis().get_frame_by_height( intercept.location[2]).time # or solve with motion equation # car_euler = rotation_to_euler(car.rotation) # jump_pitch_time = (euler.pitch - car_euler.pitch) / 5.5 + 0.35 # disregarding angular acceleration # jump_yaw_time = (euler.yaw - car_euler.yaw) / 5.5 + 0.35 # disregarding angular acceleration # jump_roll_time = (euler.roll - car_euler.roll) / 5.5 + 0.35 # disregarding angular acceleration # jump_time = max(jump_height_time, jump_pitch_time, jump_yaw_time, jump_roll_time) jump_time = jump_height_time # todo revisit rotation time # print('jump_time', jump_time) # Calculate distance to drive before jumping (to arrive perfectly on target) total_translation = intercept.location - get_car_front_center(car) total_translation[2] = 0 total_distance = norm(total_translation) start_index = analyzer.get_index_by_speed(norm(car.velocity)) start_frame = analyzer.frames[start_index] custom_error_func = lambda frame: abs(total_distance - ( frame.distance - start_frame.distance) - frame.speed * jump_time) drive_analysis = analyzer.get_frame_by_error( custom_error_func, start_index) arrival_time = drive_analysis.time - start_frame.time + jump_time # print('drive_analysis.time', drive_analysis.time) # print('drive_analysis', start_index) # arrival_time = analyzer.travel_distance(total_distance, norm(car.velocity)).time # drive_analysis = analyzer.travel_distance(norm(intercept.location - c.location), norm(c.velocity)) ball_index = int(round(arrival_time * 60)) if ball_index >= len(ball_predictions): intercept.location = ball_predictions[-1] intercept.time = len(ball_predictions) / 60.0 break ball_location = ball_predictions[ball_index] # print(f'Iteration {i} distance {norm(ball_location + vec3(optimal_hit_vector[0], optimal_hit_vector[1], 0) - intercept.location)}') if norm(ball_location - intercept_ball_position) <= 1: # if norm(intercept_ball_position - get_car_front_center(fake_car)) > 100: # intercept.location = ball_predictions[-1] # intercept.time = len(ball_predictions) / 60.0 # return intercept intercept.dodge = True #jump_time > 0.2 intercept.jump_time = car.time + arrival_time - jump_time intercept.dodge_preorientation = euler_to_rotation( vec3(euler.pitch, euler.yaw, euler.roll)) intercept.dodge_delay = jump_time intercept.dodge_direction = normalize(vec2(optimal_hit_vector)) # print(f'intercept_ball_position', intercept_ball_position) # print(f'intercept.location', intercept.location) # print(f'time until jump {drive_analysis.time}') # print(f'time now {car.time}') # print(f'distance until jump {drive_analysis.distance}') # print(f'total distance to target {total_distance}') # print(f'horiz speed @ jump {drive_analysis.speed}') # print(f'time intended to be in air {jump_time}') # print(f'distance travelled in air {jump_time * drive_analysis.speed}') # print(f'distance remaining to target @ jump {total_distance - drive_analysis.distance}') # print(f'Intercept convergence in {i} iterations') # print(f'desired roll {euler.roll}') # print(f'actual roll {rotation_to_euler(c.rotation).roll}') break intercept_ball_position = vec3(ball_location) # intercept.location = vec3(ball_location) # intercept.location[2] = 0 intercept.time = arrival_time i += 1 if i >= max_tries: print( f'Warning: max tries ({max_tries}) exceeded for calculating intercept' ) # Intercept is only meant for ground paths (and walls/cieling are only indirectly supported) # collision_radius = c.hitbox().half_width[2] * 2 + b.collision_radius + b.collision_radius * 8 # on_ground = intercept.location[2] <= collision_radius # on_back_wall = abs(intercept.location[1]) >= 5120 - collision_radius # on_side_wall = abs(intercept.location[0]) >= 4096 - collision_radius # # on_cieling = intercept.location[2] >= 2044 - collision_radius # reachable = on_ground # or on_back_wall or on_side_wall # or on_cieling # if not reachable: # return None return intercept
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() next_state = self.state if self.state == State.RESET: self.timer = 0.0 b_position = Vector3(random.uniform(-1500, 1500), random.uniform( 2500, 3500), random.uniform( 300, 500)) b_velocity = Vector3(random.uniform(-300, 300), random.uniform(-100, 100), random.uniform(1000, 1500)) ball_state = BallState(physics=Physics( location=b_position, velocity=b_velocity, rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0) )) # this just initializes the car and ball # to different starting points each time c_position = Vector3(b_position.x, 0 * random.uniform(-1500, -1000), 25) #c_position = Vector3(200, -1000, 25) car_state = CarState(physics=Physics( location=c_position, velocity=Vector3(0, 800, 0), rotation=Rotator(0, 1.6, 0), angular_velocity=Vector3(0, 0, 0) ), boost_amount=100) self.set_game_state(GameState( ball=ball_state, cars={self.game.id: car_state}) ) next_state = State.WAIT if self.state == State.WAIT: if self.timer > 0.2: next_state = State.INITIALIZE if self.state == State.INITIALIZE: self.aerial = Aerial(self.game.my_car) # self.aerial.up = normalize(vec3( # random.uniform(-1, 1), # random.uniform(-1, 1), # random.uniform(-1, 1))) self.turn = AerialTurn(self.game.my_car) # predict where the ball will be prediction = Ball(self.game.ball) self.ball_predictions = [vec3(prediction.location)] for i in range(100): prediction.step(0.016666) prediction.step(0.016666) self.ball_predictions.append(vec3(prediction.location)) # if the ball is in the air if prediction.location[2] > 500: self.aerial.target = prediction.location self.aerial.arrival_time = prediction.time simulation = self.aerial.simulate() # # check if we can reach it by an aerial if norm(simulation.location - self.aerial.target) < 100: prediction.step(0.016666) prediction.step(0.016666) self.aerial.target = prediction.location self.aerial.arrival_time = prediction.time self.target_ball = Ball(prediction) break next_state = State.RUNNING if self.state == State.RUNNING: self.log.write(f"{{\"car\":{self.game.my_car.to_json()}," f"\"ball\":{self.game.ball.to_json()}}}\n") self.aerial.step(self.game.time_delta) self.controls = self.aerial.controls if self.timer > self.timeout: next_state = State.RESET self.aerial = None self.turn = None self.timer += self.game.time_delta self.state = next_state self.renderer.begin_rendering() red = self.renderer.create_color(255, 230, 30, 30) purple = self.renderer.create_color(255, 230, 30, 230) white = self.renderer.create_color(255, 230, 230, 230) if self.aerial: r = 200 x = vec3(r, 0, 0) y = vec3(0, r, 0) z = vec3(0, 0, r) target = self.aerial.target self.renderer.draw_line_3d(target - x, target + x, purple) self.renderer.draw_line_3d(target - y, target + y, purple) self.renderer.draw_line_3d(target - z, target + z, purple) if self.ball_predictions: self.renderer.draw_polyline_3d(self.ball_predictions, purple) self.renderer.end_rendering() return self.controls
def set_ball_state(self, ball: Ball): ball.position = vec3(-11390, -6950, 470) ball.velocity = vec3(0, 0, 0) ball.angular_velocity = vec3(0, 0, 0)