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): target = self.target car = self.car if self.target_direction is not None: car_speed = norm(car.velocity) target_direction = normalize(self.target_direction) # in order to arrive in a direction, we need to shift the target in the opposite direction # the magnitude of the shift is based on how far are we from the target shift = clamp( ground_distance(car.position, target) * self.lerp_t, 0, car_speed * 1.5) # if we're too close to the target, aim for the actual target so we don't miss it if shift - self.additional_shift < Drive.turn_radius( clamp(car_speed, 1400, 2000) * 1.1): shift = 0 else: shift += self.additional_shift shifted_target = target - target_direction * shift time_shift = ground_distance(shifted_target, target) * 0.7 / clamp( car_speed, 500, 2300) shifted_arrival_time = self.arrival_time - time_shift else: shifted_target = target shifted_arrival_time = self.arrival_time self.drive.target_pos = shifted_target self.travel.target = shifted_target dist_to_target = ground_distance(car.position, shifted_target) time_left = nonzero(shifted_arrival_time - car.time) target_speed = clamp(dist_to_target / time_left, 0, 2300) self.drive.target_speed = target_speed self.drive.backwards = self.backwards # dodges and wavedashes can mess up correctly arriving, so we use them only if we really need them if ((self.allow_dodges_and_wavedashes and norm(car.velocity) < target_speed - 600 and car.boost < 20 and not self.backwards) or not self.travel.driving # a dodge/wavedash is in progress ): self.action = self.travel else: self.action = self.drive self.action.step(dt) self.controls = self.action.controls self.finished = self.car.time >= self.arrival_time
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 circle(self, pos: vec3, radius: float): segments = int(clamp(radius / 20, 10, 50)) step = 2 * math.pi / segments points = [] for i in range(segments): angle = step * i points.append(pos + vec3(math.cos(angle), math.sin(angle), 0) * radius) self.closed_polyline(points)
def arc(self, pos: vec3, radius: float, start_angle: float, end_angle: float): segments = int( clamp(radius * abs(start_angle - end_angle) / 20, 10, 50)) step = (end_angle - start_angle) / segments points = [] for i in range(segments + 1): angle = start_angle + step * i points.append( pos + vec3(math.cos(angle) * radius, math.sin(angle) * radius, 0)) self.polyline(points)
def configure(self, intercept: Intercept): super().configure(intercept) ball = intercept.ball target_direction = ground_direction(ball, self.target) hit_dir = ground_direction(ball.velocity, target_direction * 4000) self.arrive.target = intercept.ground_pos - hit_dir * 100 self.arrive.target_direction = hit_dir additional_jump = clamp( (ball.position[2] - 92) / 500, 0, 1.5) * self.jump_time_multiplier self.dodge.jump.duration = 0.05 + additional_jump self.dodge.target = intercept.ball.position self.arrive.additional_shift = additional_jump * 500
def turn_radius(speed: float) -> float: spd = clamp(speed, 0, 2300) return 156 + 0.1 * spd + 0.000069 * spd**2 + 0.000000164 * spd**3 + -5.62E-11 * spd**4
def get_jump_duration(self, ball_height: float) -> float: return 0.05 + clamp( (ball_height - 92) / 500, 0, 1.5) * self.jump_time_multiplier
def estimate_max_car_speed(car: Car): return clamp(max(norm(car.velocity), 1300) + car.boost * 100, 1600, 2300)