12
\$\begingroup\$

This is my first time trying OOP and I definitely made many stylistic mistakes. Please tell me how I should improve.

Controls:

  • w and s for player 1
  • and for player 2

The player with higher score has shorter paddle. Once the difference in score is bigger than 7, the game quits.

import pygame
import random

YELLOW = (255, 255, 100)
BLUE = (50, 50, 255)
RED = (255, 50, 50)
BLACK = (0, 0, 0)
WHITE = (255,255,255)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
PADDLE_HEIGHT = 100
done = False

class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y, xspeed, yspeed):
        super().__init__()
        self.image = pygame.Surface((16,16))
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x
        self.rect.y = y
        pygame.draw.circle(self.image,YELLOW,(8,8),8)
        self.speed_x = xspeed
        self.speed_y = yspeed
        self.deathcount_left = None
        self.deathcount_right = None
        self.walls = None
        self.index = 0
    def checkdeath(self):
        if self.rect.x<0:
            self.deathcount_left.plus()
            self.rect.x = self.x
            self.rect.y = self.y
            self.speed_x = random.randint(8,12)
            self.speed_y = random.randint(8,12)
        elif self.rect.x>SCREEN_WIDTH:
            self.deathcount_right.plus()
            self.rect.x = self.x
            self.rect.y = self.y
            self.speed_x = random.randint(10,12)
            self.speed_y = random.randint(10,12)                                        

    def update(self):
        self.checkdeath()
        self.rect.x += self.speed_x
        wall_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        if self.index == 1:
            self.rect.y+=self.speed_y
            self.index = 0
        else:
            if wall_hit_list:
                self.speed_x = -self.speed_x
                self.rect.y += self.speed_y
            else:
                self.rect.y += self.speed_y
                wall_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
                if wall_hit_list:
                    self.speed_y = -self.speed_y
                    self.index=1


class Wall(pygame.sprite.Sprite):
    def __init__ (self, x, y, width, height):
        super().__init__()
        self.width = width
        self.height = height
        self.x = x
        self.y = y
        self.image = pygame.Surface([self.width, self.height])
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

class Paddle(Wall):
    def __init__ (self,x, y, width, height):
        super().__init__(x, y, width, height)
        self.walls = None
        self.speed = 0
        self.my_score = None
        self.my_enemy = None
    def changespeed(self, change):
        self.speed+=change
    def changelength(self):
        self.height = self.my_score.lengthcal(self.my_enemy)
        self.image = pygame.Surface([self.width, self.height])
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.x = self.x
        self.rect.y = self.y
    def update(self):
        self.y += self.speed
        self.changelength()
        wall_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        for wall in wall_hit_list:
            if self.speed>0:
                self.y = wall.rect.top - self.height
            else:
                self.y = wall.rect.bottom

class Score():
    def __init__(self, x, y,color):
        self.score = 0
        self.color = color
        self.x = x
        self.y = y
    def plus(self):
        self.score += 1
    def lengthcal(self, enemy):
        if self.score <= enemy.my_score.score:
            return PADDLE_HEIGHT
        else:
            return PADDLE_HEIGHT-(self.score-enemy.my_score.score)*10

    def draw(self):
        font = pygame.font.SysFont(None,32)
        self.image = font.render(str(self.score), True, self.color, BLACK)
        self.rect = self.image.get_rect()
        self.rect.x = self.x
        self.rect.y = self.y
        screen.blit(self.image, self.rect)

pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption('Pong')

all_sprite_list = pygame.sprite.Group()
all_wall_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
empty_list = pygame.sprite.Group()

wall = Wall(0, 0, SCREEN_WIDTH, 10)
wall_list.add(wall)
all_wall_list.add(wall)
all_sprite_list.add(wall)
wall.walls = empty_list

wall = Wall(0, SCREEN_HEIGHT-10, SCREEN_WIDTH, 10)
wall_list.add(wall)
all_wall_list.add(wall)
all_sprite_list.add(wall)
wall.walls = empty_list

score_left = Score(190, 30, WHITE)
score_right = Score(590, 30, WHITE)

paddle_left = Paddle(50, 350, 10, PADDLE_HEIGHT)
paddle_right = Paddle(SCREEN_WIDTH-50, 350, 10, PADDLE_HEIGHT)

all_wall_list.add(paddle_left)
all_sprite_list.add(paddle_left)
paddle_left.my_score = score_right
paddle_left.my_enemy = paddle_right


all_wall_list.add(paddle_right)
all_sprite_list.add(paddle_right)
paddle_right.my_score = score_left
paddle_right.my_enemy = paddle_left

ball = Ball(400,300,14,9)
all_sprite_list.add(ball)

paddle_left.walls = wall_list
paddle_right.walls = wall_list
ball.walls = all_wall_list
ball.deathcount_left = score_left
ball.deathcount_right = score_right

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                paddle_right.changespeed(-8)
            elif event.key == pygame.K_DOWN:
                paddle_right.changespeed(8)
            elif event.key == pygame.K_w:
                paddle_left.changespeed(-8)
            elif event.key == pygame.K_s:
                paddle_left.changespeed(8)

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                paddle_right.changespeed(8)
            elif event.key == pygame.K_DOWN:
                paddle_right.changespeed(-8)
            elif event.key == pygame.K_w:
                paddle_left.changespeed(8)
            elif event.key == pygame.K_s:
                paddle_left.changespeed(-8)

    all_sprite_list.update()
    if paddle_left.height<30 or paddle_right.height<30:
        break
    screen.fill(BLACK)
    score_left.draw()
    score_right.draw()
    all_sprite_list.draw(screen)
    pygame.display.flip()

pygame.quit()
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

This is a short and very incomplete list of some small things that could be done differently:

  • Be wary of initializing things to None; it can produce some annoying bugs later on where Python yells at you for using a Nonetype where it expects something else:

    # In Ball
    self.walls = pygame.sprite.Group()
    self.deathcount_left = Score(...)
    self.deathcount_right = Score(...)
    ...
    # In Paddle
    self.my_score = ball.deathcount_left
    self.enemy_score = ball.deathcount_right
    

Alternately, you could add to the constructor for Paddle to take in 2 Scores--yours and the enemy's.

  • Do you intend for anything other than Paddle to inherit from Wall? If not, you don't need Wall at all because Wall.__init__ is only ever called in Paddle.__init__. Though not totally necessary, you could do away with Wall and copy over its constructor into Paddle's, though some might cringe at the length of the result.

I'm hesitant to add any more for fear of misleading you, but OOP aside, some small stylistic notes:

  • It's generally considered good practice to leave some sort of comment describing your classes/functions/etc., if only so that as your work expands you don't have to read code to figure out what a function does.

Ball.update:

  • You can move self.rect.y += self.speed_y just below self.rect.x += self.speed_x--it occurs regardless of the condition.
  • Instead of using a nested if statement (if self.index == 1 etc.) you can rewrite with elif

    if self.index == 1:
        self.index = 0
    elif wall_hit_list:
        self.speed_x *= -1
    else:
        wall_hit_list = ...
        if wall_hit_list:
            self.speed_y *= -1
            self.index = 1
    
\$\endgroup\$

Your Answer

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

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