Пример #1
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
Пример #2
0
 def simulate(self):
     ball_prediction = self.get_ball_prediction_struct()
     duration_estimate = math.floor(
         get_time_at_height(self.game.ball.location[2], 0.2) * 10) / 10
     for i in range(6):
         car = Car(self.game.my_car)
         ball = Ball(self.game.ball)
         batmobile = obb()
         batmobile.half_width = vec3(64.4098892211914, 42.335182189941406,
                                     14.697200775146484)
         batmobile.center = car.location + dot(car.rotation,
                                               vec3(9.01, 0, 12.09))
         batmobile.orientation = car.rotation
         dodge = Dodge(car)
         dodge.duration = duration_estimate + i / 60
         dodge.target = ball.location
         for j in range(round(60 * dodge.duration)):
             dodge.target = ball.location
             dodge.step(1 / 60)
             car.step(dodge.controls, 1 / 60)
             prediction_slice = ball_prediction.slices[j]
             physics = prediction_slice.physics
             ball_location = vec3(physics.location.x, physics.location.y,
                                  physics.location.z)
             dodge.target = ball_location
             batmobile.center = car.location + dot(car.rotation,
                                                   vec3(9.01, 0, 12.09))
             batmobile.orientation = car.rotation
             if intersect(sphere(ball_location, 93.15), batmobile) and abs(
                     ball_location[2] - car.location[2]
             ) < 25 and car.location[2] < ball_location[2]:
                 return True, j / 60, ball_location
     return False, None, None
Пример #3
0
    def __init__(self, car: Car, ball_predictions, predicate: callable = None):
        self.ball: Ball = None
        self.is_viable = True

        #find the first reachable ball slice that also meets the predicate
        test_car = Car(car)
        test_aerial = Aerial(car)
        
        for ball in ball_predictions:
            test_aerial.target = ball.position
            test_aerial.arrival_time = ball.time

            # fake our car state :D
            dir_to_target = ground_direction(test_car.position, test_aerial.target)
            test_car.velocity = dir_to_target * max(norm(test_car.velocity), 1200)
            test_car.orientation = look_at(dir_to_target, vec3(0,0,1))

            if test_aerial.is_viable() and (predicate is None or predicate(car, ball)):
                self.ball = ball
                break

        #if no slice is found, use the last one
        if self.ball is None:
            self.ball = ball_predictions[-1]
            self.is_viable = False

        self.time = self.ball.time
        self.ground_pos = ground(self.ball.position)
        self.position = self.ball.position
Пример #4
0
    def simulate_landing(self):
        dummy = Car(self.car)
        self.trajectory = [vec3(dummy.position)]
        self.landing = False
        collision_normal: Optional[vec3] = None

        dt = 1 / 60
        simulation_duration = 0.8
        for i in range(int(simulation_duration / dt)):
            dummy.step(Input(), dt)
            self.trajectory.append(vec3(dummy.position))

            collision_sphere = sphere(dummy.position, 50)
            collision_ray = Field.collide(collision_sphere)
            collision_normal = collision_ray.direction

            if (norm(collision_normal) > 0.0
                    or dummy.position[2] < 0) and i > 20:
                self.landing = True
                self.landing_pos = dummy.position
                break

        if self.landing:
            u = collision_normal
            f = normalize(dummy.velocity - dot(dummy.velocity, u) * u)
            l = normalize(cross(u, f))
            self.aerial_turn.target = mat3(f[0], l[0], u[0], f[1], l[1], u[1],
                                           f[2], l[2], u[2])
        else:
            target_direction = normalize(
                normalize(self.car.velocity) - vec3(0, 0, 3))
            self.aerial_turn.target = look_at(target_direction, vec3(0, 0, 1))
Пример #5
0
 def car_trajectory(self, car: Car, end_time: float, dt: float = 1 / 10):
     steps = []
     test_car = Car(car)
     while test_car.time < end_time:
         dt = min(dt, end_time - test_car.time)
         test_car.step(Input(), dt)
         test_car.time += dt
         steps.append(vec3(test_car.position))
     self.polyline(steps)
Пример #6
0
def estimate_time(car: Car, target, speed, dd=1) -> float:
    dist = distance(car, target)
    if dist < 100:
        return 0
    travel = dist / 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 dodge_simulation(end_condition=None,
                     car=None,
                     hitbox_class=None,
                     dodge=None,
                     ball=None,
                     game_info=None,
                     boost=True):
    '''
    Simulates an RLU dodge until the dodge ends, or one of pass_condition or fail_condtion are met.
    pass_condition means that the dodge does what we wanted.  Returns True and the RLU car state at the end
    fail_condition returns (False, None), meaning the dodge doesn't achieve the desired result.
    '''

    #Copy everything we need and set constants
    time = 0
    dt = 1 / 60
    car_copy = RLU_Car(car)
    dodge_copy = RLU_Dodge(car_copy)
    if dodge.target != None:
        dodge_copy.target = dodge.target
    if dodge.direction != None:
        dodge_copy.direction = dodge.direction
    if dodge.preorientation != None:
        dodge_copy.preorientation = dodge.preorientation
    if dodge.duration != None:
        dodge_copy.duration = dodge.duration
    else:
        dodge_copy.duration = 0
    #Make sure there's time between the jump and the dodge so that we don't just keep holding jump
    if dodge.delay != None:
        dodge_copy.delay = dodge.delay
    else:
        dodge_copy.delay = max(dodge_copy.duration + 2 * dt, 0.05)

    #Adjust for non-octane hitboxes
    box = update_hitbox(car_copy, hitbox_class)

    #Loop until we hit end_condition or the dodge is over.
    while not end_condition(time, box, ball, game_info.team_sign):

        #Update simulations and adjust hitbox again
        time += dt
        dodge_copy.step(dt)
        controls = dodge_copy.controls
        if boost:
            controls.boost = 1
        car_copy.step(controls, dt)
        box = update_hitbox(car_copy, hitbox_class)

        if dodge_copy.finished:
            #If the dodge never triggers condition, give up and move on
            #TODO: give up sooner to save computation time
            return Simulation()

    return Simulation(ball_contact=True, car=car_copy, box=box, time=time)
def moving_ball_dodge_contact(game_info):
    '''
    Returns dodge duration and delay so the car can reach contact_height
    '''

    ball = game_info.ball
    contact_height = ball.pos.z - 20
    hitbox_class = game_info.me.hitbox_class
    car_copy = RLU_Car(game_info.utils_game.my_car)
    turn = RLU_AerialTurn(car_copy)
    turn.target = roll_away_from_target(ball.pos, pi / 4, game_info)
    box = update_hitbox(car_copy, hitbox_class)
    time = 0
    dt = 1 / 60
    ball_contact = has_ball_contact(time, box, ball, game_info.team_sign)
    closest_point = ball_contact[1]

    while closest_point[2] < contact_height and not ball_contact[0]:
        time += dt
        ball = game_info.ball_prediction.state_at_time(game_info.game_time +
                                                       time)

        turn.step(dt)
        contact_height = ball.pos.z - 30
        controls = turn.controls
        if time <= 0.20:
            controls.jump = 1
        controls.boost = 1

        car_copy.step(controls, dt)
        box = update_hitbox(car_copy, hitbox_class)

        ball_contact = has_ball_contact(time, box, ball, game_info.team_sign)
        closest_point = ball_contact[1]
        if time >= 1.45:  #Max dodge time
            return None, None, Simulation()

    if not ball_contact[0]:
        return None, None, Simulation()

    if time < 0.2:
        duration = time
        delay = duration + 2 * dt
    else:
        duration = 0.2
        delay = time

    delay -= 0.05  #Window to dodge just before ball contact

    return duration, delay, Simulation(ball_contact=True,
                                       car=car_copy,
                                       hitbox=box,
                                       time=time)
Пример #9
0
    def toPoint(car: Car, target: vec3):

        direction = normalize(target - car.position)

        turnAngleAmount = math.acos(
            max(-1, min(1, dot(car.forward(), direction))))

        rotateToZeroAngle = -atan2(direction)

        towardsZeroVector = rotate2(car.forward(), rotateToZeroAngle)
        turnDirection = math.copysign(1, -towardsZeroVector[1])

        return PID.fromAngle(car, turnAngleAmount * turnDirection)
Пример #10
0
 def best_intercept(self, cars: List[Car]) -> Intercept:
     if not cars:
         return Intercept(Car(), self.info.ball_predictions)
     intercepts = [
         Intercept(car, self.info.ball_predictions) for car in cars
     ]
     return min(intercepts, key=lambda intercept: intercept.time)
def stationary_ball_dodge_contact(game_info, contact_height):
    '''
    Returns dodge duration and delay so the car can reach contact_height
    '''

    ball = game_info.ball
    hitbox_class = game_info.me.hitbox_class
    car_copy = RLU_Car(game_info.utils_game.my_car)
    turn = RLU_AerialTurn(car_copy)
    turn.target = roll_away_from_target(ball.pos, pi / 4, game_info)
    box = update_hitbox(car_copy, hitbox_class)
    time = 0
    dt = 1 / 60
    ball_contact = has_ball_contact(time, box, ball, game_info.team_sign)
    intended_contact_point = ball_contact[1]

    while intended_contact_point[2] < contact_height and not ball_contact[0]:
        time += dt
        turn.step(dt)
        controls = turn.controls
        if time <= 0.20:
            controls.jump = 1
        controls.boost = 1

        car_copy.step(controls, dt)
        box = update_hitbox(car_copy, hitbox_class)
        ball_contact = has_ball_contact(time, box, ball, game_info.team_sign)
        intended_contact_point = ball_contact[1]
        if time >= 1.45:  #Max dodge time
            return None, None, Simulation()

    if not ball_contact[0]:
        return None, None, Simulation()
    if time < 0.2:
        duration = time
        delay = duration + 2 * dt
    else:
        duration = 0.2
        delay = time

    delay -= 0.05  #How long before we hit the ball is acceptable to dodge

    return duration, delay, Simulation(ball_contact=True,
                                       car=car_copy,
                                       hitbox=box,
                                       time=time)
Пример #12
0
    def toPointReverse(car: Car, target: vec3):

        direction = normalize(target - car.position)

        turnAngleAmount = math.acos(
            max(-1, min(1, -dot(car.forward(), direction))))

        rotateToZeroAngle = -atan2(direction)

        towardsZeroVector = rotate2(car.forward(), rotateToZeroAngle + math.pi)
        turnDirection = math.copysign(1, towardsZeroVector[1])

        ANGLETERM = 3.5
        ANGULARTERM = -0.3
        angleP = turnDirection * min(2, ANGLETERM * turnAngleAmount)
        angleD = ANGULARTERM * car.angular_velocity[2]

        return min(1, max(-1, angleP + angleD))
Пример #13
0
    def step(self, dt):
        if self.aerialing:
            self.aerial.target_orientation = look_at(
                direction(self.car, self.target), vec3(0, 0, -1))
            self.aerial.step(dt)
            self.controls = self.aerial.controls
            self.finished = self.aerial.finished

        else:
            super().step(dt)

            # simulate aerial from current state
            simulated_car = self.simulate_flight(self.car)

            # if the car ended up too far, we're too fast and we need to slow down
            if ground_distance(self.car,
                               self.aerial.target) + 100 < ground_distance(
                                   self.car, simulated_car):
                # self.controls.throttle = -1
                pass

            # if it ended up near the target, we could take off
            elif distance(simulated_car,
                          self.aerial.target) < self.MAX_DISTANCE_ERROR:
                if angle_to(self.car, self.aerial.target) < 0.1 or norm(
                        self.car.velocity) < 1000:

                    if self.DELAY_TAKEOFF:
                        # extrapolate current state a small amount of time
                        future_car = Car(self.car)
                        time = 0.2
                        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, write_to_flight_path=False)

                        # 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) > 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
Пример #14
0
    def simulate_flight(car: Car, aerial: Aerial, flight_path: List[vec3] = None) -> Car:
        test_car = Car(car)
        test_aerial = Aerial(test_car)
        test_aerial.target = aerial.target
        test_aerial.arrival_time = aerial.arrival_time
        test_aerial.angle_threshold = aerial.angle_threshold
        test_aerial.up = aerial.up
        test_aerial.single_jump = aerial.single_jump

        if flight_path: flight_path.clear()

        while not test_aerial.finished:
            test_aerial.step(1 / 120)
            test_car.boost = 100  # TODO: fix boost depletion in RLU car sim
            test_car.step(test_aerial.controls, 1 / 120)

            if flight_path:
                flight_path.append(vec3(test_car.position))

        return test_car
Пример #15
0
    def simulate_flight(self, car: Car, write_to_flight_path=True) -> Car:
        test_car = Car(car)
        test_aerial = Aerial(test_car)
        test_aerial.target = self.aerial.target
        test_aerial.arrival_time = self.aerial.arrival_time
        test_aerial.angle_threshold = self.aerial.angle_threshold
        test_aerial.up = self.aerial.up
        test_aerial.single_jump = self.aerial.single_jump

        if write_to_flight_path:
            self._flight_path.clear()

        while not test_aerial.finished:
            test_aerial.step(1 / 120)
            test_car.boost = 100  # TODO: fix boost depletion in RLU car sim
            test_car.step(test_aerial.controls, 1 / 120)

            if write_to_flight_path:
                self._flight_path.append(vec3(test_car.position))

        return test_car
Пример #16
0
    def align(car: Car, target: vec3, direction: vec3):

        turnAngleAmount = math.acos(dot(car.forward(), direction))
        rotateToZeroAngle = -atan2(direction)
        posOffset = rotate2(target - car.position, rotateToZeroAngle)

        towardsZeroVector = rotate2(car.forward(), rotateToZeroAngle)
        turnDirection = math.copysign(1, -towardsZeroVector[1])

        turnRadius = 1 / RLUDrive.max_turning_curvature(norm(car.velocity))

        ANGLETERM = 10
        ANGULARTERM = -0.3
        CORRECTIONTERM = 1 / 40
        angleP = turnDirection * min(2, ANGLETERM * turnAngleAmount)
        angleD = ANGULARTERM * car.angular_velocity[2]

        finalOffset = posOffset[1] + turnDirection * turnRadius / .85 * (
            1 - math.cos(turnAngleAmount))
        offsetCorrection = CORRECTIONTERM * finalOffset

        return min(1, max(-1, angleP + angleD + offsetCorrection))
Пример #17
0
    def reset_gamestate(self):
        print('> reset_gamestate()')

        # Initialize inputs
        self.reset_for_ground_shots()
        t = self.target
        b = Ball(self.game.ball)
        c = Car(self.game.cars[self.index])
        b.location = to_vec3(self.initial_ball_location)
        b.velocity = to_vec3(self.initial_ball_velocity)
        c.location = to_vec3(self.initial_car_location)
        c.velocity = to_vec3(self.initial_car_velocity)

        # Point car at ball
        c.rotation = look_at(
            vec3(b.location[0] - c.location[0], b.location[1] - c.location[1],
                 0), vec3(0, 0, 1))
        rotator = rotation_to_euler(c.rotation)

        # Reset
        self.aerial = None
        self.dodge = None
        self.rotation_input = None
        self.timer = 0.0

        # Set gamestate
        car_state = CarState(boost_amount=100,
                             physics=Physics(
                                 location=self.initial_car_location,
                                 velocity=self.initial_car_velocity,
                                 rotation=rotator,
                                 angular_velocity=Vector3(0, 0, 0)))
        ball_state = BallState(
            Physics(location=self.initial_ball_location,
                    velocity=self.initial_ball_velocity,
                    rotation=Rotator(0, 0, 0),
                    angular_velocity=Vector3(0, 0, 0)))
        game_state = GameState(ball=ball_state, cars={self.index: car_state})
        self.set_game_state(game_state)
Пример #18
0
    def simulate(self, bot) -> vec3:
        # print('simulate intercept')

        # Init vars
        c = Car(bot.game.my_car)
        b = Ball(bot.game.ball)
        t = vec3(bot.target)
        intercept = self.location
        dt = 1.0 / 60.0
        hit = False
        min_error = None

        # Drive towards intercept (moving in direction of c.forward())
        c.rotation = look_at(intercept, c.up())
        direction = normalize(intercept - c.location)  #c.forward()
        advance_distance = norm(intercept - c.location) - c.hitbox(
        ).half_width[0] - b.collision_radius
        translation = direction * advance_distance
        sim_start_state: ThrottleFrame = BoostAnalysis().travel_distance(
            advance_distance, norm(c.velocity))
        c.velocity = direction * sim_start_state.speed
        c.location += translation
        c.time += sim_start_state.time
        bot.ball_predictions = [vec3(b.location)]

        while b.time < c.time:
            b.step(dt)
            bot.ball_predictions.append(vec3(b.location))

        # print(c.time, b.time)
        # print(c.location, b.location)

        # Simulate the collision and resulting
        for i in range(60 * 3):
            c.location += c.velocity * dt
            b.step(dt, c)

            # Check if we hit the ball yet
            if norm(b.location - c.location) < (c.hitbox().half_width[0] +
                                                b.collision_radius) * 1.05:
                hit = True
                # print('hit')

            # Measure dist from target
            error = t - b.location
            if hit and (min_error == None or norm(error) < norm(min_error)):
                min_error = error

            # Record trajectory
            bot.ball_predictions.append(vec3(b.location))

        if not hit: return None
        return min_error
Пример #19
0
    def best_intercept(self, cars, max_height=9999) -> Intercept:
        best_intercept = None
        best_car = None

        for car in cars:
            intercept = Intercept(car, self.info.ball_predictions, lambda car, ball: ball.position[2] < max_height)
            if best_intercept is None or intercept.time <= best_intercept.time:
                best_intercept = intercept
                best_car = car

        if best_intercept is None:
            best_car = Car()
            best_intercept = Intercept(best_car, [])

        return best_intercept, best_car
Пример #20
0
    def get_controls(self, car_state: CarState, car: Car):
        controls = SimpleControllerState()
        target_Vec3 = Vec3(self.location[0], self.location[1],
                           self.location[2])

        if angle_between(self.location - to_vec3(car_state.physics.location),
                         car.forward()) > pi / 2:
            controls.boost = False
            controls.handbrake = True
        elif angle_between(self.location - to_vec3(car_state.physics.location),
                           car.forward()) > pi / 4:
            controls.boost = False
            controls.handbrake = False
        else:
            controls.boost = self.boost
            controls.handbrake = False

        # Be smart about not using boost at max speed
        # if Vec3(car.physics.velocity).length() > self.boost_analysis.frames[-1].speed - 10:
        #     controls.boost = False

        controls.steer = steer_toward_target(car_state, target_Vec3)
        controls.throttle = 1
        return controls
Пример #21
0
    def __init__(self, car: Car, use_boost=False):
        self.car = car
        self.use_boost = use_boost
        self.controls = Input()

        self.dodge = Dodge(car)
        self.dodge.duration = 0.12
        self.dodge.direction = vec2(car.forward() * (-1))

        self.s = 0.95 * sgn(
            dot(self.car.angular_velocity, self.car.up()) + 0.01)

        self.timer = 0.0

        self.finished = False
Пример #22
0
    def __init__(self, physics: SimPhysics):
        self.physics: SimPhysics = physics
        self.boost = 100  # Right now always a 100

        self.renderer = None
        self.rlu_car = RLUCar()
        self.is_rlu_updated = False

        self.last_base = Vec3(0, 0, -1000)
        self.last_normal = Vec3(0, 0, 1)
        self.last_was_jump = False
        self.airtime = 0

        self.count = 0
        self.index = 0
        self.locations = []
        self.up = []
        self.forward = []
Пример #23
0
    def __init__(self, car: Car, target: vec3 = vec3(0, 0, 0), waste_boost=False):
        super().__init__(car)

        self.target = Arena.clamp(ground(target), 100)
        self.waste_boost = waste_boost
        self.finish_distance = 500

        self._time_on_ground = 0
        self.driving = True

        # decide whether to start driving backwards and halfflip later
        forward_estimate = estimate_time(car, self.target)
        backwards_estimate = estimate_time(car, self.target, -1) + 0.5
        backwards = (
                dot(car.velocity, car.forward()) < 500
                and backwards_estimate < forward_estimate
                and (distance(car, self.target) > 3000 or distance(car, self.target) < 300)
                and car.position[2] < 200
        )

        self.drive = Drive(car, self.target, 2300, backwards)
        self.action = self.drive
Пример #24
0
    def calculate(car: Car, ball: Ball, target: vec3, ball_predictions=None):
        # Init vars
        b = Ball(ball)
        dt = 1.0 / 60.0

        # Generate predictions of ball path
        if ball_predictions is None:
            ball_predictions = []
            for i in range(60 * 5):
                b.step(dt)
                ball_predictions.append(vec3(b.location))

        # Gradually converge on ball location by aiming at a location, checking time to that location,
        # and then aiming at the ball's NEW position. Guaranteed to converge (typically in <10 iterations)
        # unless the ball is moving away from the car faster than the car's max boost speed
        intercept = Intercept(b.location)
        intercept.purpose = 'ball'
        intercept.boost = True
        intercept_ball_position = vec3(b.location)
        collision_achieved = False
        last_horizontal_error = None
        last_horizontal_offset = None
        i = 0
        max_tries = 101
        analyzer = BoostAnalysis() if intercept.boost else ThrottleAnalysis()
        while i < max_tries:
            i += 1
            fake_car = Car(car)
            direction = normalize(intercept.location - car.location)
            fake_car.rotation = look_at(direction, fake_car.up())

            for t in range(60 * 5):
                # Step car location with throttle/boost analysis data
                # Not super efficient but POITROAE
                frame = analyzer.travel_time(dt, norm(fake_car.velocity))
                # print('in 1 frame I travel', frame.time, frame.distance, frame.speed)
                fake_car.location += direction * frame.distance
                fake_car.velocity = direction * frame.speed
                fake_car.time += dt
                ball_location = ball_predictions[t]

                # Check for collision
                p = closest_point_on_obb(fake_car.hitbox(), ball_location)
                if norm(p - ball_location) <= ball.collision_radius:
                    direction_vector = p - (fake_car.location - normalize(
                        fake_car.forward()) * 13.88)  # octane center of mass
                    direction_vector[2] = 0
                    target_direction_vector = target - ball_location
                    target_direction_vector[2] = 0
                    intercept_ball_position = ball_location
                    direction = atan2(direction_vector[1], direction_vector[0])
                    ideal_direction = atan2(target_direction_vector[1],
                                            target_direction_vector[0])
                    horizontal_error = direction - ideal_direction

                    # intercept.location = vec3(ball_location)
                    # intercept.time = fake_car.time
                    # return intercept

                    # Now descend the hit direction gradient
                    # Kick off the gradient descent with an arbitrary seed value
                    if last_horizontal_error is None:
                        last_horizontal_error = horizontal_error
                        last_horizontal_offset = 0
                        if horizontal_error > 0:
                            horizontal_offset = 25
                        else:
                            horizontal_offset = 25
                        intercept.location = ball_location - normalize(
                            fake_car.left()) * horizontal_offset
                        break

                    # Recursive case of gradient descent
                    if horizontal_offset == last_horizontal_offset:
                        gradient = 0
                    else:
                        gradient = (horizontal_error - last_horizontal_error
                                    ) / (horizontal_offset -
                                         last_horizontal_offset)

                    if gradient == 0:
                        predicted_horizontal_offset = horizontal_offset
                    else:
                        predicted_horizontal_offset = horizontal_offset - horizontal_error / gradient

                    # Base case (convergence)
                    if abs(gradient) < 0.0005:
                        print(f'convergence in {i} iterations')
                        print(f'gradient = {gradient}')
                        print(
                            f'last_horizontal_offset = {last_horizontal_offset}'
                        )
                        print(f'direction = {degrees(direction)}')
                        print(f'ideal direction = {degrees(ideal_direction)}')
                        print(f'target = {target}')
                        print(f'ball_location = {ball_location}')
                        return intercept

                    # Edge case exit: offset maxed out
                    max_horizontal_offset = car.hitbox(
                    ).half_width[1] + ball.collision_radius
                    if predicted_horizontal_offset > max_horizontal_offset:
                        predicted_horizontal_offset = max_horizontal_offset
                    elif predicted_horizontal_offset < -max_horizontal_offset:
                        predicted_horizontal_offset = -max_horizontal_offset
                    last_horizontal_offset = horizontal_offset
                    last_horizontal_error = horizontal_error
                    horizontal_offset = predicted_horizontal_offset

                    # Return the latest intercept location and continue descending the gradient
                    intercept.location = ball_location - normalize(
                        fake_car.left()) * predicted_horizontal_offset
                    print(f'iteration {i}')
                    print(f'gradient = {gradient}')
                    print(f'horizontal_offset = {horizontal_offset}')
                    print(f'horizontal_error = {degrees(horizontal_error)}')
                    # print(f'ideal direction = {degrees(ideal_direction)}')
                    break

                # Check for arrival
                if norm(fake_car.location -
                        intercept.location) < ball.collision_radius / 2:
                    intercept.location = ball_location
                    break

        if i >= max_tries:
            print(
                f'Warning: max tries ({max_tries}) exceeded for calculating intercept'
            )
        return intercept
Пример #25
0
from rlutilities.simulation import Car, Navigator
from rlutilities.mechanics import FollowPath
from rlutilities.linear_algebra import vec3, normalize

c = Car()

c.time = 0.0
c.position = vec3(0, 0, 0)
c.velocity = vec3(1000, 0, 0)
c.angular_velocity = vec3(0.1, -2.0, 1.2)
c.on_ground = False

navigator = Navigator(c)

drive = FollowPath(c)
drive.arrival_speed = 1234
drive.path = navigator.path_to(vec3(1000, 0, 0), vec3(1, 0, 0), 1000)

for p in drive.path.points:
    print(p)
Пример #26
0
from rlutilities.linear_algebra import vec3, mat3
from rlutilities.simulation import Game, Car, Ball, intersect

Game.set_mode("dropshot")

c = Car()

c.location = vec3(-164.13, 0, 88.79)
c.velocity = vec3(1835.87, 0, 372.271)
c.angular_velocity = vec3(0, 3.78721, 0)
c.rotation = mat3(0.9983, -5.23521e-6, 0.0582877, 5.5498e-6, 1.0, -5.23521e-6,
                  -0.0582877, 5.5498e-6, 0.9983)

b = Ball()

b.location = vec3(0, 0, 150)
b.velocity = vec3(0, 0, 0)
b.angular_velocity = vec3(0, 0, 0)

print("before:")
print(b.location)
print(b.velocity)
print(b.angular_velocity)
print("overlapping: ", intersect(c.hitbox(), b.hitbox()))

print()

b.step(0.008333, c)

print("after:")
print(b.location)
Пример #27
0
    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        # Record start time
        self.tick_start = time.time()

        # Gather some information about our car and the ball
        my_car: CarState = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        car_direction = car_velocity.ang_to(Vec3(
            1, 0, 0)) if car_velocity.length() > 0 else 0
        ball_location = Vec3(packet.game_ball.physics.location)
        ball_velocity = Vec3(packet.game_ball.physics.velocity)
        ball_direction = ball_velocity.ang_to(Vec3(
            1, 0, 0)) if ball_velocity.length() > 0 else 0
        reset = False

        # Initialize simulation game model
        if self.game == None:
            Game.set_mode('soccar')
            self.game = Game(self.index, self.team)
            self.game.read_game_information(packet, self.get_rigid_body_tick(),
                                            self.get_field_info())
            self.target = vec3(
                0, 5120 + 880 / 2 if self.team is 0 else -(5120 + 880 / 2),
                642.775 / 2)  # Opposing net
            self.reset_gamestate()
            print('TEAM', self.team)
            return SimpleControllerState()

        # Update simulation
        self.game.read_game_information(packet, self.get_rigid_body_tick(),
                                        self.get_field_info())

        # Check for car hit ball
        if self.last_touch_location != packet.game_ball.latest_touch.hit_location:
            self.last_touch_location = Vec3(
                packet.game_ball.latest_touch.hit_location)
            print(f'> Car hit ball')
            self.not_hit_yet = False

        # Recalculate intercept every frame
        self.plan()

        # Re-simulate the aerial every frame
        if self.aerial is not None and not self.aerial.finished:
            simulate_aerial(self)
            simulate_alternate_aerials(self)

        # Update dodge (init or clean up old)
        # try_init_dodge(self)

        # Rendering
        if len(self.ball_predictions) > 2:
            self.renderer.draw_polyline_3d(self.ball_predictions,
                                           self.renderer.red())
        if self.aerial != None and self.aerial.target:
            self.renderer.draw_rect_3d(self.aerial.target,
                                       8,
                                       8,
                                       True,
                                       self.renderer.green(),
                                       centered=True)
            self.renderer.draw_line_3d(car_location, self.aerial.target,
                                       self.renderer.white())
            self.renderer.draw_line_3d(vec3_to_Vec3(self.target),
                                       self.target + self.avg_aerial_error,
                                       self.renderer.cyan())
        if self.intercept != None:
            self.renderer.draw_rect_3d(self.intercept.location,
                                       8,
                                       8,
                                       True,
                                       self.renderer.green(),
                                       centered=True)
        self.renderer.draw_rect_3d(vec3_to_Vec3(self.target),
                                   8,
                                   8,
                                   True,
                                   self.renderer.green(),
                                   centered=True)

        # Controller state
        if reset:
            self.reset_gamestate()
            return SimpleControllerState()
        # "Do a flip!"
        elif self.dodge is not None:
            if self.dodge.finished:
                self.dodge = None
                return SimpleControllerState()
            self.dodge.step(self.game.time_delta)
            return self.dodge.controls
        # Just do an aerial :4head:
        elif self.aerial is not None:
            aerial_step(self.aerial, Car(self.game.my_car),
                        self.rotation_input, self.game.time_delta)
            return self.aerial.controls
        # Just hit the ball :4head:
        elif self.intercept is not None:
            if self.intercept.dodge and abs(self.game.time - self.intercept.
                                            jump_time) <= self.game.time_delta:
                print('im gonna nut')
                self.dodge = Dodge(self.game.my_car)
                self.dodge.duration = 0.2
                self.dodge.preorientation = self.intercept.dodge_preorientation
                self.dodge.delay = self.intercept.dodge_delay + 0.1
                self.dodge.direction = self.intercept.dodge_direction
                self.dodge.step(self.game.time_delta)
                return self.dodge.controls
            return self.intercept.get_controls(
                my_car, self.game.my_car
            )  #drive_at(self, my_car, self.intercept.location)

        return SimpleControllerState()
Пример #28
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
Пример #29
0
def get_car_front_center(car: Car):
    return car.location + normalize(car.forward()) * car.hitbox(
    ).half_width[0] + normalize(car.up()) * car.hitbox().half_width[2]
Пример #30
0
    def calculate_old(car: Car,
                      ball: Ball,
                      target: vec3,
                      ball_predictions=None):
        # Init vars
        fake_car = Car(car)
        b = Ball(ball)

        # Generate predictions of ball path
        if ball_predictions is None:
            ball_predictions = [vec3(b.location)]
            for i in range(60 * 5):
                b.step(1.0 / 60.0)
                ball_predictions.append(vec3(b.location))

        # Gradually converge on ball location by aiming at a location, checking time to that location,
        # and then aiming at the ball's NEW position. Guaranteed to converge (typically in <10 iterations)
        # unless the ball is moving away from the car faster than the car's max boost speed
        intercept = Intercept(b.location)
        intercept.purpose = 'ball'
        intercept.boost = True
        intercept_ball_position = vec3(b.location)
        i = 0
        max_tries = 100
        analyzer = BoostAnalysis() if intercept.boost else ThrottleAnalysis()
        while i < max_tries:
            # Find optimal spot to hit the ball
            optimal_hit_vector = normalize(
                target - intercept_ball_position) * b.collision_radius
            optimal_hit_location = intercept_ball_position - optimal_hit_vector

            # Find ideal rotation, unless it intersects with ground
            optimal_rotation = look_at(
                optimal_hit_vector, vec3(0, 0, 1)
            )  #axis_to_rotation(optimal_hit_vector) # this might be wrong
            fake_car.rotation = optimal_rotation
            # print(f'fake_car.location {fake_car.location}')
            # print(f'get_car_front_center(fake_car) {get_car_front_center(fake_car)}')
            fake_car.location += optimal_hit_location - get_car_front_center(
                fake_car
            )  # try to position the car's front center directly on top of the best hit vector
            euler = rotation_to_euler(optimal_rotation)
            # todo put some super precise trigonometry in here to find the max angle allowed at given height
            if fake_car.location[2] <= fake_car.hitbox().half_width[0]:
                euler.pitch = 0
            fake_car.rotation = euler_to_rotation(
                vec3(euler.pitch, euler.yaw, euler.roll))
            fake_car.location += optimal_hit_location - get_car_front_center(
                fake_car
            )  # try to position the car's front center directly on top of the best hit vector

            # Adjust vertical position if it (still) intersects with ground
            if fake_car.location[2] < 17.0:
                fake_car.location[2] = 17.0
            intercept.location = get_car_front_center(fake_car)

            # Calculate jump time needed
            jump_height_time = JumpAnalysis().get_frame_by_height(
                intercept.location[2]).time  # or solve with motion equation

            # car_euler = rotation_to_euler(car.rotation)
            # jump_pitch_time = (euler.pitch - car_euler.pitch) / 5.5 + 0.35 # disregarding angular acceleration
            # jump_yaw_time = (euler.yaw - car_euler.yaw) / 5.5 + 0.35 # disregarding angular acceleration
            # jump_roll_time = (euler.roll - car_euler.roll) / 5.5 + 0.35 # disregarding angular acceleration
            # jump_time = max(jump_height_time, jump_pitch_time, jump_yaw_time, jump_roll_time)
            jump_time = jump_height_time  # todo revisit rotation time
            # print('jump_time', jump_time)

            # Calculate distance to drive before jumping (to arrive perfectly on target)
            total_translation = intercept.location - get_car_front_center(car)
            total_translation[2] = 0
            total_distance = norm(total_translation)
            start_index = analyzer.get_index_by_speed(norm(car.velocity))
            start_frame = analyzer.frames[start_index]
            custom_error_func = lambda frame: abs(total_distance - (
                frame.distance - start_frame.distance) - frame.speed *
                                                  jump_time)
            drive_analysis = analyzer.get_frame_by_error(
                custom_error_func, start_index)
            arrival_time = drive_analysis.time - start_frame.time + jump_time
            # print('drive_analysis.time', drive_analysis.time)
            # print('drive_analysis', start_index)

            # arrival_time = analyzer.travel_distance(total_distance, norm(car.velocity)).time

            # drive_analysis = analyzer.travel_distance(norm(intercept.location - c.location), norm(c.velocity))
            ball_index = int(round(arrival_time * 60))
            if ball_index >= len(ball_predictions):
                intercept.location = ball_predictions[-1]
                intercept.time = len(ball_predictions) / 60.0
                break
            ball_location = ball_predictions[ball_index]
            # print(f'Iteration {i} distance {norm(ball_location + vec3(optimal_hit_vector[0], optimal_hit_vector[1], 0) - intercept.location)}')
            if norm(ball_location - intercept_ball_position) <= 1:
                # if norm(intercept_ball_position - get_car_front_center(fake_car)) > 100:
                #     intercept.location = ball_predictions[-1]
                #     intercept.time = len(ball_predictions) / 60.0
                #     return intercept

                intercept.dodge = True  #jump_time > 0.2
                intercept.jump_time = car.time + arrival_time - jump_time
                intercept.dodge_preorientation = euler_to_rotation(
                    vec3(euler.pitch, euler.yaw, euler.roll))
                intercept.dodge_delay = jump_time
                intercept.dodge_direction = normalize(vec2(optimal_hit_vector))
                # print(f'intercept_ball_position', intercept_ball_position)
                # print(f'intercept.location', intercept.location)
                # print(f'time until jump {drive_analysis.time}')
                # print(f'time now {car.time}')
                # print(f'distance until jump {drive_analysis.distance}')
                # print(f'total distance to target {total_distance}')
                # print(f'horiz speed @ jump {drive_analysis.speed}')
                # print(f'time intended to be in air {jump_time}')
                # print(f'distance travelled in air {jump_time * drive_analysis.speed}')
                # print(f'distance remaining to target @ jump {total_distance - drive_analysis.distance}')
                # print(f'Intercept convergence in {i} iterations')
                # print(f'desired roll {euler.roll}')
                # print(f'actual roll {rotation_to_euler(c.rotation).roll}')
                break

            intercept_ball_position = vec3(ball_location)
            # intercept.location = vec3(ball_location)
            # intercept.location[2] = 0
            intercept.time = arrival_time
            i += 1

        if i >= max_tries:
            print(
                f'Warning: max tries ({max_tries}) exceeded for calculating intercept'
            )

        # Intercept is only meant for ground paths (and walls/cieling are only indirectly supported)
        # collision_radius = c.hitbox().half_width[2] * 2 + b.collision_radius + b.collision_radius * 8
        # on_ground = intercept.location[2] <= collision_radius
        # on_back_wall = abs(intercept.location[1]) >= 5120 - collision_radius
        # on_side_wall = abs(intercept.location[0]) >= 4096 - collision_radius
        # # on_cieling = intercept.location[2] >= 2044 - collision_radius
        # reachable = on_ground # or on_back_wall or on_side_wall # or on_cieling
        # if not reachable:
        #     return None

        return intercept