Junaid Patel
Junaid Patel

Reputation: 11

Brick Breaker game help, ball bouncing side to side

I've completed a small game project of the breakout game, but my main problem is that the ball seems to get stuck going side to side much more often than i would be okay with it happening. It's definitely a problem with the ball velocity and I've tried messing around with the numbers but I can't seem to make it stop getting stuck. Any ideas on how to fix it ,or even improve any of the code, would be greatly appreciated.

import sys
import pygame as pg
from random import randint

black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
score = 0
lives = 3


def run_game():
    pg.init()

    screen = pg.display.set_mode((800,600))
    pg.display.set_caption("Brick Breaker")
    bg_color = (0, 0, 0)
    screen.fill(bg_color)

    class Paddle(pg.sprite.Sprite):
        def __init__(self, color, width, height):
            super().__init__()
            self.image = pg.Surface([width, height])
            self.image.fill(black)
            self.image.set_colorkey(black)
            pg.draw.rect(self.image, color, [0, 0, width, height])
            self.rect = self.image.get_rect()
        def moveLeft(self,pixels):
            self.rect.x -= pixels
            if self.rect.x < 0:
                self.rect.x = 0
        def moveRight(self,pixels):
            self.rect.x += pixels
            if self.rect.x > 700:
                self.rect.x = 700

    class Ball(pg.sprite.Sprite):
        def __init__(self, color, width, height):
            super().__init__()
            self.image = pg.Surface([width, height])
            self.image.fill(black)
            self.image.set_colorkey(black)
            pg.draw.rect(self.image, color, [0, 0, width, height])
            self.velocity = [randint(4,8),randint(-8,8)]
            self.rect = self.image.get_rect()
        def update(self):
            self.rect.x += self.velocity[0]
            self.rect.y += self.velocity[1]
        def bounce(self):
            self.velocity[0] = -self.velocity[0]
            self.velocity[1] = randint(-8,10)

    class Brick(pg.sprite.Sprite):
        def __init__(self, color, width, height):
            super().__init__()
            self.image = pg.Surface([width, height])
            self.image.fill(black)
            self.image.set_colorkey(black)
            pg.draw.rect(self.image, color, [0, 0, width, height])
            self.rect = self.image.get_rect()

    clock = pg.time.Clock()

    all_sprites_list = pg.sprite.Group()
    paddle = Paddle(white,100,10)
    paddle.rect.x = 350
    paddle.rect.y = 560
    ball = Ball(white,10,10)
    ball.rect.x = 345
    ball.rect.y = 195
    all_bricks = pg.sprite.Group()
    for i in range(7):
        brick = Brick(red,80,30)
        brick.rect.x = 60 + i* 100
        brick.rect.y = 60
        all_sprites_list.add(brick)
        all_bricks.add(brick)
    for i in range(7):
        brick = Brick(blue,80,30)
        brick.rect.x = 60 + i* 100
        brick.rect.y = 100
        all_sprites_list.add(brick)
        all_bricks.add(brick)
    for i in range(7):
        brick = Brick(green,80,30)
        brick.rect.x = 60 + i* 100
        brick.rect.y = 140
        all_sprites_list.add(brick)
        all_bricks.add(brick)
    all_sprites_list.add(paddle)
    all_sprites_list.add(ball)

    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                sys.exit()

        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            paddle.moveLeft(10)
        if keys[pg.K_RIGHT]:
            paddle.moveRight(10)

        all_sprites_list.update()

        if ball.rect.x>=790:
            ball.velocity[0] = -ball.velocity[0]
        if ball.rect.x<=0:
            ball.velocity[0] = -ball.velocity[0]
        if ball.rect.y>590:
            ball.velocity[1] = -ball.velocity[1]
            global lives
            lives-=1
            if lives == 0:
                font = pg.font.Font(None, 74)
                text = font.render("YOU LOSE", 1, red)
                screen.blit(text,(280,250))
                pg.display.flip()
                sys.exit()
        if ball.rect.y<40:
            ball.velocity[1] = -ball.velocity[1]
        if pg.sprite.collide_mask(ball, paddle):
            ball.rect.x -= ball.velocity[0]
            ball.rect.y -= ball.velocity[1]
            ball.bounce()

        brick_collision_list = pg.sprite.spritecollide(ball,all_bricks,False)
        for brick in brick_collision_list:
          ball.bounce()
          brick.kill()
          if len(all_bricks)==0:
            font = pg.font.Font(None, 74)
            text = font.render("YOU WIN", 1, green)
            screen.blit(text,(280,250))
            pg.display.flip()
            sys.exit()

        screen.fill(black)
        font = pg.font.Font(None, 40)
        text = font.render("lives: " + str(lives), 1, white)
        screen.blit(text, (10,10))

        all_sprites_list.draw(screen)
        pg.display.flip()
        clock.tick(50)
run_game()

Upvotes: 1

Views: 641

Answers (1)

Rabbid76
Rabbid76

Reputation: 210968

When the ball hits the paddle, then set the bottom of the ball to the top of the paddle. It is not necessary to change the direction of the ball, because it's direction is changed in ball.bounce()

if pg.sprite.collide_mask(ball, paddle):
    ball.rect.bottom = paddle.rect.top 
    #ball.rect.x -= ball.velocity[0]
    #ball.rect.y -= ball.velocity[1]
    ball.bounce() 

In Ball.bounce invert the y direction of the ball and compute a new random x direction:

class Ball(pg.sprite.Sprite):
    def __init__(self, color, width, height):
        # [...]

        self.velocity = [randint(-8,8), randint(4,8)]

    def bounce(self):
        # invert y
        self.velocity[1] = -self.velocity[1]

        # either random x
        # self.velocity[0] = randint(-8, 8)

        # or slightly changed x
        self.velocity[0] = max(-8, min(8, self.velocity[0] + randint(-3, 3)))

Upvotes: 1

Related Questions