def simulate_landing(self): pos = vec3(self.car.position) vel = vec3(self.car.velocity) grav = vec3(0, 0, -650) self.trajectory = [vec3(pos)] self.landing = False collision_normal: Optional[vec3] = None dt = 1 / 60 simulation_duration = 0.8 for i in range(int(simulation_duration / dt)): pos += vel * dt vel += grav * dt if norm(vel) > 2300: vel = normalize(vel) * 2300 self.trajectory.append(vec3(pos)) collision_sphere = sphere(pos, 50) collision_ray = Field.collide(collision_sphere) collision_normal = collision_ray.direction if (norm(collision_normal) > 0.0 or pos[2] < 0) and i > 20: self.landing = True self.landing_pos = pos break if self.landing: u = collision_normal f = normalize(vel - dot(vel, u) * u) l = normalize(cross(u, f)) self.aerial_turn.target = three_vec3_to_mat3(f, l, u) else: target_direction = normalize( normalize(self.car.velocity) - vec3(0, 0, 3)) self.aerial_turn.target = look_at(target_direction, vec3(0, 0, 1))
def step(self, packet: GameTickPacket, drone: Drone, index: int): up = normalize(drone.position) drone.aerial_turn.target = look_at(vec3(0, 0, 1), up) drone.aerial_turn.step(self.dt) drone.controls = drone.aerial_turn.controls drone.controls.boost = angle_between(vec3(0, 0, 1), drone.forward()) < 0.5 drone.controls.jump = True
def __init__(self, car: Car, ball_predictions, predicate: callable = None): self.ball: Ball = None self.is_viable = True #find the first reachable ball slice that also meets the predicate test_car = Car(car) test_aerial = Aerial(car) for ball in ball_predictions: test_aerial.target = ball.position test_aerial.arrival_time = ball.time # fake our car state :D dir_to_target = ground_direction(test_car.position, test_aerial.target) test_car.velocity = dir_to_target * max(norm(test_car.velocity), 1200) test_car.orientation = look_at(dir_to_target, vec3(0,0,1)) if test_aerial.is_viable() 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: 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 defending(agent): """"Method that gives output for the defending strategy""" target = defending_target(agent) agent.drive.target = target distance = distance_2d(agent.info.my_car.position, target) vf = velocity_forward(agent.info.my_car) dodge_overshoot = distance < (abs(vf) + 500) * 1.5 agent.drive.speed = get_speed(agent, target) agent.drive.step(agent.info.time_delta) agent.controls = agent.drive.controls t = time.time() can_dodge, simulated_duration, simulated_target = agent.simulate() # print(time.time() - t) if can_dodge: agent.dodge = Dodge(agent.info.my_car) agent.turn = AerialTurn(agent.info.my_car) agent.dodge.duration = simulated_duration - 0.1 agent.dodge.target = simulated_target agent.dodge.preorientation = look_at(simulated_target, vec3(0, 0, 1)) agent.timer = 0 agent.step = Step.Dodge if not agent.should_defend(): agent.step = Step.Shooting elif vf < -900 and (not dodge_overshoot or distance < 600): agent.step = Step.HalfFlip agent.halfflip = HalfFlip(agent.info.my_car) elif not dodge_overshoot and agent.info.my_car.position[2] < 80 and \ (agent.drive.speed > abs(vf) + 300 and 1200 < abs(vf) < 2000 and agent.info.my_car.boost <= 25): # Dodge towards the target for speed agent.step = Step.Dodge agent.dodge = Dodge(agent.info.my_car) agent.dodge.duration = 0.1 agent.dodge.target = target
def __init__(self, name, team, index): self.name = name self.index = index self.policy = Policy(hidden_size, hidden_size_2).to(device) self.policy.load_state_dict(model) self.simulation = Simulation(self.policy) self.controls = SimpleControllerState() self.finished = False self.FPS = 120 self.lastTime = 0 self.realLastTime = 0 self.currentTick = 0 self.skippedTicks = 0 self.doneTicks = 0 self.ticksNowPassed = 0 self.lastDodgeTick = -math.inf self.lastDodgePitch = 0 self.lastDodgeRoll = 0 self.lastReset = 0 self.target = vec3(1, 0, 0) self.up = vec3(0, 0, 1) self.targetOrientation = look_at(self.target, self.up) self.lastDoneTick = 0 self.totalScore = 0 self.tests = 0 self.stage = 0
def simulate_landing(self): dummy = Car(self.car) self.trajectory = [vec3(dummy.position)] self.landing = False collision_normal: Optional[vec3] = None dt = 1 / 60 simulation_duration = 0.8 for i in range(int(simulation_duration / dt)): dummy.step(Input(), dt) self.trajectory.append(vec3(dummy.position)) collision_sphere = sphere(dummy.position, 50) collision_ray = Field.collide(collision_sphere) collision_normal = collision_ray.direction if (norm(collision_normal) > 0.0 or dummy.position[2] < 0) and i > 20: self.landing = True self.landing_pos = dummy.position break if self.landing: u = collision_normal f = normalize(dummy.velocity - dot(dummy.velocity, u) * u) l = normalize(cross(u, f)) self.aerial_turn.target = mat3(f[0], l[0], u[0], f[1], l[1], u[1], f[2], l[2], u[2]) else: target_direction = normalize( normalize(self.car.velocity) - vec3(0, 0, 3)) self.aerial_turn.target = look_at(target_direction, vec3(0, 0, 1))
def tick(self, packet: GameTickPacket) -> bool: if self.agent.car.on_ground: self.controller.jump = not self.controller.jump self.controller.throttle = 1 return True else: self.controller.jump = self.agent.car.velocity[2] > 100 self.controller.boost = dot(self.agent.car.forward(), vec3( 0, 0, -1)) * dot(self.agent.car.velocity, vec3(0, 0, -1)) < 0 self.controller.throttle = self.controller.boost and self.agent.car.position[ 2] > 150 hitbox = self.agent.car.hitbox() target = normalize( flatten(dot(self.agent.car.orientation, hitbox.half_width))) tmp = vec3(-hitbox.half_width[1], 0, 0) target = dot(self.agent.car.orientation, tmp) + vec3( 0, 0, -hitbox.half_width[0]) # self.agent.draw.vector(self.agent.car.position, target) self.agent.reorientML.target_orientation = look_at( target, self.direction * self.agent.car.left() if abs(self.agent.car.velocity[2]) < 20 else self.agent.car.velocity) self.agent.reorientML.step(1 / self.agent.FPS) self.controller.yaw = self.agent.reorientML.controls.yaw self.controller.pitch = self.agent.reorientML.controls.pitch self.controller.roll = self.agent.reorientML.controls.roll return True
def set_drone_states(self, drones: List[Drone]): # get the length of the path from start to the dragons's head (first bot) head_t = self.time_since_start / self.duration * self.path.length for drone in drones: # offset the other body parts drone_t = head_t - self.distance_between_body_parts * ( drone.id - drones[0].id) # if we're not on the path yet, don't do any state setting if drone_t < 0: continue t = self.path.length - drone_t # because Curve.point_at's argument means distance to end pos = self.path.point_at(t) pos_ahead = self.path.point_at(t - 500) pos_behind = self.path.point_at(t + 300) # figure out the orientation of the body part facing_direction = direction(pos_behind, pos) target_left = cross(facing_direction, direction(pos, pos_ahead)) target_up = cross(target_left, facing_direction) up = drone.up() + target_up * 0.9 + vec3(0, 0, 0.1) target_orientation = look_at(facing_direction, up) drone.position = pos_behind drone.velocity = facing_direction * (self.path.length / self.duration) drone.angular_velocity = vec3( 0, 0, 0 ) # TODO: setting correct angular velocity could help with replays drone.orientation = target_orientation
def __init__(self, car): self.timer = 0 self.car = car self.direction = vec3(car.forward() * -1) self.target = self.direction * 1000 + self.car.location self.aerial_turn = AerialTurn(car) self.aerial_turn.target = look_at(self.direction, vec3(0, 0, 1)) self.controls = SimpleControllerState() self.finished = False
def set_drone_states(self, drones: List[Drone]): for i, drone in enumerate(drones): angle = i * math.pi * 2 / len(drones) rot = rotation(angle) v = vec3(dot(rot, vec2(1, 0))) drone.position = v * self.radius + self.center drone.orientation = look_at(v * -1, vec3(0, 0, 1)) drone.velocity = vec3(0, 0, 0) drone.angular_velocity = vec3(0, 0, 0)
def step(self, dt): if self.aerialing: self.aerial.target_orientation = look_at( direction(self.car, self.target), vec3(0, 0, -1)) self.aerial.step(dt) self.controls = self.aerial.controls self.finished = self.aerial.finished else: super().step(dt) # simulate aerial from current state simulated_car = self.simulate_flight(self.car) # if the car ended up too far, we're too fast and we need to slow down if ground_distance(self.car, self.aerial.target) + 100 < ground_distance( self.car, simulated_car): # self.controls.throttle = -1 pass # if it ended up near the target, we could take off elif distance(simulated_car, self.aerial.target) < self.MAX_DISTANCE_ERROR: if angle_to(self.car, self.aerial.target) < 0.1 or norm( self.car.velocity) < 1000: if self.DELAY_TAKEOFF: # extrapolate current state a small amount of time future_car = Car(self.car) time = 0.2 future_car.time += time displacement = future_car.velocity * time if norm(future_car.velocity) > 500\ else normalize(future_car.velocity) * 500 * time future_car.position += displacement # simulate aerial fot the extrapolated car again future_simulated_car = self.simulate_flight( future_car, write_to_flight_path=False) # if the aerial is also successful, that means we should continue driving instead of taking off # this makes sure that we go for the most late possible aerials, which are the most effective if distance( future_simulated_car, self.aerial.target) > self.MAX_DISTANCE_ERROR: self.aerialing = True else: self.too_early = True else: self.aerialing = True else: # self.controls.boost = True self.controls.throttle = 1
def rotate(self, car: Car, target: vec3, dt) -> SimpleControllerState: # up = vec3(*[self.car.theta[i, 2] for i in range(3)]) target_rotation = look_at(self.target, vec3(0, 0, 1)) action = AerialTurn(car) action.target = target_rotation action.step(dt) controls = action.controls return controls
def set_drone_states(self, drones: List[Drone]): for i, drone in enumerate(drones): shifted_index = i - 15 sign = 1 if shifted_index >= 0 else -1 if sign > 0: shifted_index = 15 - shifted_index drone.position = vec3(shifted_index * 200 + sign * 800, -600 * sign, 20) drone.velocity = vec3(0, 0, 0) drone.angular_velocity = vec3(0, 0, 0) drone.orientation = look_at(vec3(0, 1, 0) * sign, vec3(0, 0, 1))
def step(self, dt): if self.jumping: self.controls = Input() # first jump for full 0.2 sec if self.timer <= 0.2: self.controls.jump = True # single tick between jumps elif self.timer <= 0.2 + dt * JUMP_FALSE_TICKS: self.controls.jump = False # second jump else: self.controls.jump = True self.jumping = False self.timer += dt else: self.finished = self.intercept.time < self.info.time if self.car.on_ground: # manage speed before jump distance_to_target = ground_distance(self.car.position, self.intercept.position) if distance_to_target < MIN_DIST_BEFORE_SPEED_CONTROL: target_speed = distance_to_target / self.time_for_jump self.drive.target_speed = -target_speed if self._should_strike_backwards else target_speed self.drive.step(dt) self.controls = self.drive.controls else: super().step(dt) # decide when to jump ground_vel = ground(self.car.velocity) direction_to_target = ground_direction(self.car.position, self.intercept.position) alignment = dot(normalize(ground_vel), direction_to_target) # check alignment if alignment >= MIN_ALIGNMENT: # check that speed is correct speed_in_direction = dot(ground_vel, direction_to_target) time_to_target = distance_to_target / speed_in_direction if self.time_for_jump - ALLOWED_TIME_ERROR <= time_to_target <= self.time_for_jump + ALLOWED_TIME_ERROR: self.jumping = True # after jump (when the car is in the air) else: # face the ball for some additional height self.reorient.target_orientation = look_at( direction(self.car.position, self.info.ball), vec3(0, 0, 1)) self.reorient.step(dt) self.controls = self.reorient.controls
def step(self, dt): super().step(dt) if not self.jump.finished and not self.car.on_ground: target_direction = direction(self.car, self.target + vec3(0, 0, 200)) up = target_direction * (-1) up[2] = 1 up = normalize(up) self.reorient.target_orientation = look_at(target_direction, up) self.reorient.step(dt) self.controls.pitch = self.reorient.controls.pitch self.controls.yaw = self.reorient.controls.yaw self.controls.roll = self.reorient.controls.roll
def step(self, dt): delta_target = self.target - self.car.position if norm(delta_target) > 500: delta_target = direction(self.car.position, self.target) * 500 target_direction = delta_target - self.car.velocity + vec3(0, 0, 500) self.turn.target = look_at(target_direction, direction(self.car.position, vec3(0, 0, 0))) self.turn.step(dt) self.controls = self.turn.controls self.controls.boost = delta_target[2] - self.car.velocity[2] * 0.5 > 0 and self.car.forward()[2] > 0.2 self.controls.throttle = not self.car.on_ground self.controls.jump = self.car.position[2] < 30 and self.info.time % 1.0 < 0.5
def step(self, dt: float): self.speed = abs(self.speed) car_to_target = (self.target - self.car.location) local_target = dot(car_to_target, self.car.rotation) angle = atan2(local_target[1], local_target[0]) vel = norm(self.car.velocity) in_air = (not self.car.on_ground) on_wall = (self.car.location[2] > 250 and not in_air) reverse = (cos(angle) < 0 and not (on_wall or in_air or self.kickoff)) get_off_wall = (on_wall and local_target[2] > 450) if get_off_wall: car_to_target[2] = -self.car.location[2] local_target = dot(car_to_target, self.car.rotation) angle = atan2(local_target[1], local_target[0]) max_speed = self.determine_max_speed(local_target) self.update_rlu_drive(reverse, max_speed) self.rlu_drive.step(dt) self.finished = self.rlu_drive.finished self.controls = self.rlu_drive.controls self.controls.handbrake = False if reverse: angle = -invert_angle(angle) if self.power_turn and not on_wall: angle *= -1 self.controls.handbrake = (vel > 200) self.controls.steer = cap(angle * 3, -1, 1) self.controls.boost = False if not self.controls.handbrake: self.controls.handbrake = (abs(angle) > radians(70) and vel > 500 and not on_wall) if self.controls.handbrake: self.controls.handbrake = (dot(self.car.velocity, car_to_target) > -150) if in_air: self.aerial_turn.target = look_at(xy(car_to_target), vec3(0, 0, 1)) self.aerial_turn.step(dt) aerial_turn_controls = self.aerial_turn.controls self.controls.pitch = aerial_turn_controls.pitch self.controls.yaw = aerial_turn_controls.yaw self.controls.roll = aerial_turn_controls.roll self.controls.boost = False
def step(self, dt): delta_target = self.target - self.car.position target_direction = normalize( vec3((delta_target[0]) * self.P - self.car.velocity[0] * self.D, (delta_target[1]) * self.P - self.car.velocity[1] * self.D, 1000)) self.turn.target = look_at(target_direction, self.up) self.turn.step(dt) self.controls = self.turn.controls self.controls.boost = 0 # tap boost to keep height if (delta_target[2] - self.car.velocity[2] * 0.5) > 0: self.controls.boost = 1
def set_drone_states(self, drones: List[Drone]): for drone in drones: t = self.time_since_start / self.duration * self.curve.length t -= self.distance_between_body_parts * (drone.id - self.target_indexes[0]) t = self.curve.length - t pos = self.curve.point_at(t) pos_ahead = self.curve.point_at(t - 500) pos_behind = self.curve.point_at(t + 30) facing_direction = direction(pos_behind, pos) target_left = cross(facing_direction, direction(pos, pos_ahead)) target_up = cross(target_left, facing_direction) up = drone.up() + target_up * 0.9 + vec3(0, 0, 0.1) target_orientation = look_at(facing_direction, up) drone.position = pos drone.velocity = facing_direction * (self.curve.length / self.duration) drone.angular_velocity = vec3(0, 0, 0) drone.orientation = target_orientation
def set_drone_states(self, drones: List[Drone]): drone = drones[1] drone.position = vec3(-1500, 500, 800) drone.velocity = vec3(0, 0, 0) drone.angular_velocity = vec3(0, 0, 0) drone.orientation = look_at(vec3(0, 0, 500), vec3(0, 0, 1))
def get_output(self, packet: GameTickPacket) -> SimpleControllerState: self.renderer.begin_rendering() self.game.read_game_information(packet, self.get_rigid_body_tick(), self.get_field_info()) if self.lastReset + 300 < self.currentTick: if self.tests > 0: score = min(300, self.currentTick - self.lastDoneTick) self.totalScore += score print(self.tests, score, round(self.totalScore / self.tests, 2)) self.tests += 1 self.lastReset = self.currentTick self.target = vec3(2 * random() - 1, 2 * random() - 1, 2 * random() - 1) self.up = orthogonalize( vec3(2 * random() - 1, 2 * random() - 1, 2 * random() - 1), self.target) self.targetOrientation = look_at(self.target, self.up) car_state = CarState( physics=Physics(location=Vector3(0, 1000, 17), velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0), angular_velocity=Vector3(0, 0, 0))) self.set_game_state(GameState(cars={self.index: car_state})) self.stage = 0 self.lastDodgeTick = -math.inf # print("TELEPORT TO GROUND") return self.controls else: car_state = CarState(physics=Physics(location=Vector3(0, 0, 400), velocity=Vector3(0, 0, 0))) self.set_game_state(GameState(cars={self.index: car_state})) if self.stage <= 5: self.stage += 1 if self.stage == 6: self.dodgeDirection = normalize(vec2(0, 2 * random() - 1)) self.controls.jump = True #random() > 0.5 if self.controls.jump: self.lastDodgeTick = self.currentTick self.controls.roll, self.controls.pitch, self.controls.yaw = self.dodgeDirection[ 0], self.dodgeDirection[1], 0 self.stage += 1 return self.controls else: self.controls.jump = False self.packet = packet self.handleTime() car = packet.game_cars[self.index] position = vec3(car.physics.location.x, car.physics.location.y, car.physics.location.z) self.renderer.draw_line_3d(car.physics.location, position + 300 * normalize(self.target), self.renderer.yellow()) self.renderer.draw_line_3d(car.physics.location, position + 300 * normalize(self.up), self.renderer.pink()) carOrientation = rotationToOrientation(car.physics.rotation) ang = parseVector(car.physics.angular_velocity) if angle_between(carOrientation, self.targetOrientation) > 1 / 180 * math.pi: self.lastDoneTick = self.currentTick o_rlu = dot(transpose(self.targetOrientation), carOrientation) w_rlu = dot(transpose(self.targetOrientation), ang) o = torch.tensor([[o_rlu[i, j] for j in range(3)] for i in range(3)])[None, :].float().to(device) w = torch.tensor([w_rlu[i] for i in range(3)])[None, :].float().to(device) noPitchTime = max(0, (self.lastDodgeTick - self.currentTick) / 120 + .95) dodgeTime = max(0, (self.lastDodgeTick - self.currentTick) / 120 + .65) if dodgeTime == 0: self.dodgeDirection = vec2(0, 0) noPitchTime = torch.tensor([noPitchTime]).float().to(device) dodgeTime = torch.tensor([dodgeTime]).float().to(device) dodgeDirection = torch.tensor([ self.dodgeDirection[i] for i in range(2) ])[None, :].float().to(device) # if self.simulation.o is not None and self.simulation.w is not None: # print("=====================================") # print("-------------------------------------") # print(self.simulation.o, o) # print(self.simulation.w, w) # print(self.simulation.noPitchTime, noPitchTime) # print(self.simulation.dodgeTime, dodgeTime) # print(self.simulation.dodgeDirection, dodgeDirection) # self.simulation.step(self.ticksNowPassed / 120) # print(self.simulation.o, o) # print(self.simulation.w, w) # print(self.simulation.noPitchTime, noPitchTime) # print(self.simulation.dodgeTime, dodgeTime) # print(self.simulation.dodgeDirection, dodgeDirection) self.simulation.o = o self.simulation.w = w self.simulation.noPitchTime = noPitchTime self.simulation.dodgeTime = dodgeTime self.simulation.dodgeDirection = dodgeDirection if True: rpy = self.policy(self.simulation.o.permute(0, 2, 1), self.simulation.w_local(), self.simulation.noPitchTime, self.simulation.dodgeTime, self.simulation.dodgeDirection)[0] self.controls.roll, self.controls.pitch, self.controls.yaw = rpy else: self.reorientML.target_orientation = self.targetOrientation self.reorientML.step(1 / self.FPS) self.controls.roll, self.controls.pitch, self.controls.yaw = self.reorientML.controls.roll, self.reorientML.controls.pitch, self.reorientML.controls.yaw if self.simulation.error()[0].item() < 0.01: self.frames_done += 1 else: self.frames_done = 0 if self.frames_done >= 10: self.finished = True self.renderer.end_rendering() return self.controls
def kickoffTick(self, packet: GameTickPacket) -> bool: isBallInCenter = packet.game_ball.physics.location.x == 0 and packet.game_ball.physics.location.y == 0 carToBallDistance = norm(self.agent.car.position - self.agent.game.ball.position) # if at any point something goes wrong and i'll be way too late, cancel the kickoff early. if isBallInCenter: for car in self.agent.game.cars[:self.agent.game.num_cars]: if car.team != self.agent.car.team and norm( car.position - self.agent.game.ball.position ) + 200 < carToBallDistance: print("kickoff failed!! big problems..") self.agent.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Apologies_Cursing) return False speed = norm(self.agent.car.velocity) self.controller.throttle = 1 self.controller.boost = speed < 2300 - 991.666 / 120 * ( 1 if self.controller.boost else 10) and self.agent.car.boost > 0 if speed < 10: self.startTime = self.agent.currentTick self.isDiagonalKickoff = abs(self.agent.car.position[0]) >= 1024 self.isSemiDiagonalKickoff = abs( abs(self.agent.car.position[0]) - 256) < 128 self.isStraightKickoff = not self.isDiagonalKickoff and not self.isSemiDiagonalKickoff if self.isSemiDiagonalKickoff: # force speedflip direction to pick up boost self.speedFlipDirection = math.copysign( 1, self.agent.car.position[0] * (2 * self.agent.car.team - 1)) self.speedFlipMaxTurnTicks = 15 self.riskyStrat = self.full_kickoff_strength if self.speedFlipState == 0 and self.isDiagonalKickoff and self.alternateDiagonalKickoff: self.alternateDiagonalKickoff = False for car in self.agent.game.cars[:self.agent.game.num_cars]: if car.team != self.agent.car.team: if norm(car.position - self.agent.game.ball.position ) < carToBallDistance + 150: try: crossWithYAxis = ( car.position[1] - self.agent.game.ball.position[1] - (car.position[0] - self.agent.game.ball.position[0]) / car.velocity[0] * car.velocity[1]) * ( 2 * car.team - 1) if crossWithYAxis > 300: self.alternateDiagonalKickoff = True break except ZeroDivisionError: self.alternateDiagonalKickoff = True break target = self.agent.game.ball.position # LOGIC TO CANCEL THE RISKY STRAT if self.riskyStrat: if self.isDiagonalKickoff: # check if enemy car is also doing a fast strat if carToBallDistance < 1500: for car in self.agent.game.cars[:self.agent.game.num_cars]: if car.team != self.agent.car.team: try: enemyTime = norm(car.position - self.agent.game.ball.position ) / norm(car.velocity) myTime = carToBallDistance / norm( self.agent.car.velocity) lead = enemyTime - myTime if lead < 0.09: self.riskyStrat = False break except ZeroDivisionError: pass else: for car in self.agent.game.cars[:self.agent.game.num_cars]: if car.team != self.agent.car.team: # if the enemy car jumped, fall back to safe strat immediately if norm(car.position - self.agent.game.ball.position ) < 1500 and car.position[2] > 20: self.riskyStrat = False break lead = norm( car.position - self.agent.game.ball.position) - carToBallDistance # if enemy car is too far, it also has to fall back to safe strat instead of reacting to it if lead < 1500 and ( norm(target - self.agent.car.position) < 525 and lead > 460): self.riskyStrat = False break # LOGIC TO ADJUST THE TARGET TO AIM THE BALL if self.riskyStrat: if self.isDiagonalKickoff: if self.alternateDiagonalKickoff: # aim for the wall to make a pass target += vec3( math.copysign(100, self.agent.car.position[0]), 0, 0) else: # aim straight for the goal if carToBallDistance > 1000: target += vec3(0, 190 * (self.agent.car.team * 2 - 1), 0) else: target += vec3( math.copysign(3, self.agent.car.position[0]), 140 * (self.agent.car.team * 2 - 1), 0) else: if self.isSemiDiagonalKickoff: offset = 29 else: offset = 26 target += vec3( math.copysign(offset, self.agent.car.position[0]), 0, 0) else: target += vec3(0, 90 * (self.agent.car.team * 2 - 1), 0) # force to pick up boost if self.isSemiDiagonalKickoff and abs( self.agent.car.position[1]) > 1700: self.speedFlipTarget = vec3(0, 1800 * (2 * self.agent.car.team - 1), 70) else: self.speedFlipTarget = target # always drive straight at start if speed < 550: self.controller.steer = 0 self.controller.jump = False return True else: carAngle = -atan2(self.agent.car.forward()) self.controller.steer = min( 1, max( -1, 5 * atan2( rotate2(target - self.agent.car.position, carAngle)))) if super().tick(packet): return True else: if self.riskyStrat: if self.isDiagonalKickoff: maxJumpDistance = 210 elif self.isSemiDiagonalKickoff: maxJumpDistance = 230 else: maxJumpDistance = 242 self.controller.jump = carToBallDistance < maxJumpDistance return isBallInCenter else: self.agent.reorientML.target_orientation = look_at( self.agent.game.ball.position - self.agent.car.position, vec3(0, 0, 1)) self.agent.reorientML.step(1 / self.agent.FPS) self.controller.yaw = self.agent.reorientML.controls.yaw self.controller.pitch = self.agent.reorientML.controls.pitch self.controller.roll = self.agent.reorientML.controls.roll if isBallInCenter: if norm(target - self.agent.car.position) < 525: if not self.hasUnJumped: jump = self.agent.game.ball.position[ 2] > self.agent.car.position[2] if self.controller.jump and not jump: self.hasUnJumped = True self.controller.jump = jump else: if speed < 2200: for car in self.agent.game.cars[:self.agent.game. num_cars]: if car.team != self.agent.car.team: if norm(car.position - self.agent.game.ball.position ) < 1000: if not self.hasUnJumped: self.controller.jump = False self.hasUnJumped = True elif self.controller.jump == False: self.controller.jump = True self.controller.pitch = -1 self.controller.yaw = 0 else: return False break # if no enemies have been found nearby, no need to dodge into the ball again return False return True
def step(self, dt): time_left = self.aerial.arrival_time - self.car.time if self.aerialing: to_ball = direction(self.car, self.info.ball) # freestyling if self.car.position[2] > 200: # if time_left > 0.7: # rotation = axis_to_rotation(self.car.forward() * 0.5) # self.aerial.up = dot(rotation, self.car.up()) # else: self.aerial.up = vec3(0, 0, -1) + xy(to_ball) self.aerial.target_orientation = look_at(to_ball, vec3(0, 0, -3) + to_ball) self.aerial.step(dt) self.controls = self.aerial.controls self.finished = self.aerial.finished and time_left < -0.3 else: super().step(dt) # simulate aerial from current state simulated_car = self.simulate_flight(self.car, self.aerial, self._flight_path) speed_towards_target = dot( self.car.velocity, ground_direction(self.car, self.aerial.target_position)) speed_needed = ground_distance( self.car, self.aerial.target_position) / time_left # too fast, slow down if speed_towards_target > speed_needed and angle_to( self.car, self.aerial.target_position) < 0.1: self.controls.throttle = -1 # if it ended up near the target, we could take off elif distance( simulated_car, self.aerial.target_position) < self.MAX_DISTANCE_ERROR: if angle_to(self.car, self.aerial.target_position) < 0.1 or norm( self.car.velocity) < 1000: if self.DELAY_TAKEOFF and ground_distance( self.car, self.aerial.target_position) > 1000: # extrapolate current state a small amount of time future_car = Car(self.car) time = 0.5 future_car.time += time displacement = future_car.velocity * time if norm(future_car.velocity) > 500\ else normalize(future_car.velocity) * 500 * time future_car.position += displacement # simulate aerial fot the extrapolated car again future_simulated_car = self.simulate_flight( future_car, self.aerial) # if the aerial is also successful, that means we should continue driving instead of taking off # this makes sure that we go for the most late possible aerials, which are the most effective if distance(future_simulated_car, self.aerial. target_position) > self.MAX_DISTANCE_ERROR: self.aerialing = True else: self.too_early = True else: self.aerialing = True else: # self.controls.boost = True self.controls.throttle = 1
from rlutilities.linear_algebra import vec3, axis_to_rotation, look_at from rlutilities.mechanics import AerialTurn from rlutilities.simulation import Car c = Car() c.time = 0.0 c.location = vec3(0, 0, 500) c.velocity = vec3(0, 0, 0) c.angular_velocity = vec3(0.1, -2.0, 1.2) c.rotation = axis_to_rotation(vec3(1.7, -0.5, 0.3)) c.on_ground = False turn = AerialTurn(c) turn.target = look_at(vec3(1, 0, 0), vec3(0, 0, 1)) turn.step(0.0166) print(turn.controls.roll) print(turn.controls.pitch) print(turn.controls.yaw) simulation = turn.simulate() print(simulation.time)
def tick(self, packet: GameTickPacket) -> bool: if not self.recoveryActive: return False GRAVITY = vec3(0, 0, packet.game_info.world_gravity_z) DOWN = normalize(GRAVITY) # TODO: this should be a parameter or something boostUsefullnessTreshold = 0.7 self.controller.jump = False if self.ceilingJumpState == 1: if self.agent.currentTick - self.ceilingJumpStartTick > 6: self.controller.jump = False self.ceilingJumpState = 2 return True elif self.ceilingJumpState == 2: self.controller.jump = True self.ceilingJumpState = 0 return True # If this is true, the car is considered to be recovered. if self.agent.car.on_ground and self.agent.currentTick - self.agent.lastJumpTick > 28: if self.agent.car.position[2] < 2044 - 17 * 1.5: return False else: # on ceiling, jump down if self.ceilingJumpState == 0 and self.agent.car.velocity[ 2] <= 0: self.controller.jump = True self.controller.yaw = 0 self.controller.pitch = 0 self.controller.roll = 0 self.ceilingJumpStartTick = self.agent.currentTick self.ceilingJumpState = 1 return True # Find landing point landPosition = vec3(0, 0, 0) landVelocity = vec3(0, 0, 0) landBottomDirection = vec3(0, 0, 0) airTime = self.agent.car.nextApproxCollision(landPosition, landVelocity, landBottomDirection) aimToBoost = airTime > boostUsefullnessTreshold and self.agent.car.boost > 0 # TODO: mix landing velocity and target velocity if self.forceLandDirection: landVelocity = self.forceLandDirection else: landVelocity = orthogonalize(landVelocity, landBottomDirection) downAngle = dot(landBottomDirection, DOWN) nextIsCeiling = downAngle > 0.5 nextIsGround = downAngle < -0.5 if nextIsCeiling: landVelocity = orthogonalize(self.agent.car.forward(), landBottomDirection) landVelocityUnit = normalize(landVelocity) # self.agent.draw.vector(landPosition, landVelocityUnit * 750, self.agent.draw.pink) # TODO: this time constraint is just an estimate.. :P if not nextIsCeiling\ and airTime > .65 + math.sqrt(2 * max(0, self.agent.car.position[2] - 17.01) / -packet.game_info.world_gravity_z) \ and not self.agent.car.double_jumped: # dodge to cancel momentum atan2(self.agent.car.forward()) rotate2(landVelocity, atan2(self.agent.car.forward())) direction = flatten( rotate2(landVelocity, atan2(self.agent.car.forward()))) direction = direction / max(direction[0], direction[1]) self.controller.yaw = 0 self.controller.roll = direction[1] self.controller.pitch = direction[0] self.controller.throttle = 1 self.controller.jump = True self.controller.boost = False # print("DOING AIR DASH") return True upAngle = dot(self.agent.car.up(), landBottomDirection) if aimToBoost and nextIsGround and airTime > 0.15 + 0.2 * (1 + dot( self.agent.car.forward(), landVelocityUnit)) + 0.3 * (1 + upAngle): self.agent.reorientML.target_orientation = look_at( DOWN, landVelocity) elif aimToBoost and nextIsCeiling and airTime > 0.3 + 0.35 * (1 + upAngle): self.agent.reorientML.target_orientation = look_at( DOWN * -1, landVelocity) else: WAVEDASHANGLE = 30 / 180 * math.pi MAXDODGEBEFORELANDTIME = 20.5 / 120 doWaveDash = False if not nextIsCeiling and not self.agent.car.double_jumped and airTime - MAXDODGEBEFORELANDTIME < self.agent.maxDodgeTick: waveDashLandVelocity = flatten(landVelocity) waveDashLandVelocity += normalize(waveDashLandVelocity) * 500 if norm(waveDashLandVelocity) > 2300: waveDashLandVelocity *= 2300 / norm(waveDashLandVelocity) # TODO: decide if vertical momentum is more important if norm(waveDashLandVelocity) > norm(landVelocity) + 100: doWaveDash = True if doWaveDash: landVelocity = waveDashLandVelocity landVelocityUnit = normalize(landVelocity) waveDashDirection = landVelocityUnit * math.cos( WAVEDASHANGLE) + landBottomDirection * math.sin( WAVEDASHANGLE) self.agent.reorientML.target_orientation = look_at( waveDashDirection, landBottomDirection) currentWaveDashAngle = dot(landBottomDirection, normalize(project(\ self.agent.car.up(), landBottomDirection)\ + project(self.agent.car.up(), landVelocityUnit)\ )) dodgeBeforeLandTime = 6.5 / 120\ + 14 / 120 * min(1, (1 - currentWaveDashAngle) / (1 - math.cos(WAVEDASHANGLE)))\ - 8 / 120 * (dot(DOWN, self.agent.car.up()) / 2 + 0.5) # TODO: this term should probably depend on speed towards landing surface # print(dot(landBottomDirection, self.agent.car.up()) > (1 - 1.5 * (1 - math.cos(WAVEDASHANGLE))), dot(landVelocityUnit, self.agent.car.up()) ) if airTime < dodgeBeforeLandTime\ and currentWaveDashAngle > (1 - 1.5 * (1 - math.cos(WAVEDASHANGLE)))\ and dot(landVelocityUnit, self.agent.car.up()) < 0: self.controller.yaw = 0 self.controller.roll = 0 self.controller.pitch = -1 self.controller.throttle = 1 self.controller.jump = True # print("DOING WAVEDASH") return True else: self.agent.reorientML.target_orientation = look_at( landVelocity, landBottomDirection) # TODO train my own ML network that 1. prioritizes landing wheels down over in the right direction 2. doesnt care so much about having no angular velocity, instead give it air time # TODO do a wavedash self.agent.reorientML.step(1 / self.agent.FPS) self.controller.yaw = self.agent.reorientML.controls.yaw self.controller.pitch = self.agent.reorientML.controls.pitch if upAngle < 0 and abs(self.agent.reorientML.controls.roll) < 0.1: self.controller.roll = math.copysign( 1, self.agent.reorientML.controls.roll) self.controller.throttle = 1 else: self.controller.roll = self.agent.reorientML.controls.roll forwardAngle = dot(self.agent.car.forward(), landBottomDirection) if abs(upAngle) > .4 or abs(forwardAngle) > 0.9 or airTime > 0.1: self.controller.throttle = math.copysign(1, forwardAngle) else: self.controller.throttle = 0 nextTouchDirection = dot(self.agent.car.forward(), DOWN * -1 if nextIsCeiling else DOWN) boostUsefullness = 0 if nextTouchDirection < 0.3 or self.agent.lastDodgeTick + .5 + .65 * 120 > self.agent.currentTick else nextTouchDirection * airTime # TODO: decide how urgent the car needs to be somewhere # TODO: maybe boost forward a little bit too? self.controller.boost = boostUsefullness > boostUsefullnessTreshold self.controller.handbrake = nextIsCeiling # print(f"YAW {round(self.controller.yaw, 1)}\tPITCH {round(self.controller.pitch, 1)}\tROLL {round(self.reorientML.controls.roll, 1)}\tTHROTTLE {round(self.controller.throttle, 1)}") return True