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 step(self, dt): if not self.flicking: self.carry.step(dt) self.controls = self.carry.controls self.finished = self.carry.finished car = self.car ball = self.info.ball # check if it's a good idea to flick dir_to_target = ground_direction(car, self.target) if (distance(car, ball) < 150 and ground_distance(car, ball) < 100 and dot(car.forward(), dir_to_target) > 0.7 and norm(car.velocity) > clamp( distance(car, self.target) / 3, 1000, 1700) and dot(dir_to_target, ground_direction(car, ball)) > 0.9): self.flicking = True # flick if opponent is close for opponent in self.info.get_opponents(): if (distance(opponent.position + opponent.velocity, car) < max( 300.0, norm(opponent.velocity) * 0.5) and dot(opponent.velocity, direction(opponent, self.info.ball)) > 0.5): if distance(car.position, self.info.ball.position) < 200: self.flicking = True else: self.finished = True else: self.flick.target = self.info.ball.position + self.info.ball.velocity * 0.2 self.flick.step(dt) self.controls = self.flick.controls self.finished = self.flick.finished
def configure(self, intercept: Intercept): super().configure(intercept) self.aerial.target_position = intercept.position - direction( intercept, self.target) * 100 self.aerial.up = normalize( ground_direction(intercept, self.car) + vec3(0, 0, 0.5)) self.aerial.arrival_time = intercept.time
def estimate_time(car: Car, target, dd=1) -> float: turning_radius = 1 / Drive.max_turning_curvature(norm(car.velocity) + 500) turning = angle_between(car.forward() * dd, direction( car, target)) * turning_radius / 1800 if turning < 0.5: turning = 0 dist = ground_distance(car, target) - 200 if dist < 0: return turning speed = dot(car.velocity, car.forward()) time = 0 result = None if car.boost > 0 and dd > 0: boost_time = car.boost / 33.33 result = BOOST.simulate_until_limit(speed, distance_limit=dist, time_limit=boost_time) dist -= result.distance_traveled time += result.time_passed speed = result.speed_reached if dist > 0 and speed < 1410: result = THROTTLE.simulate_until_limit(speed, distance_limit=dist) dist -= result.distance_traveled time += result.time_passed speed = result.speed_reached if result is None or not result.distance_limit_reached: time += dist / speed return time * 1.05 + turning
def render(self, draw: DrawingTool): draw.color(draw.cyan) draw.square(self.target_pos, 50) target_direction = direction(self.car.position, self.target_pos) draw.triangle(self.car.position + target_direction * 200, target_direction, up=self.car.up())
def find_second_touch(self): self.info.predict_ball(time_limit=3.0) intercept = AirToAirIntercept(self.car, self.info.ball_predictions) self.aerial.target = intercept.position - direction(intercept, self.aerial_strike.target) * 80 self.aerial.up = vec3(0, 0, -1) self.aerial.arrival_time = intercept.time if not intercept.is_viable: self.finished = True
def estimate_time(car: Car, target, speed, dd=1) -> float: travel = distance(car, target) / speed turning = angle_between(car.forward() * dd, direction( car, target)) / math.pi * 2 if turning < 1: turning **= 2 acceleration = (speed * dd - dot(car.velocity, car.forward())) / 2100 * 0.2 * dd / max( car.boost / 20, 1) return travel + acceleration + turning * 0.7
def step(self, 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 find_second_touch(self): self.info.predict_ball(duration=4.0) for i in range(0, len(self.info.ball_predictions), 5): ball = self.info.ball_predictions[i] if ball.position[2] < 500: break self.aerial.target = ball.position - direction( ball, self.aerial_strike.target) * 80 self.aerial.arrival_time = ball.time final_car = AerialStrike.simulate_flight(self.car, self.aerial, self._flight_path) if distance(final_car, self.aerial.target) < 50: return self.finished = True
def step(self, dt): car = self.car target = ground(self.target) car_speed = norm(car.velocity) time_left = (ground_distance(car, target) - self.finish_distance) / max(car_speed + 500, 1400) forward_speed = dot(car.forward(), car.velocity) if self.driving and car.on_ground: self.action.target_pos = target self._time_on_ground += dt # check if it's a good idea to dodge, wavedash or halfflip if ( self._time_on_ground > 0.2 and car.position[2] < 200 and car_speed < 2000 and angle_to(car, target, backwards=forward_speed < 0) < 0.1 and car.gravity[2] < -500 # don't dodge in low gravity ): # if going forward, use a dodge or a wavedash if forward_speed > 0: use_boost_instead = self.waste_boost and car.boost > 20 if car_speed > 1200 and not use_boost_instead: if time_left > self.DODGE_DURATION: dodge = Dodge(car) dodge.duration = 0.07 dodge.direction = vec2(direction(car, target)) self.action = dodge self.driving = False elif time_left > self.WAVEDASH_DURATION: wavedash = Wavedash(car) wavedash.direction = vec2(direction(car, target)) self.action = wavedash self.driving = False # if going backwards, use a halfflip elif time_left > self.HALFFLIP_DURATION and car_speed > 800: self.action = HalfFlip(car, self.waste_boost and time_left > 3) self.driving = False self.action.step(dt) self.controls = self.action.controls # make sure we're not boosting airborne if self.driving and not car.on_ground: self.controls.boost = False # make sure we're not stuck turtling if not car.on_ground: self.controls.throttle = 1 # a dodge/wavedash/halfflip has finished if self.action.finished and not self.driving: self.driving = True self._time_on_ground = 0 self.action = self.drive self.drive.backwards = False if ground_distance(car, target) < self.finish_distance and self.driving: self.finished = True
def 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