Since writing my blog post explaining how to
Write Pong Using Python and Pygame the guys over at
Webucator (a
Python Training Company) have refactored it to include OOP. They have created an excellent video tutorial on this as part of their new free self-paced "Python Solutions from the Web" course they are developing.
You should definitely check out the video as they really have done an awesome job!
Nat who helped create the tutorial was also kind enough to provide the source code which I have included below, which will help you follow the video.
Enjoy!
import pygame, sys
from pygame.locals import *
# Set up the colours
BLACK = (0,0,0)
WHITE = (255,255,255)
window_width = 400
window_height = 300
display_surf = pygame.display.set_mode((window_width,window_height))
fps_clock = pygame.time.Clock()
fps = 40 # Number of frames per second
class Game():
def __init__(self,line_thickness=10,speed=5):
self.line_thickness = line_thickness
self.speed = speed
self.score = 0
#Initiate variable and set starting positions
#any future changes made within rectangles
ball_x = int(window_width/2 - self.line_thickness/2)
ball_y = int(window_height/2 - self.line_thickness/2)
self.ball = Ball(ball_x,ball_y,self.line_thickness,
self.line_thickness,self.speed)
self.paddles = {}
paddle_height = 50
paddle_width = self.line_thickness
user_paddle_x = 20
computer_paddle_x = window_width - paddle_width - 20
self.paddles['user'] = Paddle(user_paddle_x,
paddle_width, paddle_height)
self.paddles['computer'] = AutoPaddle(computer_paddle_x,
paddle_width, paddle_height,
self.ball, self.speed)
self.scoreboard = Scoreboard(0)
#Draws the arena the game will be played in.
def draw_arena(self):
display_surf.fill((0,0,0))
#Draw outline of arena
pygame.draw.rect(display_surf, WHITE,
((0,0),(window_width,window_height)),
self.line_thickness*2)
#Draw centre line
pygame.draw.line(display_surf, WHITE,
(int(window_width/2),0),
(int(window_width/2),window_height),
int(self.line_thickness/4))
def update(self):
self.ball.move()
self.paddles['computer'].move()
if self.ball.hit_paddle(self.paddles['computer']):
self.ball.bounce('x')
elif self.ball.hit_paddle(self.paddles['user']):
self.ball.bounce('x')
self.score += 1
elif self.ball.pass_computer():
self.score += 5
elif self.ball.pass_player():
self.score = 0
self.draw_arena()
self.ball.draw()
self.paddles['user'].draw()
self.paddles['computer'].draw()
self.scoreboard.display(self.score)
class Paddle(pygame.sprite.Sprite):
def __init__(self,x,w,h):
self.x = x
self.w = w
self.h = h
self.y = int(window_height / 2 - self.h / 2)
#Creates Rectangle for paddle.
self.rect = pygame.Rect(self.x, self.y, self.w, self.h)
#Draws the paddle
def draw(self):
#Stops paddle moving too low
if self.rect.bottom > window_height - self.w:
self.rect.bottom = window_height - self.w
#Stops paddle moving too high
elif self.rect.top < self.w:
self.rect.top = self.w
#Draws paddle
pygame.draw.rect(display_surf, WHITE, self.rect)
#Moves the paddle
def move(self,pos):
self.rect.y = pos[1]
class AutoPaddle(Paddle):
def __init__(self,x,w,h,ball,speed):
super().__init__(x,w,h)
self.ball = ball
self.speed = speed
def move(self):
#If ball is moving away from paddle, center bat
if self.ball.dir_x == -1:
if self.rect.centery < int(window_height/2):
self.rect.y += self.speed
elif self.rect.centery > int(window_height/2):
self.rect.y -= self.speed
#if ball moving towards bat, track its movement.
elif self.ball.dir_x == 1:
if self.rect.centery < self.ball.rect.centery:
self.rect.y += self.speed
else:
self.rect.y -= self.speed
class Ball(pygame.sprite.Sprite):
def __init__(self,x,y,w,h,speed):
self.x = x
self.y = y
self.w = w
self.h = h
self.speed = speed
self.dir_x = -1 ## -1 = left 1 = right
self.dir_y = -1 ## -1 = up 1 = down
self.rect = pygame.Rect(self.x, self.y, self.w, self.h)
#draws the ball
def draw(self):
pygame.draw.rect(display_surf, WHITE, self.rect)
#moves the ball returns new position
def move(self):
self.rect.x += (self.dir_x * self.speed)
self.rect.y += (self.dir_y * self.speed)
#Checks for a collision with a wall, and 'bounces' ball off it.
if self.hit_ceiling() or self.hit_floor():
self.bounce('y')
if self.hit_wall():
self.bounce('x')
def bounce(self,axis):
if axis == 'x':
self.dir_x *= -1
elif axis == 'y':
self.dir_y *= -1
def hit_paddle(self,paddle):
if pygame.sprite.collide_rect(self,paddle):
return True
else:
return False
def hit_wall(self):
if ((self.dir_x == -1 and self.rect.left <= self.w) or
(self.dir_x == 1 and self.rect.right >= window_width - self.w)):
return True
else:
return False
def hit_ceiling(self):
if self.dir_y == -1 and self.rect.top <= self.w:
return True
else:
return False
def hit_floor(self):
if self.dir_y == 1 and self.rect.bottom >= window_height - self.w:
return True
else:
return False
def pass_player(self):
if self.rect.left <= self.w:
return True
else:
return False
def pass_computer(self):
if self.rect.right >= window_width - self.w:
return True
else:
return False
class Scoreboard():
def __init__(self,score=0,x=window_width-150,y=25,font_size=20):
self.score = score
self.x = x
self.y = y
self.font = pygame.font.Font('freesansbold.ttf', font_size)
#Displays the current score on the screen
def display(self,score):
self.score = score
result_surf = self.font.render('Score = %s' %(self.score), True, WHITE)
rect = result_surf.get_rect()
rect.topleft = (self.x, self.y)
display_surf.blit(result_surf, rect)
#Main function
def main():
pygame.init()
pygame.display.set_caption('Pong')
pygame.mouse.set_visible(0) # make cursor invisible
game = Game(speed=4)
while True: #main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# mouse movement commands
elif event.type == MOUSEMOTION:
game.paddles['user'].move(event.pos)
game.update()
pygame.display.update()
fps_clock.tick(fps)
if __name__=='__main__':
main()