示例#1
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))
示例#2
0
文件: agent.py 项目: robbai/NVDerevo
 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 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)
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)
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)
示例#7
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
示例#8
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
示例#9
0
c.time = 0.0
c.location = vec3(1509.38, -686.19, 17.01)
c.velocity = vec3(-183.501, 1398., 8.321)
c.angular_velocity = vec3(0, 0, 0)
c.rotation = mat3(-0.130158, -0.991493, -0.00117062, 0.991447, -0.130163,
                  0.00948812, -0.00955977, 0.0000743404, 0.999954)
c.dodge_rotation = mat2(-0.130163, -0.991493, 0.991493, -0.130163)

c.on_ground = True
c.jumped = False
c.double_jumped = False
c.jump_timer = -1.0
c.dodge_timer = -1.0

dodge = Dodge(c)
dodge.direction = vec2(-230.03, 463.42)
dodge.duration = 0.1333
dodge.delay = 0.35

f = open("dodge_simulation.csv", "w")
for i in range(300):
    dodge.step(0.008333)
    print(c.time, dodge.controls.jump, dodge.controls.pitch,
          dodge.controls.yaw)
    c.step(dodge.controls, 0.008333)
    f.write(
        f"{c.time}, {c.location[0]}, {c.location[1]}, {c.location[2]}, "
        f"{c.velocity[0]}, {c.velocity[1]}, {c.velocity[2]}, "
        f"{c.angular_velocity[0]}, {c.angular_velocity[1]}, {c.angular_velocity[2]}\n"
    )
示例#10
0
    def simulate(self, global_target=None):
        lol = 0
        # Initialize the ball prediction
        # Estimate the probable duration of the jump and round it down to the floor decimal
        ball_prediction = self.get_ball_prediction_struct()
        if self.info.my_car.boost < 6:
            duration_estimate = math.floor(
                get_time_at_height(self.info.ball.position[2]) * 10) / 10
        else:
            adjacent = norm(
                vec2(self.info.my_car.position - self.info.ball.position))
            opposite = (self.info.ball.position[2] -
                        self.info.my_car.position[2])
            theta = math.atan(opposite / adjacent)
            t = get_time_at_height_boost(self.info.ball.position[2], theta,
                                         self.info.my_car.boost)
            duration_estimate = (math.ceil(t * 10) / 10)
        # Loop for 6 frames meaning adding 0.1 to the estimated duration. Keeps the time constraint under 0.3s
        for i in range(6):
            # Copy the car object and reset the values for the hitbox
            car = Car(self.info.my_car)
            # Create a dodge object on the copied car object
            # Direction is from the ball to the enemy goal
            # Duration is estimated duration plus the time added by the for loop
            # preorientation is the rotation matrix from the ball to the goal
            # TODO make it work on both sides
            #  Test with preorientation. Currently it still picks a low duration at a later time meaning it
            #  wont do any of the preorientation.
            dodge = Dodge(car)
            prediction_slice = ball_prediction.slices[round(
                60 * (duration_estimate + i / 60))]
            physics = prediction_slice.physics
            ball_location = vec3(physics.location.x, physics.location.y,
                                 physics.location.z)
            # ball_location = vec3(0, ball_y, ball_z)
            dodge.duration = duration_estimate + i / 60
            if dodge.duration > 1.4:
                break

            if global_target is not None:
                dodge.direction = vec2(global_target - ball_location)
                target = vec3(vec2(global_target)) + vec3(
                    0, 0, jeroens_magic_number * ball_location[2])
                dodge.preorientation = look_at(target - ball_location,
                                               vec3(0, 0, 1))
            else:
                dodge.target = ball_location
                dodge.direction = vec2(ball_location) + vec2(ball_location -
                                                             car.position)
                dodge.preorientation = look_at(ball_location, vec3(0, 0, 1))
            # Loop from now till the end of the duration
            fps = 30
            for j in range(round(fps * dodge.duration)):
                lol = lol + 1
                # Get the ball prediction slice at this time and convert the location to RLU vec3
                prediction_slice = ball_prediction.slices[round(60 * j / fps)]
                physics = prediction_slice.physics
                ball_location = vec3(physics.location.x, physics.location.y,
                                     physics.location.z)
                dodge.step(1 / fps)

                T = dodge.duration - dodge.timer
                if T > 0:
                    if dodge.timer < 0.2:
                        dodge.controls.boost = 1
                        dodge.controls.pitch = 1
                    else:
                        xf = car.position + 0.5 * T * T * vec3(
                            0, 0, -650) + T * car.velocity

                        delta_x = ball_location - xf
                        if angle_between(vec2(car.forward()),
                                         dodge.direction) < 0.3:
                            if norm(delta_x) > 50:
                                dodge.controls.boost = 1
                                dodge.controls.throttle = 0.0
                            else:
                                dodge.controls.boost = 0
                                dodge.controls.throttle = clip(
                                    0.5 * (200 / 3) * T * T, 0.0, 1.0)
                        else:
                            dodge.controls.boost = 0
                            dodge.controls.throttle = 0.0
                else:
                    dodge.controls.boost = 0

                car.step(dodge.controls, 1 / fps)
                succesfull = self.dodge_succesfull(car, ball_location, dodge)
                if succesfull is not None:
                    if succesfull:
                        return True, j / fps, ball_location
                    else:
                        break
        return False, None, None
示例#11
0
class CarSimmer:
    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 = []

    def reset(self, physics: SimPhysics):
        self.physics = physics
        self._set_rlu_car()

    def is_jumped(self):
        return self.is_rlu_updated and self.rlu_car.jumped

    def is_double_jumped(self):
        return self.is_rlu_updated and self.rlu_car.double_jumped

    def is_on_ground(self):
        return not self.is_rlu_updated

    def is_supersonic(self):
        return self.physics.velocity.length() > 2200

    def _set_rlu_car(self):
        c = self.rlu_car
        c.position = to_rlu_vec(self.physics.location)
        c.velocity = to_rlu_vec(self.physics.velocity)
        c.angular_velocity = to_rlu_vec(self.physics.angular_velocity)
        c.orientation = Orientation(self.physics.rotation).to_rot_mat()

        c.boost = self.boost
        c.jumped = False
        c.double_jumped = False
        c.on_ground = True
        c.team = 0
        c.time = 0
        self.is_rlu_updated = True

    def _make_input(self, controls):
        inputs = RLUInput()
        fields = [
            'boost', 'handbrake', 'jump', 'pitch', 'roll', 'steer', 'throttle',
            'yaw'
        ]
        for f in fields:
            setattr(inputs, f, getattr(controls, f))
        return inputs

    def _rlu_step(self, controls, dt, on_ground):
        # we think RLU sims this situation better
        # print(f"{self.count}: rlusim")
        if not self.is_rlu_updated:
            self._set_rlu_car()

        self.rlu_car.on_ground = on_ground

        inputs = self._make_input(controls)
        self.rlu_car.step(inputs, dt)

        self.physics.location = rlu_to_Vec3(self.rlu_car.position)
        self.physics.velocity = rlu_to_Vec3(self.rlu_car.velocity)
        self.physics.angular_velocity = rlu_to_Vec3(
            self.rlu_car.angular_velocity)
        self.physics.rotation = Orientation.from_rot_mat(
            self.rlu_car.orientation)
        # self.boost = self.rlu_car.boost

    def mark_location(self):
        N = 200
        rate = 30
        if not self.renderer:
            return

        # use as a ring buffer, list has N items
        # self.index marks the spot between latest and oldest

        if self.count % rate != 0:
            self.index = (self.index + 1) % N
            o = Orientation(self.physics.rotation)
            location = Vec3(self.physics.location)
            if len(self.locations) <= self.index:
                self.locations.append(location)
                self.up.append(o.up)
                self.forward.append(o.forward)
            else:
                self.locations[self.index] = location
                self.up[self.index] = o.up
                self.forward[self.index] = o.forward

        self.renderer.begin_rendering()

        end = len(self.locations)
        for index in range(self.index + 1, self.index + end):
            i = index % end
            loc = self.locations[i]
            component = float(i) / len(self.locations)
            inverse = 1 - component
            color = self.renderer.create_color(255, ceil(255 * component),
                                               ceil(255 * inverse / 2),
                                               ceil(255 * inverse))
            self.renderer.draw_rect_3d(loc, 4, 4, True, color, centered=True)
            self.renderer.draw_line_3d(loc, loc + (self.up[i] * 200), color)

        self.renderer.end_rendering()

    def tick(self, controls: SimpleControllerState, dt: float):
        self.count += 1
        self.mark_location()

        was_ground = self.is_on_ground()
        if not was_ground:
            self.airtime += dt
        else:
            self.airtime = 0

        # we will now find actual normal
        result = Field.collide(make_obb(self.physics))
        normal = rlu_to_Vec3(result.direction)

        on_ground = True

        if normal.length() < 0.1:
            # normally should be one. This just means there is no collision
            last_distance = (self.last_base - self.physics.location).length()
            if last_distance > (36.16 / 2) * 1.01:
                on_ground = False
                self.last_base.z = 1e5
            normal = self.last_normal
        else:
            self.last_base = clamp_location(rlu_to_Vec3(result.start))
            self.last_normal = normal

        if not on_ground or controls.jump:
            self._rlu_step(controls, dt, on_ground and not self.last_was_jump)
            self.last_was_jump = controls.jump
            clamp(self.physics)
            return self.physics

        # TODO: Special landing logic to maintain speed
        if on_ground and self.airtime > 0:
            # we are landing! lets give ourselves a nice landing
            # NOT REALISTIC but that's not our goal anyways
            # we want up = normal, and maintain all momentum in the appropriate direction
            orientation = Orientation(self.physics.rotation)
            self.physics.rotation = rotate_by_axis(orientation, orientation.up,
                                                   normal)
            orientation = Orientation(self.physics.rotation)
            # now lets update the velocities
            remove_velocity_against_normal(self.physics.velocity, normal)

        self.last_was_jump = controls.jump
        self.is_rlu_updated = False
        orientation = Orientation(self.physics.rotation)
        # compare orientations
        if normal.ang_to(orientation.up) > pi / 6:
            # 30 degrees seems like an awful a lot
            return stuck_on_ground(self.physics, controls, dt, result,
                                   self.renderer)

        self.physics.rotation = rotate_by_axis(orientation, orientation.up,
                                               normal)
        self.physics.angular_velocity = Vec3(0, 0, 0)

        rotate_ground_and_move(self.physics, controls, dt, normal)
        clamp(self.physics)
        return self.physics