def step(self, dt): # update finished state even if we are not using the controls self.travel.step(dt) if self.travel.finished: # turn around to face the target direction if angle_to(self.car, self.face_target) > 0.3: self.drive.target_pos = self.face_target self.drive.target_speed = 1000 self.drive.step(dt) self.controls = self.drive.controls self.controls.handbrake = False else: self.stop.step(dt) self.controls = self.stop.controls else: self.pad = None # collect boost pads on the way (greedy algorithm, assumes first found is best) if self.car.boost < 90 and self.travel.interruptible(): to_target = ground_direction(self.car, self.travel.target) for pad in self.info.large_boost_pads + self.info.small_boost_pads: to_pad = ground_direction(self.car, pad) if (pad.is_active and distance(self.car, pad) < self.BOOST_LOOK_RADIUS and angle_between(to_target, to_pad) < self.BOOST_LOOK_ANGLE): self.pad = pad self.drive.target_pos = pad.position self.drive.target_speed = 2200 self.drive.step(dt) self.controls = self.drive.controls break # go to the actual target if self.pad is None: self.controls = self.travel.controls # don't waste boost during downtime if self.car.boost < 100 and ground_distance(self.car, self.travel.target) < 4000: self.controls.boost = False self.finished = self.travel.driving and self.car.time > self.start_time + self.DURATION
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
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, clamp(car_speed, 1500, 2300) * 1.6) # if we're too close to the target, aim for the actual target so we don't miss it if shift - self.additional_shift * 0.5 < Drive.turn_radius( clamp(car_speed, 500, 2300)) * 1.1: shift = 0 else: shift += self.additional_shift shifted_target = target - target_direction * shift time_shift = ground_distance(shifted_target, target) / clamp( car_speed, 500, 2300) * 1.2 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) if target_speed < 800 and dist_to_target > 1000 and angle_to( self.car, shifted_target) < 0.1: target_speed = 0 # if self.asap: # target_speed += 50 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