Example #1
0
    def get_balls(game: GameType):
        m = BALL_MASS
        r = BALL_RADIUS

        ball_c = PoolBall(BallType.CUE, Coordinates(0, 0), m, r)
        ball_1 = PoolBall(BallType.ONE, Coordinates(0, 0), m, r)
        ball_2 = PoolBall(BallType.TWO, Coordinates(0, 0), m, r)
        ball_3 = PoolBall(BallType.THREE, Coordinates(0, 0), m, r)
        ball_4 = PoolBall(BallType.FOUR, Coordinates(0, 0), m, r)
        ball_5 = PoolBall(BallType.FIVE, Coordinates(0, 0), m, r)
        ball_6 = PoolBall(BallType.SIX, Coordinates(0, 0), m, r)
        ball_7 = PoolBall(BallType.SEVEN, Coordinates(0, 0), m, r)
        ball_8 = PoolBall(BallType.EIGHT, Coordinates(0, 0), m, r)
        ball_9 = PoolBall(BallType.NINE, Coordinates(0, 0), m, r)

        balls = {
            BallType.CUE: ball_c,
            BallType.ONE: ball_1,
            BallType.TWO: ball_2,
            BallType.THREE: ball_3,
            BallType.FOUR: ball_4,
            BallType.FIVE: ball_5,
            BallType.SIX: ball_6,
            BallType.SEVEN: ball_7,
            BallType.EIGHT: ball_8,
            BallType.NINE: ball_9,
        }

        return balls
Example #2
0
def resolve_ball_wall_collision(ball: PoolBall, wall: Direction):
    """
    Sets the new velocity for this ball after it has collided with a wall.
    *Assumes wall is in one of 4 directions: N, E, S, or W*

    :param ball: pool ball
    :param wall: which wall (N, E, S, W)
    """

    if wall == Direction.NORTH or wall == Direction.SOUTH:
        ball.vel = Vector(ball.vel.x, -ball.vel.y)  # Reverse y-direction
    else:  # EAST or WEST
        ball.vel = Vector(-ball.vel.x, ball.vel.y)  # Reverse x-direction
    def test_resolve_ball_ball_collision_2d_two_moving(self):
        # Initialize ball objects
        ball_a = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)
        ball_b = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)

        # A enters from W (270 degrees), contacts B on its left (180 degrees)
        # A enters from E (0 degrees), contacts A on its right (0 degrees)
        # A and B should both reverse their direction
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-0.5, 0.0), Vector(1.0, 0.0), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.5, 0.0), Vector(-1.0, 0.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(-1.0, 0.0)
        b_vel_new = Vector(1.0, 0.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)

        # A enters from W (270 degrees), contacts B on its left (180 degrees)
        # A enters from E (0 degrees), contacts A on its right (0 degrees)
        # A and B should both reverse their direction
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-0.5, 0.0), Vector(1.0, 0.0), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.5, 0.0), Vector(-1.0, 0.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(-1.0, 0.0)
        b_vel_new = Vector(1.0, 0.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)

        """
    def test_resolve_ball_ball_collision_1d_diagonal(self):
        # Initialize ball objects
        ball_a = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)
        ball_b = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)

        # 2-D, stationary target ball
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-1.0, -1.0), Vector(2.0, 2.0), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.0, 0.0), Vector(0.0, 0.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(0.0, 0.0)
        b_vel_new = Vector(2.0, 2.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)

        # 2-D, head-on collision, same speeds
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-1.0, -1.0), Vector(2.0, 2.0), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.0, 0.0), Vector(-2.0, -2.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(-2.0, -2.0)
        b_vel_new = Vector(2.0, 2.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)
    def test_init(self):
        name = '1'
        pos = Coordinates(0, 0)
        mass = 1.0
        radius = 1.0

        p = PoolBall(name, pos, mass, radius)

        self.assertEqual(p.type, name)
        self.assertEqual(p.pos, pos)
        self.assertEqual(p.mass, mass)
        self.assertEqual(p.radius, radius)
        self.assertEqual(p.vel, Vector(0, 0))  # Default should be 0
    def test_check_ball_ball_collision_y_axis(self):
        # Initialize ball objects
        ball_a = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)
        ball_b = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)

        # On x-axis, not touching
        ball_a.pos = Coordinates(0.0, 2.01)
        ball_b.pos = Coordinates(0.0, 0.0)
        result = check_ball_ball_collision(ball_a, ball_b)
        self.assertFalse(result)

        # On x-axis, touching
        ball_a.pos = Coordinates(0.0, 1.00)
        ball_b.pos = Coordinates(0.0, 0.0)
        result = check_ball_ball_collision(ball_a, ball_b)
        self.assertTrue(result)

        # On x-axis, overlapping
        ball_a.pos = Coordinates(0.0, 0.99)
        ball_b.pos = Coordinates(0.0, 0.0)
        result = check_ball_ball_collision(ball_a, ball_b)
        self.assertTrue(result)
Example #7
0
def resolve_ball_ball_collision(a: PoolBall, b: PoolBall):
    """
    Sets new velocity vectors after a ball-ball collision.

    :param a: ball A
    :param b: ball B
    """

    # Taken from https://en.wikipedia.org/wiki/Elastic_collision#Two-dimensional_collision_with_two_moving_objects

    a_vel_new = a.vel - (2 * b.mass) / (a.mass + b.mass) * (
        (a.vel - b.vel).dot_product(a.pos - b.pos)
    ) / get_distance(a.pos - b.pos)**2 * (a.pos - b.pos)
    b_vel_new = b.vel - (2 * a.mass) / (a.mass + b.mass) * (
        (b.vel - a.vel).dot_product(b.pos - a.pos)
    ) / get_distance(b.pos - a.pos)**2 * (b.pos - a.pos)

    a.vel, b.vel = a_vel_new, b_vel_new
    def test_resolve_ball_ball_collision_2d_one_moving(self):
        # Initialize ball objects
        ball_a = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)
        ball_b = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.5)

        # A enters from NW (135 degrees), contacts B on its left (180 degrees)
        # B is stationary, located at origin
        # A should exit S (270 degrees)
        # B should exit E (0 degrees)
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-1.0, 0.0), Vector(1.0, -1.0), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.0, 0.0), Vector(0.0, 0.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(0.0, -1.0)
        b_vel_new = Vector(1.0, 0.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)

        # A enters from 122.3 degrees, contacts B on its left (180 degrees)
        # B is stationary, located at origin
        # A should exit S (270 degrees), with y-component of initial magnitude
        # B should exit E (0 degrees), with x-component of initial magnitude
        mag = 7.14
        ang = 32.3
        ball_a.pos, ball_a.vel, ball_a.mass = Coordinates(-1.0, 0.0), Vector(mag * np.cos(ang), -mag * np.sin(ang)), 3.0
        ball_b.pos, ball_b.vel, ball_b.mass = Coordinates(0.0, 0.0), Vector(0.0, 0.0), 3.0

        resolve_ball_ball_collision(ball_a, ball_b)

        a_vel_new = Vector(0.0, -mag * np.sin(ang))
        b_vel_new = Vector(mag * np.cos(ang), 0.0)

        self.assertVectorAlmostEqual(ball_a.vel, a_vel_new)
        self.assertVectorAlmostEqual(ball_b.vel, b_vel_new)
    def test_check_ball_wall_collision(self):
        n, e, s, w = 1.0, 1.0, -1.0, -1.0

        # Not touching any walls
        ball = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.0), mass=1.0, radius=0.1)
        result = check_ball_wall_collision(ball, n, e, s, w)
        self.assertFalse(result)

        # Touching each wall
        ball_n = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.9), mass=1.0, radius=0.1)
        result_n = check_ball_wall_collision(ball_n, n, e, s, w)
        ball_e = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.9, 0.0), mass=1.0, radius=0.1)
        result_e = check_ball_wall_collision(ball_e, n, e, s, w)
        ball_s = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, -0.9), mass=1.0, radius=0.1)
        result_s = check_ball_wall_collision(ball_s, n, e, s, w)
        ball_w = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.9, 0.0), mass=1.0, radius=0.1)
        result_w = check_ball_wall_collision(ball_w, n, e, s, w)

        self.assertTrue(result_n)
        self.assertTrue(result_e)
        self.assertTrue(result_s)
        self.assertTrue(result_w)

        # Overlapping each wall
        ball_n = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, 0.91), mass=1.0, radius=0.1)
        result_n = check_ball_wall_collision(ball_n, n, e, s, w)
        ball_e = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.91, 0.0), mass=1.0, radius=0.1)
        result_e = check_ball_wall_collision(ball_e, n, e, s, w)
        ball_s = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.0, -0.91), mass=1.0, radius=0.1)
        result_s = check_ball_wall_collision(ball_s, n, e, s, w)
        ball_w = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.91, 0.0), mass=1.0, radius=0.1)
        result_w = check_ball_wall_collision(ball_w, n, e, s, w)

        self.assertTrue(result_n)
        self.assertTrue(result_e)
        self.assertTrue(result_s)
        self.assertTrue(result_w)

        # Touching each corner
        ball_ne = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.9, 0.9), mass=1.0, radius=0.1)
        result_ne = check_ball_wall_collision(ball_ne, n, e, s, w)
        ball_nw = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.9, 0.9), mass=1.0, radius=0.1)
        result_nw = check_ball_wall_collision(ball_nw, n, e, s, w)
        ball_se = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.9, -0.9), mass=1.0, radius=0.1)
        result_se = check_ball_wall_collision(ball_se, n, e, s, w)
        ball_sw = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.9, -0.9), mass=1.0, radius=0.1)
        result_sw = check_ball_wall_collision(ball_sw, n, e, s, w)

        self.assertTrue(result_ne)
        self.assertTrue(result_nw)
        self.assertTrue(result_se)
        self.assertTrue(result_sw)

        # Overlapping each corner
        ball_ne = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.91, 0.91), mass=1.0, radius=0.1)
        result_ne = check_ball_wall_collision(ball_ne, n, e, s, w)
        ball_nw = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.91, 0.91), mass=1.0, radius=0.1)
        result_nw = check_ball_wall_collision(ball_nw, n, e, s, w)
        ball_se = PoolBall(ball_type=BallType.CUE, pos=Coordinates(0.91, -0.91), mass=1.0, radius=0.1)
        result_se = check_ball_wall_collision(ball_se, n, e, s, w)
        ball_sw = PoolBall(ball_type=BallType.CUE, pos=Coordinates(-0.91, -0.91), mass=1.0, radius=0.1)
        result_sw = check_ball_wall_collision(ball_sw, n, e, s, w)

        self.assertTrue(result_ne)
        self.assertTrue(result_nw)
        self.assertTrue(result_se)
        self.assertTrue(result_sw)