Exemple #1
0
    def test_calc_new_angle_right_invalid(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation does not calculate a new
        angle when the right of the ball collides but the angle is invalid for
        a right collision.

        Angles are calculated clockwise from the righthand x-axis, so in order
        for a right collision to occur, the ball must be travelling at an angle
        greater than 4.71 or less than 1.57.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            points = [(111.0, 93.0), (111.0, 103.0)]
            return point in points

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 2.32, 8)  # Invalid angle for right collision.
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        # Due to the invalid state, the ball's angle is not recalculated.
        self.assertGreaterEqual(ball.angle, 2.32 - RANDOM_RANGE)
        self.assertLess(ball.angle, 2.32 + RANDOM_RANGE + 0.03)
Exemple #2
0
    def test_clone_ball(self, mock_pygame, mock_load_png):
        self._configure_mocks(mock_pygame, mock_load_png)

        ball = Ball((100, 100), 2.32, 8)

        sprite, bounce, on_collide, offscreen = Mock(), Mock(), Mock(), Mock()
        ball._collidable_sprites.__iter__.return_value = [sprite]

        ball.add_collidable_sprite(sprite,
                                   bounce_strategy=bounce,
                                   speed_adjust=2,
                                   on_collide=on_collide)

        clone = ball.clone(start_pos=(200, 200),
                           start_angle=3.01,
                           base_speed=9,
                           top_speed=14,
                           normalisation_rate=0.3,
                           off_screen_callback=offscreen)

        self.assertEqual(clone._start_pos, (200, 200))
        self.assertEqual(clone._start_angle, 3.01)
        self.assertEqual(clone.base_speed, 9)
        self.assertEqual(clone._top_speed, 14)
        self.assertEqual(clone.normalisation_rate, 0.3)
        self.assertEqual(clone._off_screen_callback, offscreen)
        clone._collidable_sprites.add.assert_has_calls([call(sprite)])
        self.assertEqual(clone._collision_data, ball._collision_data)
Exemple #3
0
    def test_add_collidable_sprite(self, mock_pygame, mock_load_png):
        mock_load_png.return_value = Mock(), Mock()
        mock_sprite, mock_bounce, mock_on_collide = Mock(), Mock(), Mock()

        ball = Ball((100, 100), 2.36, 8)

        ball.add_collidable_sprite(mock_sprite,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.05,
                                   on_collide=mock_on_collide)

        ball._collidable_sprites.add.assert_called_once_with(mock_sprite)
        self.assertEqual(len(ball._collision_data), 1)
Exemple #4
0
    def test_calc_new_angle_all_corners(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the ball collides with all corners of a sprite (is
        effectively inside the sprite).
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        mock_sprite.rect.collidepoint.return_value = True

        ball = Ball((100, 100), 4.01, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertAlmostEqual(ball.angle, 0.87, places=2)
Exemple #5
0
    def test_remove_collidable_sprite_no_exist(self, mock_pygame,
                                               mock_load_png):
        mock_load_png.return_value = Mock(), Mock()
        mock_sprite1, mock_sprite2, mock_bounce, mock_on_collide = (Mock(),
                                                                    Mock(),
                                                                    Mock(),
                                                                    Mock())

        ball = Ball((100, 100), 2.36, 8)

        ball.add_collidable_sprite(mock_sprite2,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.05,
                                   on_collide=mock_on_collide)
        ball.remove_collidable_sprite(mock_sprite1)  # Does not exist.

        ball._collidable_sprites.remove.assert_called_once_with(mock_sprite1)
        self.assertEqual(len(ball._collision_data), 1)
Exemple #6
0
    def test_calc_new_angle_three_corners(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the ball collides with three corners of a sprite.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            points = [(95.0, 94.0), (105.0, 94.0), (95.0, 104.0)]
            return point in points

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 4.01, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertAlmostEqual(ball.angle, 0.87, places=2)
Exemple #7
0
    def test_calc_new_angle_bottom_collision(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the bottom of the ball collides with another sprite.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            points = [(95.0, 115.0), (105.0, 115.0)]
            return point in points

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 2.32, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertGreaterEqual(ball.angle, 3.96 - RANDOM_RANGE)
        self.assertLess(ball.angle, 3.96 + RANDOM_RANGE + 0.03)
Exemple #8
0
    def test_calc_new_angle_single_corner(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the ball collides with a single corner of a sprite.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)

        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            return point == (95.0, 95.0)

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 3.92, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertGreaterEqual(ball.angle, 0.78 - RANDOM_RANGE)
        self.assertLess(ball.angle, 0.78 + RANDOM_RANGE + 0.03)
Exemple #9
0
    def test_calc_new_angle_left_collision_2(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the left of the ball collides with another sprite and
        the current angle is greater than PI.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            points = [(95.0, 94.0), (95.0, 104.0)]
            return point in points

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 4.01, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertGreaterEqual(ball.angle, 5.41 - RANDOM_RANGE)
        self.assertLess(ball.angle, 5.41 + RANDOM_RANGE + 0.03)
Exemple #10
0
    def test_calc_new_angle_right_collision_horizontal(self, mock_pygame,
                                                       mock_load_png):
        """Test that the when the right of the ball bounces at a near
        horizontal angle, that the angle of bounce is adjusted to more that
        what it would naturally be. This is to overcome bounce loops.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            points = [(117.0, 100.0), (117.0, 110.0)]
            return point in points

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 6.25, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertGreaterEqual(ball.angle, 3.52 - RANDOM_RANGE)
        self.assertLess(ball.angle, 3.52 + RANDOM_RANGE + 0.03)
Exemple #11
0
    def test_single_sprite_collision_default(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation is used, the ball speed
        adjusted, and a collision callback invoked when the ball collides with
        a single sprites which does not have an associated ball bounce
        strategy callback.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_on_collide, mock_calc_new_angle = Mock(), Mock()

        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        ball = Ball((100, 100), 2.36, 8)
        ball.add_collidable_sprite(mock_sprite,
                                   speed_adjust=0.5,
                                   on_collide=mock_on_collide)
        ball._calc_new_angle = mock_calc_new_angle
        ball.update()

        self.assertEqual(ball.speed, 8.5)
        mock_on_collide.assert_called_once_with(mock_sprite, ball)
        mock_calc_new_angle.assert_called_once_with([mock_sprite.rect])
Exemple #12
0
    def test_calc_new_angle_corner_oblique_bottom_right_v(
            self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation correctly calculates
        the angle when the ball collides with a single corner of a sprite
        but the angle of collision is vertically oblique against the bottom
        right corner of the ball, rather than head on.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)

        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        def collidepoint(point):
            return point == (115.0, 105.0)  # Bottom left corner

        mock_sprite.rect.collidepoint.side_effect = collidepoint

        ball = Ball((100, 100), 5.5, 8)
        ball.add_collidable_sprite(mock_sprite)
        ball.update()

        self.assertGreaterEqual(ball.angle, 3.92 - RANDOM_RANGE)
        self.assertLess(ball.angle, 3.92 + RANDOM_RANGE + 0.03)
Exemple #13
0
    def test_single_sprite_collision(self, mock_pygame, mock_load_png):
        """Test that a bounce strategy is used, the ball speed adjusted, and
        a collision callback invoked when the ball collides with a single
        sprite.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        mock_bounce, mock_on_collide = Mock(), Mock()

        mock_pygame.sprite.spritecollide.return_value = [mock_sprite]

        mock_bounce.return_value = 2.4

        ball = Ball((100, 100), 2.36, 8)
        ball.add_collidable_sprite(mock_sprite,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.5,
                                   on_collide=mock_on_collide)
        ball.update()

        self.assertEqual(ball.speed, 8.5)
        mock_on_collide.assert_called_once_with(mock_sprite, ball)
        mock_bounce.assert_called_once_with(mock_sprite.rect, ball.rect)
        self.assertEqual(ball.angle, 2.4)
Exemple #14
0
    def test_multiple_sprite_collision(self, mock_pygame, mock_load_png):
        """Test that the default bounce calculation is used, the ball speed
        adjusted, and collision callbacks invoked when the ball collides with
        multiple sprites.
        """
        mock_sprite = self._configure_mocks(mock_pygame, mock_load_png)
        (mock_bounce, mock_on_collide, mock_calc_new_angle, mock_sprite2,
         mock_sprite3) = (Mock(), Mock(), Mock(), Mock(), Mock())

        mock_pygame.sprite.spritecollide.return_value = [
            mock_sprite, mock_sprite2, mock_sprite3
        ]

        mock_bounce.return_value = 3.2

        ball = Ball((100, 100), 2.36, 8, top_speed=9)
        ball.add_collidable_sprite(mock_sprite,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.5,
                                   on_collide=mock_on_collide)
        ball.add_collidable_sprite(mock_sprite2,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.5,
                                   on_collide=mock_on_collide)
        ball.add_collidable_sprite(mock_sprite3,
                                   bounce_strategy=mock_bounce,
                                   speed_adjust=0.5,
                                   on_collide=mock_on_collide)
        ball._calc_new_angle = mock_calc_new_angle
        ball.update()

        self.assertEqual(ball.speed, 9.0)  # Gone up, but not above top speed.
        mock_on_collide.assert_has_calls([
            call(mock_sprite, ball),
            call(mock_sprite2, ball),
            call(mock_sprite3, ball)
        ])
        mock_calc_new_angle.assert_called_once_with(
            [mock_sprite.rect, mock_sprite2.rect, mock_sprite3.rect])