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))
Hi
ReplyDeleteTrevor Appleton has code for the AI paddle on his page, using Pygame.
I'm working on adding a second player to his code.
http://trevorappleton.blogspot.ie/2014/04/writing-pong-using-python-and-pygame.html
Thanks for the game code Martin. I am a teacher trying to use it with my Python class. As a non-programmer I am puzzled by the fact that you set properties such as x_vel and y_vel that do not seem to be defined anywhere. Does the Actor class have such properties built-in?
ReplyDeleteI appeared as "unknown" so have replied this time properly logged in :-)
DeleteI am using a feature of Python which allows you to create properties of an object at run time, this is a convenient way for me to associate data which relates to the ball (i.e. its velocity in x and y) to the object itself rather than using global variables which are 'a bit dirty' (imho).
DeleteProperties you can define at runtime! Fantastic! Loving discovering Python. Thanks (Thanks also for your Minecraft book which I own)
Delete