<-- Back to list of examples

"""
 Show how to bounce a ball with a paddle in Pygame.
 This program assumes there are two joysticks plugged in.

 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/
"""
import pygame
import random

black = (0, 0, 0)
white = (255, 255, 255)
blue = (0, 0, 255)


class Player(pygame.sprite.Sprite):
    """ This class represents the paddles on either side of the screen
        It derives from the "Sprite" class in Pygame """

    # Constructor. Pass in the color of the block, and its x and y position
    def __init__(self, x, y, joystick_no):
        # Call the parent class (Sprite) constructor
        super().__init__()

        # Variables to hold the height and width of the block
        self.width = 10
        self.height = 75
        self.my_joystick = None

        # Create an image of the ball, and fill it with a color.
        # This could also be an image loaded from the disk.
        self.image = pygame.Surface([self.width, self.height])
        self.image.fill(white)

        # Fetch the rectangle object that has the dimensions of the image
        self.rect = self.image.get_rect()

        # Set initial position of sprite to 100,100
        self.rect.x = x
        self.rect.y = y

        # Count the joysticks the computer has
        joystick_count = pygame.joystick.get_count()
        if joystick_count < joystick_no+1:
            # No joysticks!
            print("Error, not enough joysticks. Found ", joystick_count)
        else:
            # Use joystick #0 and initialize it
            self.my_joystick = pygame.joystick.Joystick(joystick_no)
            self.my_joystick.init()

    def update(self):
        """ Update the player's position. """
        # As long as there is a joystick
        if self.my_joystick != None:

            # This gets the position of the axis on the game controller
            # It returns a number between -1.0 and +1.0
            vert_axis_pos = self.my_joystick.get_axis(1)

            # Move x according to the axis.
            # We multiply by 10 to speed up the movement.
            self.rect.y = self.rect.y+vert_axis_pos*10

            # If the user moves past the top/bottom of the screen, set the
            # position to the edge.
            if self.rect.y < 0:
                self.rect.y = 0
            if self.rect.y > screen_height - self.height:
                self.rect.y = screen_height - self.height


class Wall(pygame.sprite.Sprite):
    """ This class represents the wall at the top and bottom of the
        screen. """

    # Constructor function
    def __init__(self, x, y, width, height):
        # Call the parent's constructor
        super().__init__()

        # Make a blue wall, of the size specified in the parameters
        self.image = pygame.Surface([width, height])
        self.image.fill((blue))

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x


class Ball(pygame.sprite.Sprite):
    """ This class represents the ball that bounces around. """

    # Set speed vector
    change_x = 0
    change_y = 0
    walls = None

    # Constructor function
    def __init__(self, x, y, walls):
        # Call the parent's constructor
        super().__init__()

        # Set height, width
        self.image = pygame.Surface([15, 15])
        self.image.fill(white)

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

        self.walls = walls

    def update(self):
        """ Updat the ball's position. """
        # Get the old position, in case we need to go back to it
        old_x = self.rect.x
        new_x = old_x + self.change_x
        self.rect.x = new_x

        # Did this update cause us to hit a wall?
        collide = pygame.sprite.spritecollide(self, self.walls, False)
        if collide:
            # Whoops, hit a wall. Go back to the old position
            self.rect.x = old_x
            self.change_x *= -1

        old_y = self.rect.y
        new_y = old_y + self.change_y
        self.rect.y = new_y

        # Did this update cause us to hit a wall?
        collide = pygame.sprite.spritecollide(self, self.walls, False)
        if collide:
            # Whoops, hit a wall. Go back to the old position
            self.rect.y = old_y
            self.change_y *= -1

        if self.rect.x < -20 or self.rect.x > screen_width + 20:
            self.change_x = 0
            self.change_y = 0


# Call this function so the Pygame library can initialize itself
pygame.init()

# Create an 800x600 sized screen
screen_width = 800
screen_height = 600

screen = pygame.display.set_mode([screen_width, screen_height])

# Set the title of the window
pygame.display.set_caption('Test')

# Create a surface we can draw on
background = pygame.Surface(screen.get_size())

# Used for converting color maps and such
background = background.convert()

# Fill the screen with a black background
background.fill(black)

# All sprite lists
wall_list = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
movingsprites = pygame.sprite.Group()

# Create the players
player1 = Player(10, screen_height / 2, 0)
all_sprites.add(player1)
wall_list.add(player1)
movingsprites.add(player1)

player2 = Player(screen_width - 20, screen_height / 2, 1)
all_sprites.add(player2)
wall_list.add(player2)
movingsprites.add(player2)

# Make the walls. (x_pos, y_pos, width, height)
# Top wall
wall = Wall(0, 0, screen_width, 10)
wall_list.add(wall)
all_sprites.add(wall)

# Bottom wall
wall = Wall(0, screen_height - 10, screen_width, screen_height)
wall_list.add(wall)
all_sprites.add(wall)

# Create the ball
ball = Ball(-50, -50, wall_list)
movingsprites.add(ball)
all_sprites.add(ball)

clock = pygame.time.Clock()

done = False

# Main program loop
while not done:

    # Loop through any window events
    for event in pygame.event.get():
        # The user clicked 'close' or hit Alt-F4
        if event.type == pygame.QUIT:
            done = True

        # The user clicked the mouse button
        # or pressed a key
        elif event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.KEYDOWN:

            # Is the ball not moving?
            if ball.change_y == 0:

                # Start in the middle of the screen at a random y location
                ball.rect.x = screen_width / 2
                ball.rect.y = random.randrange(10, screen_height - 0)

                # Set a random vector
                ball.change_y = random.randrange(-5, 6)
                ball.change_x = random.randrange(5, 10)

                # Is the ball headed left or right? Select randomly
                if(random.randrange(2) == 0):
                    ball.change_x *= -1

    # Update the ball position. Pass it the list of stuff it can bounce off of
    movingsprites.update()

    # Clear the screen
    screen.fill(black)

    # Draw the sprites
    all_sprites.draw(screen)

    # Display the screen
    pygame.display.flip()

    clock.tick(30)

# All done, shut down Pygame
pygame.quit()