def get_cue_ball_path(self):
        """
        Sets the cue stick line endpoint.
        Will either be at a ball or a cushion.
        """

        # If cue ball is currently pocketed, skip
        if self.cue_ball is None:
            return

        # Reset lines
        self.object_deflect_line_start = self.object_deflect_line_end = self.cue_deflect_line_end = None

        angle = self.cue_angle
        nw = Coordinates(self.left, self.top)
        se = Coordinates(self.right, self.bottom)

        cue_mid_start = self.cue_ball.pos  # Line start is cue ball position
        cue_mid_end = self.cue_line_end = get_line_endpoint_within_box(
            cue_mid_start, angle, nw, se, self.cue_ball.radius)

        cue_top_start, cue_top_end = get_parallel_line(cue_mid_start,
                                                       cue_mid_end,
                                                       self.cue_ball.radius,
                                                       True)
        cue_bot_start, cue_bot_end = get_parallel_line(cue_mid_start,
                                                       cue_mid_end,
                                                       self.cue_ball.radius,
                                                       False)

        # Ghost ball computation
        balls_by_distance = list(self.balls.values())
        balls_by_distance.sort(
            key=lambda b: get_distance(cue_mid_start, b.pos))

        for ball in balls_by_distance:
            if ball.ball_type is BallType.CUE: continue  # Skip the cue ball

            if (check_ray_circle_intersection(cue_top_start, cue_top_end,
                                              ball.pos, ball.radius)
                    or check_ray_circle_intersection(
                        cue_bot_start, cue_bot_end, ball.pos, ball.radius)):

                print("CUE BALL INTERSECTING {}".format(ball))

                self.cue_line_end = get_point_on_line_distance_from_point(
                    cue_mid_start, cue_mid_end, ball.pos, 2 * ball.radius)

                # Set object ball deflection line
                self.object_deflect_line_start = ball.pos
                object_ball_angle = get_angle(ball.pos, self.cue_line_end)
                self.object_deflect_line_end = get_line_endpoint_within_box(
                    ball.pos, object_ball_angle, nw, se, self.cue_ball.radius)

                # Set cue ball deflection line
                cue_deflect_angle = get_angle(self.object_deflect_line_end,
                                              self.object_deflect_line_start)
                cue_object_angle = get_angle(ball.pos, self.cue_ball.pos)
                print('self.cue_angle: {}'.format(self.cue_angle))
                print('self.cue_angle: {}'.format(cue_object_angle))
                if self.cue_angle % 360 == 0:
                    # Edge case when perfectly to the right
                    cue_deflect_angle = (cue_deflect_angle + 90) % 360
                elif self.cue_angle < cue_object_angle:

                    print("CUE BALL GOING RIGHT OF OBJECT BALl")
                    cue_deflect_angle = (cue_deflect_angle - 90) % 360
                else:
                    print("CUE BALL GOING LEFT OF OBJECT BALl")
                    cue_deflect_angle = (cue_deflect_angle + 90) % 360
                self.cue_deflect_line_end = get_line_endpoint_within_box(
                    self.cue_line_end, cue_deflect_angle, nw, se,
                    self.cue_ball.radius)
                return
Exemple #2
0
    def get_angle(self):
        """
        Get the angle for this vector.
        """

        return util.get_angle(Coordinates(self.x, self.y))
Exemple #3
0
    def test_get_parallel_line(self):
        # def get_parallel_line(p1: Coordinates, p2: Coordinates, dist: float, top: bool) -> (Coordinates, Coordinates):

        ######################
        # Parallel to x-axis #
        ######################
        p1 = Coordinates(-1, 0)
        p2 = Coordinates(1, 0)
        dist = 1.0

        expected_angle = get_angle(p2, p1)

        result_top = get_parallel_line(p1, p2, dist, True)
        result_bot = get_parallel_line(p1, p2, dist, False)
        result_top_angle = get_angle(result_top[1], result_top[0])
        result_bot_angle = get_angle(result_bot[1], result_bot[0])

        # Check angles are the same
        self.assertEqual(expected_angle, result_top_angle)
        self.assertEqual(expected_angle, result_bot_angle)

        # Check distance apart
        self.assertAlmostEqual(dist, get_distance(p1, result_top[0]),
                               FLOAT_PLACES)
        self.assertAlmostEqual(dist, get_distance(p2, result_top[1]),
                               FLOAT_PLACES)

        ######################
        # Parallel to y-axis #
        ######################
        p1 = Coordinates(0, -1)
        p2 = Coordinates(0, 1)
        dist = 1.0

        expected_angle = get_angle(p2, p1)

        result_top = get_parallel_line(p1, p2, dist, True)
        result_bot = get_parallel_line(p1, p2, dist, False)

        result_top_angle = get_angle(result_top[1], result_top[0])
        result_bot_angle = get_angle(result_bot[1], result_bot[0])

        # Check angles are the same
        self.assertEqual(expected_angle, result_top_angle)
        self.assertEqual(expected_angle, result_bot_angle)

        # Check distance apart
        self.assertAlmostEqual(dist, get_distance(p1, result_top[0]),
                               FLOAT_PLACES)
        self.assertAlmostEqual(dist, get_distance(p2, result_top[1]),
                               FLOAT_PLACES)

        #####################
        # Parallel to y = x #
        #####################
        p1 = Coordinates(-1, -1)
        p2 = Coordinates(1, 1)
        dist = 1.0

        expected_angle = get_angle(p2, p1)

        result_top = get_parallel_line(p1, p2, dist, True)
        result_bot = get_parallel_line(p1, p2, dist, False)

        result_top_angle = get_angle(result_top[1], result_top[0])
        result_bot_angle = get_angle(result_bot[1], result_bot[0])

        # Check angles are the same
        self.assertEqual(expected_angle, result_top_angle)
        self.assertEqual(expected_angle, result_bot_angle)

        # Check distance apart
        self.assertAlmostEqual(dist, get_distance(p1, result_top[0]),
                               FLOAT_PLACES)
        self.assertAlmostEqual(dist, get_distance(p2, result_top[1]),
                               FLOAT_PLACES)
Exemple #4
0
def main2():
    init()

    # Create pool table
    nw = coords_from_pygame((TABLE_OFFSET_X, TABLE_OFFSET_Y), HEIGHT)
    se = coords_from_pygame(
        (TABLE_OFFSET_X + TABLE_LENGTH, TABLE_OFFSET_Y + TABLE_LENGTH / 2),
        HEIGHT)
    table = PoolTable(nw, se)

    while 1:
        # Get just the list of balls to iterate easily
        balls = list(table.balls.values())

        clear_screen()

        # Check Pygame events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONUP:
                # These positions assume origin lower-left
                target_pos = coords_from_pygame(pygame.mouse.get_pos(), HEIGHT)
                cue_pos = table.cue_ball.pos

                table.cue_angle = get_angle(target_pos, cue_pos)
                print('AFTER SETTING cue_angle', table.cue_angle)
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    sys.exit()
                elif event.key == pygame.K_b:
                    # BREAK cue ball
                    mag = 500.0
                    force = Vector(mag * np.cos(np.radians(table.cue_angle)),
                                   mag * np.sin(np.radians(table.cue_angle)))
                    table.balls[BallType.CUE].apply_force(force)
                elif event.key == pygame.K_SPACE:
                    # Strike cue ball
                    mag = 50.0
                    force = Vector(mag * np.cos(np.radians(table.cue_angle)),
                                   mag * np.sin(np.radians(table.cue_angle)))
                    table.balls[BallType.CUE].apply_force(force)
                elif event.key == pygame.K_p:
                    # DEBUG set all speeds to 0
                    for ball in balls:
                        ball.vel.x, ball.vel.y = 0, 0
                elif event.key == pygame.K_r:
                    # DEBUG reset
                    # Create pool table
                    nw = coords_from_pygame((TABLE_OFFSET_X, TABLE_OFFSET_Y),
                                            HEIGHT)
                    se = coords_from_pygame(
                        (TABLE_OFFSET_X + TABLE_LENGTH,
                         TABLE_OFFSET_Y + TABLE_LENGTH / 2), HEIGHT)
                    table = PoolTable(nw, se)

        # Table time step
        table.time_step()

        # Draw pool table
        draw_pool_table(table)

        draw_cue_stick_line(table)
        draw_cue_ghost_ball(table)
        draw_cue_ball_deflection_line(table)
        draw_object_ball_deflection_line(table)

        # Draw all pool balls
        for ball in balls:
            draw_pool_ball(ball)

        pygame.display.flip()