← all posts

Pygame Zero - Pong

I wanted to explore Pygame Zero so I gave myself a challenge of creating a version of Pong.

My first piece of learning from the experience just reconfirms something I already knew - games development is hard! Pygame Zero takes some of the pain and is certainly a lot easier to get started with than Pygame, but there is still a lot of work to do for game like Pong.

The second thing I learnt is that I didn’t know how Pong worked! This page which describes how the balls reacts when it hits a paddle is really useful.

You will find all the code on github https://github.com/martinohanlon/pgzero-pong.

You control the paddles with Q A (player 1) and K M (player 2).

Its very much unfinished and is missing features like:

  • Time limit - the game continues forever
  • Scores - the score should be displayed on the screen
  • 1 player mode - artificial intelligent 2nd player

Does anyone fancy picking it up?

Code

from math import sin, cos, radians
from time import sleep

#setup the constants
WIDTH = 500
HEIGHT = 300
BALLSPEED = 10
PADDLESPEED = 5
MAXBOUNCEANGLE = 75

def reset_game(angle):

    #setup ball properties
    ball.pos = WIDTH / 2, HEIGHT / 2
    ball.x_float = float(ball.x)
    ball.y_float = float(ball.y)
    ball.angle = angle
    ball.x_vel = BALLSPEED * cos(radians(ball.angle))
    ball.y_vel = BALLSPEED * sin(radians(ball.angle))

    #position the paddles
    pad1.pos = 10, HEIGHT / 2
    pad2.pos = WIDTH - 10, HEIGHT / 2

#create a rectangle of the playing area
screenRect = Rect(10,0,WIDTH - 10,HEIGHT)

#create ball
ball = Actor('ball')

#create paddles
pad1 = Actor('paddle')
pad2 = Actor('paddle')

#reset the game
reset_game(180)

#setup the goals
goals = [0, 0]

def draw():
    screen.clear()
    ball.draw()
    pad1.draw()
    pad2.draw()

def update():

    #move the paddles
    if keyboard.q:
        pad1.top -= PADDLESPEED
    if keyboard.a:
        pad1.top += PADDLESPEED
    if keyboard.k:
        pad2.top -= PADDLESPEED
    if keyboard.m:
        pad2.top += PADDLESPEED

    #move the ball
    ball_old_x = ball.x_float
    ball_old_y = ball.y_float

    ball.x_float = ball.x_float + ball.x_vel
    ball.y_float = ball.y_float + ball.y_vel
    ball.x = int(round(ball.x_float))
    ball.y = int(round(ball.y_float))

    #move the ball back to where it was?
    reset_ball = False

    #has the ball left the screen?
    if not screenRect.contains(ball):

        #did it hit the top or bottom?
        if ball.top < 0 or ball.bottom > HEIGHT:
            ball.y_vel *= -1
            reset_ball = True

        #it must have hit the side
        else:
            if ball.left < 10:
                print("Player 2 goal")
                goals[1] += 1
                reset_game(180)
                sleep(2)
                print("Score {} : {}".format(goals[0], goals[1]))

            elif ball.right > WIDTH - 10:
                print("player 1 goal")
                goals[1] += 1
                reset_game(0)
                sleep(2)
                print("Score {} : {}".format(goals[0], goals[1]))

    #has the ball hit a paddle
    if pad1.colliderect(ball):
        #work out the bounce angle
        bounce_angle = ((ball.y - pad1.y) / (pad1.height / 2)) * MAXBOUNCEANGLE
        ball.angle = max(0 - MAXBOUNCEANGLE, min(MAXBOUNCEANGLE, bounce_angle))
        #work out the ball velocity
        ball.x_vel = BALLSPEED * cos(radians(ball.angle))
        ball.y_vel = BALLSPEED * sin(radians(ball.angle))

        reset_ball = True

    elif pad2.colliderect(ball):
        bounce_angle = 180 - (((ball.y - pad2.y) / (pad2.height / 2)) * MAXBOUNCEANGLE)
        ball.angle = max(180 - MAXBOUNCEANGLE, min(180 + MAXBOUNCEANGLE, bounce_angle))
        ball.x_vel = BALLSPEED * cos(radians(ball.angle))
        ball.y_vel = BALLSPEED * sin(radians(ball.angle))

        reset_ball = True

    if reset_ball:
        ball.x_float = ball_old_x
        ball.y_float = ball_old_y
        ball.x = int(round(ball.x_float))
        ball.y = int(round(ball.y_float))