示例#1
0
    def simulate_landing(self):
        pos = vec3(self.car.position)
        vel = vec3(self.car.velocity)
        grav = vec3(0, 0, -650)
        self.trajectory = [vec3(pos)]
        self.landing = False
        collision_normal: Optional[vec3] = None

        dt = 1 / 60
        simulation_duration = 0.8
        for i in range(int(simulation_duration / dt)):
            pos += vel * dt
            vel += grav * dt
            if norm(vel) > 2300: vel = normalize(vel) * 2300
            self.trajectory.append(vec3(pos))

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

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

        if self.landing:
            u = collision_normal
            f = normalize(vel - dot(vel, u) * u)
            l = normalize(cross(u, f))
            self.aerial_turn.target = three_vec3_to_mat3(f, l, u)
        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
    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))
示例#3
0
 def intercept_predicate(self, car: Car, ball: Ball):
     if ball.position[2] > 200 or abs(
             ball.position[1]) > Arena.size[1] - 400:
         return False
     contact_ray = Field.collide(
         sphere(ball.position, self.max_distance_from_wall))
     return norm(contact_ray.start) > 0 and abs(
         dot(ball.velocity, contact_ray.direction)) < 150
示例#4
0
 def intercept_predicate(self, car: Car, ball: Ball):
     # max_height = align(car, ball, self.target) * 60 + self.max_base_height
     max_height = 300
     contact_ray = Field.collide(sphere(ball.position, max_height))
     return (norm(contact_ray.direction) > 0
             and ball.position[2] < max_height + 50
             and (Arena.inside(ball.position, 100)
                  or distance(ball, self.target) < 1000)
             and abs(car.position[0]) < Arena.size[0] - 300)
示例#5
0
 def find_landing_pos(self, num_points=200, dt=0.0333) -> vec3:
     '''Simulate car falling until it hits a plane and return it's final position'''
     dummy = Car(self.car)
     for i in range(0, num_points):
         dummy.step(Input(), dt)
         dummy.time += dt
         n = Field.collide(sphere(dummy.position, 40)).direction
         if norm(n) > 0.0 and i > 10:
             return dummy.position
     return self.car.position
示例#6
0
    def find_landing_orientation(self, num_points):

        f = vec3(0, 0, 0)
        l = vec3(0, 0, 0)
        u = vec3(0, 0, 0)

        dummy = Car(self.car)
        self.trajectory = [vec3(dummy.position)]
        found = False
        for i in range(0, num_points):
            dummy.step(Input(), 0.01633)
            self.trajectory.append(vec3(dummy.position))
            u = Field.collide(sphere(dummy.position, 40)).direction
            if norm(u) > 0.0 and i > 40:
                f = normalize(dummy.velocity - dot(dummy.velocity, u) * u)
                l = normalize(cross(u, f))
                found = True
                break

        if found:
            self.turn.target = mat3(f[0], l[0], u[0], f[1], l[1], u[1], f[2],
                                    l[2], u[2])
        else:
            self.turn.target = self.car.orientation
示例#7
0
    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
示例#8
0
    def start(self):

        if TWITCH_CHAT_INTERACTION:
            port = find_usable_port(9097)
            Thread(target=run_action_server, args=(port, ),
                   daemon=True).start()
            set_bot_action_broker(
                self.action_broker
            )  # This seems to only work after the bot hot reloads once, weird.

            Thread(target=self.heartbeat_connection_attempts_to_twitch_broker,
                   args=(port, ),
                   daemon=True).start()

        while True:
            sleep(0)
            packet = self.wait_game_tick_packet()

            raw_players = [
                self.game_tick_packet.game_cars[i]
                for i in range(packet.num_cars)
            ]
            self.known_players = [p for p in raw_players if p.name]
            if self.last_seconds_elapsed == packet.game_info.seconds_elapsed:
                continue
            elapsed_now = packet.game_info.seconds_elapsed - self.last_seconds_elapsed
            self.last_seconds_elapsed = packet.game_info.seconds_elapsed

            ball_pos = Vec3(packet.game_ball.physics.location)
            ball_vel = Vec3(packet.game_ball.physics.velocity)
            ball_ang = Vec3(packet.game_ball.physics.angular_velocity)

            self.ticksThisSecond += 1
            if int(packet.game_info.seconds_elapsed) != self.lastFullSecond:
                print("ticks this second:", self.ticksThisSecond)
                self.ticksThisSecond = 0
                self.lastFullSecond = int(packet.game_info.seconds_elapsed)

            if TWITCH_CHAT_INTERACTION:
                self.car_lasers = {
                    k: v
                    for k, v in self.car_lasers.items()
                    if v.time_remaining >= 0
                }
            else:
                self.car_lasers = {}
                for i in range(packet.num_cars):
                    self.car_lasers[i] = Laser(0, math.inf)

            if packet.teams[0].score - packet.teams[1].score != self.lastScore:
                self.isPaused = True
                self.lastScore = packet.teams[0].score - packet.teams[1].score
                self.isKickoff = 0
            elif packet.game_ball.physics.location.x == 0 and packet.game_ball.physics.location.y == 0 and packet.game_ball.physics.velocity.x == 0 and packet.game_ball.physics.velocity.y == 0:
                self.isKickoff += elapsed_now
                if self.isKickoff >= 4:
                    self.isPaused = False

            ballTouchers = []
            random.seed(a=int(packet.game_info.seconds_elapsed / .14))

            if DURING_BOOST_ONLY:
                boosting = {}
                boostContent = {}
                for i in range(packet.num_cars):
                    car = packet.game_cars[i]
                    boosting[i] = i in self.boostContent and (
                        6 if self.boostContent[i] > car.boost or
                        (self.boostContent[i] < car.boost and self.boosting[i])
                        else max(0, self.boosting[i] - 1))
                    boostContent[i] = car.boost
                self.boosting = boosting
                self.boostContent = boostContent

            for index in range(packet.num_cars):
                car = packet.game_cars[index]
                car_pos = Vec3(car.physics.location)
                car_ori = Orientation(car.physics.rotation)

                self.renderer.begin_rendering(str(index) + "Lb")

                if index in self.car_lasers:
                    laser = self.car_lasers[index]
                    if not packet.game_cars[index].is_demolished and (
                            not DURING_BOOST_ONLY
                            or self.boosting[index]):  # and not self.isPaused:
                        if not self.isPaused:
                            laser.time_remaining -= elapsed_now
                        if laser.time_remaining >= 0:
                            for leftRight in (-1, 1):
                                startPoint = car_pos + car_ori.forward * 63 - leftRight * car_ori.right * 26 + car_ori.up * 3
                                direction = car_ori.forward.orthogonalize(
                                    Vec3(0, 0, 1)).normalized(
                                    ) if car.has_wheel_contact and abs(
                                        car_ori.up.dot(Vec3(0, 0, 1))
                                    ) > 0.999 else car_ori.forward

                                for bounce in range(BOUNCE_SEGMENTS):
                                    closest = math.inf
                                    closestTarget = None
                                    toBall = Vec3(packet.game_ball.physics.
                                                  location) - car_pos
                                    toBallProj = toBall.project(direction)
                                    toBallOrth = toBall - toBallProj
                                    toCollisionOrth = toBallOrth
                                    endVector = direction
                                    if toBallOrth.length(
                                    ) <= BALL_RADIUS and toBallProj.dot(
                                            direction) > 0:
                                        closestTarget = -1
                                        closest = toBallProj.length(
                                        ) - math.sqrt(BALL_RADIUS**2 -
                                                      toBallOrth.length()**2)
                                        ballTouchers.append(index)

                                    for otherIndex in range(packet.num_cars):
                                        if otherIndex == index:
                                            continue
                                        other_car = packet.game_cars[
                                            otherIndex]
                                        other_car_pos = Vec3(
                                            other_car.physics.location)
                                        other_car_ori = Orientation(
                                            other_car.physics.rotation)

                                        v_local = other_car_ori.dot2(
                                            startPoint -
                                            (other_car_pos +
                                             other_car_ori.dot1(HITBOX_OFFSET)
                                             ) + 15 * other_car_ori.up)
                                        d_local = other_car_ori.dot2(direction)

                                        def lineFaceCollision(i):
                                            offset = Vec3(0, 0, 0)
                                            offset[i] = math.copysign(
                                                HITBOX_HALF_WIDTHS[i],
                                                -d_local[i])
                                            collisionPoint = v_local - offset
                                            try:
                                                distance = -collisionPoint[
                                                    i] / d_local[i]
                                            except ZeroDivisionError:
                                                return None
                                            if distance < 0:
                                                return None
                                            collisionPoint += d_local * distance
                                            for j in range(
                                                    i == 0, 3 - (i == 2),
                                                    1 + (i == 1)):
                                                if abs(
                                                        collisionPoint[j]
                                                ) > HITBOX_HALF_WIDTHS[j]:
                                                    return None
                                            collisionPoint[i] = offset[i]
                                            return distance

                                        distance = lineFaceCollision(
                                            0) or lineFaceCollision(
                                                1) or lineFaceCollision(2)
                                        if distance is not None:
                                            collisionPoint = startPoint + distance * direction
                                            toCollisionOrth = (
                                                collisionPoint - startPoint
                                            ).orthogonalize(direction)
                                            if distance < closest:
                                                closest = distance
                                                closestTarget = otherIndex

                                    if closestTarget is not None:
                                        if closestTarget not in self.forces:
                                            self.forces[closestTarget] = Push()
                                        self.forces[
                                            closestTarget].velocity += direction * elapsed_now
                                        try:
                                            self.forces[
                                                closestTarget].angular_velocity += toCollisionOrth * -1 * direction / toCollisionOrth.length(
                                                )**2 * elapsed_now
                                        except ZeroDivisionError:
                                            pass
                                        pass
                                    else:
                                        # simulate raycast closest
                                        length = 100000
                                        startPointRLU = toRLU(startPoint)
                                        directionRLU = toRLU(direction)
                                        ray = Ray(startPointRLU,
                                                  directionRLU * length)
                                        while closest >= length + .2:
                                            closest = length
                                            newStartPointRLU, mirrorDirectionRLU = ray.start, ray.direction
                                            ray = Field.raycast_any(
                                                Ray(
                                                    startPointRLU,
                                                    directionRLU *
                                                    (length - .1)))
                                            length = norm(ray.start -
                                                          startPointRLU)
                                        mirrorDirection = fromRLU(
                                            mirrorDirectionRLU)
                                        newStartPoint = fromRLU(
                                            newStartPointRLU)
                                        newDirection = direction - 2 * direction.dot(
                                            mirrorDirection) * mirrorDirection
                                        endVector = direction * 0.6 - mirrorDirection * 0.4

                                    R = 4
                                    COLORSPIN = 2
                                    SCATTERSPIN = 0.75

                                    dir_ori = look_at_orientation(
                                        direction, Vec3(0, 0, 1))
                                    dir_ori.right *= R
                                    dir_ori.up *= R
                                    end_ori = look_at_orientation(
                                        endVector, Vec3(0, 0, 1))
                                    scatterStartFirst = startPoint + closest * direction

                                    for i in range(LASERLINES):
                                        i = i / LASERLINES * 2 * math.pi
                                        offset = dir_ori.right * math.sin(
                                            i) + dir_ori.up * math.cos(i)
                                        color = self.renderer.create_color(
                                            255,
                                            int(255 * (0.5 + 0.5 * math.sin(
                                                car.physics.rotation.roll +
                                                leftRight * i +
                                                (COLORSPIN * packet.game_info.
                                                 seconds_elapsed)))),
                                            int(255 * (0.5 + 0.5 * math.sin(
                                                car.physics.rotation.roll +
                                                leftRight * i +
                                                (COLORSPIN * packet.game_info.
                                                 seconds_elapsed +
                                                 2 / 3 * math.pi)))),
                                            int(255 * (0.5 + 0.5 * math.sin(
                                                car.physics.rotation.roll +
                                                leftRight * i +
                                                (COLORSPIN * packet.game_info.
                                                 seconds_elapsed +
                                                 4 / 3 * math.pi)))))
                                        self.renderer.native_draw_line_3d(
                                            self.renderer.builder, color,
                                            toDrawVector3(startPoint + offset),
                                            toDrawVector3(scatterStartFirst +
                                                          offset))

                                    for _ in range(SCATTERLINES):
                                        r = random.uniform(0, 2 * math.pi)
                                        c = leftRight * r - (
                                            SCATTERSPIN - COLORSPIN
                                        ) * packet.game_info.seconds_elapsed
                                        i = car.physics.rotation.roll + r - leftRight * (
                                            SCATTERSPIN
                                        ) * packet.game_info.seconds_elapsed
                                        # c = random.uniform(0, 2 * math.pi)
                                        color = self.renderer.create_color(
                                            255,
                                            int(255 *
                                                (0.5 + 0.5 * math.sin(c))),
                                            int(255 *
                                                (0.5 + 0.5 *
                                                 math.sin(c + 2 / 3 * math.pi))
                                                ),
                                            int(255 *
                                                (0.5 + 0.5 *
                                                 math.sin(c + 4 / 3 * math.pi))
                                                ))
                                        length = 15 * random.expovariate(1)
                                        scatterStart = scatterStartFirst + dir_ori.right * math.sin(
                                            i) + dir_ori.up * math.cos(i)
                                        scatterEnd = scatterStart + end_ori.dot1(
                                            Vec3(-length, length * math.sin(i),
                                                 length * math.cos(i)))
                                        self.renderer.native_draw_line_3d(
                                            self.renderer.builder, color,
                                            toDrawVector3(scatterStart),
                                            toDrawVector3(scatterEnd))

                                    if closestTarget is not None:
                                        break
                                    else:
                                        startPoint, direction = newStartPoint + 0.1 * newDirection, newDirection

                self.renderer.end_rendering()

            ballState = None
            if -1 in self.forces:
                if not self.isPaused:
                    ballState = BallState(
                        # latest_touch=Touch(player_name=packet.game_cars[random.choice(ballTouchers)].name),
                        physics=Physics(velocity=toVector3(
                            ball_vel +
                            self.forces[-1].velocity * PUSH_STRENGTH_BALL),
                                        angular_velocity=toVector3(
                                            ball_ang +
                                            self.forces[-1].angular_velocity *
                                            PUSH_STRENGTH_BALL_ANGULAR)))
                del self.forces[-1]
            carStates = {}
            for i, force in self.forces.items():
                carStates[i] = CarState(physics=Physics(
                    velocity=toVector3(
                        Vec3(packet.game_cars[i].physics.velocity) +
                        self.forces[i].velocity * PUSH_STRENGTH_CAR),
                    angular_velocity=toVector3(
                        Vec3(packet.game_cars[i].physics.angular_velocity) +
                        self.forces[i].angular_velocity *
                        PUSH_STRENGTH_CAR_ANGULAR)))
            self.forces.clear()
            self.set_game_state(GameState(cars=carStates, ball=ballState))