예제 #1
0
def find_any_jump_shot(agent, cap_=3):
    struct = agent.predictions['ball_struct']

    if struct is None:
        return

    i = 5
    while i < struct.num_slices:
        intercept_time = struct.slices[i].game_seconds
        time_remaining = intercept_time - agent.time

        if time_remaining <= 0:
            return

        ball_location = Vector(struct.slices[i].physics.location.x,
                               struct.slices[i].physics.location.y,
                               struct.slices[i].physics.location.z)

        if abs(ball_location.y) > 5212:
            break

        ball_velocity = Vector(
            struct.slices[i].physics.velocity.x,
            struct.slices[i].physics.velocity.y,
            struct.slices[i].physics.velocity.z).magnitude()

        i += 15 - cap(int(ball_velocity // 150), 0, 13)

        if ball_location.z > 350:
            continue

        car_to_ball = ball_location - agent.me.location
        direction, distance = car_to_ball.normalize(True)

        forward_angle = direction.angle(agent.me.forward)
        backward_angle = math.pi - forward_angle

        forward_time = time_remaining - (forward_angle * 0.318)
        backward_time = time_remaining - (backward_angle * 0.418)

        forward_flag = forward_time > 0 and (
            distance * 1.05 /
            forward_time) < (2275 if agent.me.boost > distance / 100 else 1400)
        backward_flag = distance < 1500 and backward_time > 0 and (
            distance * 1.05 / backward_time) < 1200

        # our current direction IS our best shot vector, as we just want to get to the ball as fast as possible
        if (forward_flag or backward_flag) and is_fast_shot(
                agent.me.location, ball_location, intercept_time, agent.time,
                cap_):
            slope = find_slope(direction, car_to_ball)
            if forward_flag and ball_location.z <= 275 and slope > 0:
                return jump_shot(ball_location, intercept_time, direction)
            elif backward_flag and ball_location.z <= 250 and slope > 1.5:
                return jump_shot(ball_location, intercept_time, direction, -1)
예제 #2
0
def find_any_jump_shot(agent, cap_=3):
    slices = get_slices(agent, cap_)

    if slices is None:
        return

    me = (agent.me.location.tuple(), agent.me.forward.tuple(),
          agent.me.boost if agent.boost_amount != 'unlimited' else 1000000,
          agent.me.local_velocity().x)

    game_info = (agent.best_shot_value, agent.boost_accel)

    for ball_slice in slices:
        intercept_time = ball_slice.game_seconds
        time_remaining = intercept_time - agent.time

        if time_remaining <= 0:
            continue

        ball_location = (ball_slice.physics.location.x,
                         ball_slice.physics.location.y,
                         ball_slice.physics.location.z)

        if abs(ball_location[1]) > 5212.75:
            return

        shot = virxrlcu.parse_slice_for_jump_shot(time_remaining - 0.1,
                                                  *game_info, ball_location,
                                                  *me)

        if shot['found'] == 1:
            return jump_shot(intercept_time, Vector(*shot['best_shot_vector']))
예제 #3
0
def find_jump_shot(agent, target, weight=None, cap_=6):
    # Takes a tuple of (left,right) target pairs and finds routines that could hit the ball between those target pairs
    # Only meant for routines that require a defined intercept time/place in the future
    # Here we get the slices that need to be searched - by defining a cap or a weight, we can reduce the number of slices and improve search times
    slices = get_slices(agent, cap_, weight=weight)

    if slices is None:
        return

    # Assemble data in a form that can be passed to C
    target = (target[0].tuple(), target[1].tuple())

    me = (agent.me.location.tuple(), agent.me.forward.tuple(),
          agent.me.boost if agent.boost_amount != 'unlimited' else 100000,
          agent.me.local_velocity().x)

    game_info = (agent.best_shot_value, agent.boost_accel)

    # Loop through the slices
    for ball_slice in slices:
        # Gather some data about the slice
        intercept_time = ball_slice.game_seconds
        time_remaining = intercept_time - agent.time

        if time_remaining <= 0:
            continue

        ball_location = (ball_slice.physics.location.x,
                         ball_slice.physics.location.y,
                         ball_slice.physics.location.z)

        if abs(ball_location[1]) > 5212.75:
            return  # abandon search if ball is scored at/after this point

        # Check if we can make a shot at this slice
        # This operation is very expensive, so we use a custom C function to improve run time
        shot = virxrlcu.parse_slice_for_jump_shot_with_target(
            time_remaining - 0.1, *game_info, ball_location, *me, *target)

        # If we found a viable shot, pass the data into the shot routine and return the shot
        if shot['found'] == 1:
            return jump_shot(intercept_time, Vector(*shot['best_shot_vector']))
예제 #4
0
def find_any_shot(agent,
                  cap_=3,
                  can_aerial=True,
                  can_double_jump=True,
                  can_jump=True):
    if not can_aerial and not can_double_jump and not can_jump:
        agent.print("WARNING: All shots were disabled when find_shot was ran")
        return

    slices = get_slices(agent, cap_)

    if slices is None:
        return

    me = (agent.me.location.tuple(), agent.me.forward.tuple(),
          agent.me.boost if agent.boost_amount != 'unlimited' else 100000,
          agent.me.local_velocity().x)

    game_info = (agent.best_shot_value, agent.boost_accel)

    if can_aerial:
        me_a = (me[0], agent.me.velocity.tuple(), agent.me.up.tuple(), me[1],
                1 if agent.me.airborne else -1, me[2])

        gravity = agent.gravity.tuple()

        max_aerial_height = 643 if len(agent.friends) == 0 and len(
            agent.foes) == 1 else math.inf
        min_aerial_height = 551 if max_aerial_height > 643 and agent.me.location.z >= 2044 - agent.me.hitbox.height * 1.1 else (
            0 if agent.boost_amount == 'unlimited' else 450)

    for ball_slice in slices:
        intercept_time = ball_slice.game_seconds
        time_remaining = intercept_time - agent.time

        if time_remaining <= 0:
            return

        ball_location = (ball_slice.physics.location.x,
                         ball_slice.physics.location.y,
                         ball_slice.physics.location.z)

        if abs(ball_location[1]) > 5212.75:
            return

        if can_jump:
            shot = virxrlcu.parse_slice_for_jump_shot(time_remaining - 0.1,
                                                      *game_info,
                                                      ball_location, *me)

            if shot['found'] == 1:
                return jump_shot(intercept_time,
                                 Vector(*shot['best_shot_vector']))

        if can_double_jump and time_remaining >= 0.5:
            shot = virxrlcu.parse_slice_for_double_jump(
                time_remaining - 0.3, *game_info, ball_location, *me)

            if shot['found'] == 1:
                return double_jump(intercept_time,
                                   Vector(*shot['best_shot_vector']))

        if can_aerial and not (min_aerial_height > ball_location[2]
                               or ball_location[2] > max_aerial_height):
            shot = virxrlcu.parse_slice_for_aerial_shot(
                time_remaining, *game_info, gravity, ball_location, me_a)

            if shot['found'] == 1:
                return Aerial(intercept_time,
                              Vector(*shot['best_shot_vector']), shot['fast'])
예제 #5
0
def find_hits(agent, targets, cap_=6):
    # find_hits takes a dict of (left,right) target pairs and finds routines that could hit the ball between those target pairs
    # find_hits is only meant for routines that require a defined intercept time/place in the future
    # find_hits should not be called more than once in a given tick, as it has the potential to use an entire tick to calculate
    hits = {name: [] for name in targets}
    struct = agent.predictions['ball_struct']

    if struct is None:
        return hits

    max_aerial_height = 400
    max_jump_hit_height = 200
    min_aerial_height = 150

    if (len(agent.foes) > 1
            and len(agent.friends) == 0) or len(agent.friends) > 2:
        max_jump_hit_height = 300
        max_aerial_height = 500

    # Begin looking at slices 0.2s into the future
    i = 10
    while i < struct.num_slices:
        # Gather some data about the slice
        intercept_time = struct.slices[i].game_seconds
        time_remaining = intercept_time - agent.time
        if time_remaining > 0:
            ball_location = Vector(struct.slices[i].physics.location.x,
                                   struct.slices[i].physics.location.y,
                                   struct.slices[i].physics.location.z)

            if abs(ball_location.y) > 5200:
                break  # abandon search if ball is scored at/after this point

            ball_velocity = Vector(
                struct.slices[i].physics.velocity.x,
                struct.slices[i].physics.velocity.y,
                struct.slices[i].physics.velocity.z).magnitude()

            # determine the next slice we will look at, based on ball velocity (slower ball needs fewer slices)
            i += 15 - cap(int(ball_velocity // 150), 0, 13)

            # If the ball is above what this function can handle, don't bother with any further processing and skip to the next slice
            if ball_location.z > max_aerial_height:
                continue

            car_to_ball = ball_location - agent.me.location
            # Adding a True to a vector's normalize will have it also return the magnitude of the vector
            direction, distance = car_to_ball.normalize(True)

            # How far the car must turn in order to face the ball, for forward and reverse
            forward_angle = direction.angle(agent.me.forward)
            backward_angle = math.pi - forward_angle

            # Accounting for the average time it takes to turn and face the ball
            # Backward is slightly longer as typically the car is moving forward and takes time to slow down
            forward_time = time_remaining - (forward_angle * 0.318)
            backward_time = time_remaining - (backward_angle * 0.418)

            # If the car only had to drive in a straight line, we ensure it has enough time to reach the ball (a few assumptions are made)
            forward_flag = forward_time > 0 and (
                distance * 1.05 / forward_time) < (
                    2290 if agent.me.boost > distance / 100 else 1400)
            backward_flag = distance < 1500 and backward_time > 0 and (
                distance * 1.05 / backward_time) < 1200

            # Provided everything checks out, we begin to look at the target pairs
            if forward_flag or backward_flag:
                for pair in targets:
                    # First we correct the target coordinates to account for the ball's radius
                    # If swapped is True, the shot isn't possible because the ball wouldn't fit between the targets
                    left, right, swapped = post_correction(
                        ball_location, targets[pair][0], targets[pair][1])
                    if not swapped:
                        # Now we find the easiest direction to hit the ball in order to land it between the target points
                        left_vector = (left - ball_location).normalize()
                        right_vector = (right - ball_location).normalize()
                        best_shot_vector = direction.clamp(
                            left_vector, right_vector)

                        # Check to make sure our approach is inside the field
                        # Check if our shot is fast enough. This is equal to 500uu's per 1/2 second, for a max time of `cap` (defaut 6) seconds.
                        if in_field(ball_location - (200 * best_shot_vector),
                                    1) and is_fast_shot(
                                        agent.me.location, ball_location,
                                        intercept_time, agent.time, cap_):
                            # The slope represents how close the car is to the chosen vector, higher = better
                            # A slope of 1.0 would mean the car is 45 degrees off
                            slope = find_slope(best_shot_vector, car_to_ball)
                            if forward_flag:
                                if ball_location.z > min_aerial_height and ball_location.z <= max_aerial_height and slope > 1.0 and (
                                        ball_location.z -
                                        250) * 0.14 > agent.me.boost:
                                    hits[pair].append(
                                        aerial_shot(ball_location,
                                                    intercept_time,
                                                    best_shot_vector, slope))
                                    return hits
                                if ball_location.z <= max_jump_hit_height and slope > 0:
                                    hits[pair].append(
                                        jump_shot(ball_location,
                                                  intercept_time,
                                                  best_shot_vector, slope))
                                    return hits
                            elif backward_flag and ball_location.z <= 280 and slope > 0.25:
                                hits[pair].append(
                                    jump_shot(ball_location, intercept_time,
                                              best_shot_vector, slope, -1))
                                return hits
        else:
            return hits
    return hits