1
\$\begingroup\$

Hi I have written the following code in Python. Any improvements on my code will be appreciated as this is my first shot at pygame!

There are some problems in terms of functionality, to state briefly ball sometimes gets stuck within a paddle, which I am continuing to resolve

import pygame, sys
import random
from math import degrees, radians, sin, cos
pygame.init()
# Create a screen
win = pygame.display.set_mode((800,700))
win_info = pygame.display.Info()
win_w, win_h = win_info.current_w, win_info.current_h
pygame.display.set_caption("Pong")
pad_colour = (255,255,255) #White colour
pad_distance = 50
speed = 10
running = True
fps = 30
#############################################################################
class border(pygame.sprite.Sprite):
 width = win_w
 height = 10
 def __init__(self,width, height, colour):
 pygame.sprite.Sprite.__init__(self)
 self.image = pygame.Surface((width,height))
 self.image.fill(colour)
 self.rect = self.image.get_rect()
 def draw(self):
 win.blit(self.image, self.rect)
#############################################################################
class paddle(pygame.sprite.Sprite):
 """left arg refer to top left corner coordinate of paddle
 """
 def __init__(self,width, height, speed, colour):
 pygame.sprite.Sprite.__init__(self)
 self.width = width
 self.height = height
 self.image = pygame.Surface([width, height])
 self.image.fill(colour)
 self.speed = speed
 self.vel_x = 0
 self.vel_y = 0
 # Size of rectangle
 self.rect = self.image.get_rect()
 def move(self, x, y):
 self.rect.move_ip(x,y)
 def moveTo(self, x, y):
 self.rect.topleft = (x,y)
 def draw(self):
 win.blit(self.image, (self.rect.x,self.rect.y))
#############################################################################
class ball(pygame.sprite.Sprite):
 """ Facing takes 1 or -1 to determine direction of movement
 """
 def __init__(self, radius, factor, colour):
 pygame.sprite.Sprite.__init__(self)
 self.image = pygame.Surface([radius*2, radius*2])
 pygame.draw.circle(self.image, colour, (radius,radius), radius)
 self.rect = self.image.get_rect()
 # Replace facing when finalising implementation of ball
 self.facing = -1
 self.factor = factor
 self.vel_x, self.vel_y = self.randomMovement(factor)
 def move(self, x,y):
 self.rect.move_ip(x,y)
 def moveTo(self, x, y):
 self.rect.center = (x,y)
 def collidePad(self):
 self.vel_x = self.vel_x * -1
 def draw(self):
 win.blit(self.image, (self.rect))
 def randomMovement(self,factor=None):
 #unit vector
 if factor == None:
 # Used for all calls after ball instance is initialised
 factor = self.factor
 angle = radians(random.randint(30,80))
 rand_y = random.randrange(-1,2,2)
 y = sin(angle)
 x = cos(angle)
 """ How to get over the use of int and rounding errors. Using int the line before causes the vector to be 0,0 as the numbers after 0 are truncated"""
 self.vel_x, self.vel_y = (int(x*factor),int(y*factor)*rand_y)
 #print(x, y)
 return self.vel_x, self.vel_y
#############################################################################
# Main Game Loop
def main():
 white = (255,255,255)
 border_height = 10
 pad_width = int(win_w/50)
 pad_height = int(win_h/6)
 pad_left = paddle(pad_width, pad_height, speed, white)
 pad_right = paddle(pad_width, pad_height, speed, white)
 # Set X and Y of left pad
 pad_left.rect.topleft = (pad_distance, int((win_h-pad_height)/2))
 # Set X and Y of right pad
 pad_right.rect.topleft = ((win_w-pad_distance-pad_width), int((win_h-pad_height)/2))
 top_border = border(win_w, border_height, white)
 top_border.rect.topleft = (0, 0)
 bottom_border = border(win_w, border_height, white)
 bottom_border.rect.topleft = (0, win_h-border_height)
 gameBall = ball(10, 10, white)
 gameBall.rect.center = (int(win_w/2), int(win_h/2))
 to_draw = [pad_left, pad_right, top_border, bottom_border, gameBall]
 redrawGameWin(to_draw)
 backGround = pygame.Surface((win_w,win_h))
 backGround.fill(white)
 clock = pygame.time.Clock()
 # Game Loop
 while running:
 clock.tick(fps)
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.display.quit()
 pygame.quit()
 sys.exit()
 keys = pygame.key.get_pressed()
 # Left pad moving up with top boundary collision
 if keys[pygame.K_s] and pad_left.rect.y > 0:
 if pad_left.rect.y - top_border.height - pad_left.speed <= 0 :
 pad_left.vel_y = 0
 pad_left.moveTo(pad_distance, top_border.height)
 else:
 pad_left.vel_y = -pad_left.speed
 pad_left.move(0, pad_left.vel_y)
 # Left pad moving down with bottom boundary collision
 if keys[pygame.K_x]:
 if pad_left.rect.y + pad_left.height + pad_left.speed + bottom_border.height >= win_h:
 pad_left.vel_y = 0
 pad_left.moveTo(pad_distance, win_h-pad_left.height-bottom_border.height)
 else:
 pad_left.vel_y = pad_left.speed
 pad_left.move(0, pad_left.speed)
 if not keys[pygame.K_s] and not keys[pygame.K_x]:
 pad_left.vel_x, pad_left.vel_y = 0,0
 # Right pad moving up with top boundary collision
 if keys[pygame.K_k]:
 if pad_right.rect.y - top_border.height - pad_right.speed <= 0:
 pad_right.vel_y = 0
 pad_right.moveTo(win_w-pad_distance-pad_right.width, top_border.height)
 else:
 pad_right.vel_y = -pad_right.speed
 pad_right.move(0, pad_right.vel_y)
 # Right pad moving down with bottom boundary collision
 if keys[pygame.K_m]:
 if pad_right.rect.y + pad_right.height + pad_right.speed + bottom_border.height >= win_h:
 pad_right.vel_y = 0
 pad_right.moveTo(win_w-pad_distance-pad_right.width, win_h-pad_right.height-bottom_border.height)
 else:
 pad_right.vel_y = pad_right.speed
 pad_right.move(0, pad_right.vel_y)
 if not keys[pygame.K_k] and not keys[pygame.K_m]:
 pad_right.vel_x, pad_right.vel_y = 0,0
 # Ball bouncing off top border
 if gameBall.rect.colliderect(top_border.rect) or gameBall.rect.colliderect(bottom_border.rect):
 gameBall.vel_y = gameBall.vel_y*-1
 # Ball bouncing off right pad
 if gameBall.rect.colliderect(pad_right.rect):
 gameBall.vel_x = -(gameBall.vel_x + pad_right.vel_x)
 gameBall.vel_y = gameBall.vel_y + pad_right.vel_y
 # Ball bouncing off left pad
 if gameBall.rect.colliderect(pad_left.rect):
 gameBall.vel_x = -(gameBall.vel_x + pad_left.vel_x)
 gameBall.vel_y = gameBall.vel_y + pad_left.vel_y
 # Ball moving by velocity vector
 gameBall.move(gameBall.vel_x, gameBall.vel_y)
 # Ball moves off screem
 if gameBall.rect.left >= win_w or gameBall.rect.right <=0:
 gameBall.randomMovement()
 gameBall.moveTo(int(win_w/2), int(win_h/2))
 redrawGameWin(to_draw) 
#############################################################################
def redrawGameWin(shapes):
 #global dirty_rects
 win.fill((0,0,0))
 for shape in shapes:
 shape.draw()
 pygame.display.flip()
#############################################################################
if __name__ == "__main__":
 main()
asked Mar 16, 2020 at 9:21
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Welcome to Code Review! Are you interested in adding features to your code or in reviewing the existing code? Please read the help center before answering that. \$\endgroup\$ Commented Mar 16, 2020 at 10:21
  • \$\begingroup\$ @Mast Reviewing the existing code! And trying to address the problems I have outlined \$\endgroup\$ Commented Mar 17, 2020 at 8:00
  • \$\begingroup\$ Reviewing the existing code is on topic for here but addressing that list of problems is not. You should likely edit the question to indicate that there are some functional problems but they will be addressed separately on stack overflow. \$\endgroup\$ Commented Mar 17, 2020 at 13:02
  • 1
    \$\begingroup\$ @Reinderien Will do that now! \$\endgroup\$ Commented Mar 18, 2020 at 14:09

1 Answer 1

1
\$\begingroup\$

Global code

This stuff:

pygame.init()
# Create a screen
win = pygame.display.set_mode((800,700))
win_info = pygame.display.Info()
win_w, win_h = win_info.current_w, win_info.current_h
pygame.display.set_caption("Pong")

should be moved into one or more functions. These:

pad_colour = (255,255,255) #White colour
pad_distance = 50
speed = 10
running = True
fps = 30

can probably stay in global scope as ALL_CAPS constants.

Class names

border should be Border since it's a class name. The same goes for Paddle.

Statics

class border(pygame.sprite.Sprite):
 width = win_w
 height = 10
 def __init__(self,width, height, colour):

I don't think that the first width/height variables do what you think they do. Currently they can be deleted. If you want them to take effect as defaults, then you'd actually write

class border(pygame.sprite.Sprite):
 def __init__(self, colour, width=win_w, height=10):

Method names

should be snake_case, i.e.

random_movement, collide_pad, etc.

Don't repeat yourself

The code to check the left/right pad is very repetitive. Think about what is shared and what differs, and factor out the differing stuff. So far as I can see, the differences include the references to the key constants K_s, some distance calculations, etc.

answered Mar 21, 2020 at 16:28
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.