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()


\$\endgroup\$
  • 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\$ – Mast Mar 16 at 10:21
  • \$\begingroup\$ @Mast Reviewing the existing code! And trying to address the problems I have outlined \$\endgroup\$ – KOOTS HOOTS Mar 17 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\$ – Reinderien Mar 17 at 13:02
  • 1
    \$\begingroup\$ @Reinderien Will do that now! \$\endgroup\$ – KOOTS HOOTS Mar 18 at 14:09
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.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.