Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
 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
Пример #4
0
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
Пример #5
0
    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())
Пример #6
0
    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
Пример #7
0
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
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
    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