1
votes

I am making a BrickBreaker/Breakout game using pygame. I want my game to create rows of bricks until the a brick hits the paddle but I can't figure out how to do so. Currently it only creates 1 row of bricks. I also want to make the bricks dissappear when the ball hits them. Currently when the bricks are hit they just move off the screen, but I want them to get permanently deleted.

Thanks!

My current code:

# Brick Breaker Game

import pygame
import random

# Initialize the pygame
pygame.init()

# create the screen
screen = pygame.display.set_mode((800, 600))

# background
background = pygame.image.load("realBackground.png")

# Title and Icon
pygame.display.set_caption("Brick Breaker")
icon = pygame.image.load("Brick Breaker Icon.png")
pygame.display.set_icon(icon)

# Paddle
paddleImage = pygame.image.load("scaledPaddle.png")
paddleX = 335
paddleY = 550
paddleX_change = 0

# BrickCoordinates
brickX = []
brickY = []
brickX_change = []
brickY_change = []
numOfBricks = 6

brickXValue = 15
for i in range(numOfBricks):
    brickX.append(brickXValue)
    brickY.append(0)
    brickX_change.append(0.3)
    brickY_change.append(0)
    # Add 120 if thick lines in middle bricks
    # Add 110 if uniform thickness
    brickXValue += 130


#Bricks
yellowBrickImage = pygame.image.load("yellowBrick.png")
greenBrickImage = pygame.image.load("greenBrick.png")
blueBrickImage = pygame.image.load("blueBrick.png")
pinkBrickImage = pygame.image.load("pinkBrick.png")

# ball
ballImage = pygame.image.load("Ball.png")
ballX = 380
ballY = 280
ballX_change = 1.5
ballY_change = 1.5

#Score
scoreValue = 0
font = pygame.font.Font("Neufreit-ExtraBold.otf",24)
textX = 10
textY = 10

def showScore(x,y):
    score = font.render("Score : " + str(scoreValue), True, (255,255,255))
    screen.blit(score,(x,y))

def paddle(x, y):
    screen.blit(paddleImage, (x, y))

def yellowBrick(x, y, i):
    screen.blit(yellowBrickImage, (x, y))

def greenBrick(x, y, i):
    screen.blit(greenBrickImage, (x, y))

def blueBrick(x, y, i):
    screen.blit(blueBrickImage, (x, y))

def pinkBrick(x, y, i):
    screen.blit(pinkBrickImage, (x, y))

def ball(x, y):
    screen.blit(ballImage, (x, y))

#To pick random brick colours
colourOfBrick = []
for i in range(numOfBricks):
    colourOfBrick.append(random.randint(1,4))



# Game Loop (makes sure game is always running)
running = True

while running:
    # To change background colour
    screen.fill((128, 128, 128))
    # background image
    screen.blit(background, (0, 0))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # If keystroke is pressed check whether left or right
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                paddleX_change = -5
            if event.key == pygame.K_RIGHT:
                paddleX_change = 5
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                paddleX_change = 0

    # Checking boudries of paddle
    paddleX += paddleX_change

    if paddleX <= 0:
        paddleX = 0
    elif paddleX >= 669:
        paddleX = 669

    #Draw Rectangles around bricks
    brickRect = []
    for i in range(numOfBricks):
        brickRect.append(pygame.draw.rect(screen, (0, 0, 0), (brickX[i], brickY[i], 120, 42),1))

    # Brick Movement
    for i in range(numOfBricks):
        brickY[i] += brickY_change[i]
        if brickY[i] <= 0:
            brickY_change[i] = 0.3
        elif brickY[i] >= 500:
            brickY_change[i] = -0.3
        # Makes brick show up on screen
        if colourOfBrick[i] == 1:
            yellowBrick(brickX[i], brickY[i], i)
        elif colourOfBrick[i] == 2:
            greenBrick(brickX[i], brickY[i], i)
        elif colourOfBrick[i] == 3:
            blueBrick(brickX[i], brickY[i], i)
        elif colourOfBrick[i] == 4:
            pinkBrick(brickX[i], brickY[i], i)

    # Ball Movement and boundary checking
    ballX += ballX_change

    if ballX <= 0:
        ballX_change *= -1
    elif ballX >= 760:
        ballX_change *= -1

    ballY += ballY_change

    if ballY <= 0:
        ballY_change *= -1
    elif ballY >= 560:
        ballX = 380
        ballY = 280


    # Paddle and Ball Collision
    if ballY > 530 and ballY < 535 and (ballX+20) < paddleX + 131 and (ballX+20) > paddleX:
        ballY_change *= -1

    paddle(paddleX, paddleY)
    ballCircle = pygame.draw.circle(screen, (255,0,0), (int(ballX+20),int(ballY+20)) ,20)
    ball(ballX, ballY)

    #Ball and Brick Collision
    for i in range (numOfBricks):
        if ballCircle.colliderect(brickRect[i]):
            if abs(ballCircle.top - brickRect[i].bottom < 10) and ballY_change < 0:
                brickX[i] = -400
                ballY_change *= -1
                scoreValue += 1

    showScore(textX,textY)
    pygame.display.update()

1
if you want many rows then create nested for-loops - external loop means row, internal loop means brick in current row. And create 2-dimensional list with bricks - so later you can get all_bricks[row][column] - furas
in current version all bricks have brickY.append(0) - you have to create bricks with other value to have more rows. - furas
@furas Thanks for your help, I really appreciate it! - Moneyb

1 Answers

1
votes

In your code all bricks have brickY.append(0) so all bricks are in one row. You have to create bricks with different Y values to create other rows.

You may need nested for-loops for this - like this

row_number = 3

brickYValue = 0

for row in range(row_number):

    brickXValue = 15

    for column in range(numOfBricks):
        brickX.append(brickXValue)

        brickY.append(brickYValue)

        brickX_change.append(0.3)
        brickY_change.append(0)
        brickXValue += 130

    # after `for column`    
    brickYValue += 15  # row height

But it will create more bricks then numOfBricks - you will have numOfBricks*row_number bricks so you would have to change other for-loops and use range(numOfBricks*row_number) instead of range(numOfBricks)

Or you should learn how to use for-loop without range()

brickRect = []

for x, y in zip(brickX, brickY):
    brickRect.append(pygame.draw.rect(screen, (0, 0, 0), x, y, 120, 42),1))

BTW: you should also learn how to use pygame.Rect() to keep size and position of brick, paddle and ball. Rect() has methods to check collisions and you would no need long if ... and ... and ...


EDIT: I added rows in this code but I made many other changes so it may not be good example.

I draw surfaces instead of loading images so everyone can run it without images.

import pygame
import random

# --- classes ---

class Brick():

    def __init__(self, x, y, image):
        self.image = image
        self.rect = self.image.get_rect(x=x, y=y)
        self.x = x
        self.y = y
        self.x_change = 0
        self.y_change = 1

    def draw(self, screen):
        self.rect.x = int(self.x)
        self.rect.y = int(self.y)
        screen.blit(self.image, self.rect)
        pygame.draw.rect(screen, (0, 0, 0), self.rect, 1)

    def update(self):
        self.y += self.y_change
        self.rect.y = int(self.y)

        if self.rect.y <= 0:
            self.y_change = 1
        elif self.rect.y >= 500:
            self.y_change = -1

class Ball():

    def __init__(self):
        #self.image = pygame.image.load("Ball.png")

        self.image = pygame.Surface((16, 16)).convert_alpha()
        self.image.fill((0,0,0,0)) # transparent background
        pygame.draw.circle(self.image, (255,255,255), (8, 8), 8)

        self.rect = self.image.get_rect(centerx=380, centery=280)
        self.x = 380
        self.y = 280
        self.x_change = 3
        self.y_change = 3

    def reset(self):
        self.x = 380
        self.y = 280

    def draw(self, screen):
        self.rect.centerx = int(self.x)
        self.rect.centery = int(self.y)
        screen.blit(self.image, self.rect)

    def update(self):
        # Ball Movement and boundary checking
        self.x += self.x_change
        self.rect.centerx = int(self.x)

        if self.rect.left <= 0:
            self.x_change *= -1
        elif self.rect.right >= 800:
            self.x_change *= -1

        self.y += self.y_change
        self.rect.centery = int(self.y)

        if self.rect.top <= 0:
            self.y_change *= -1
        elif self.rect.bottom >= 600:
            self.reset()

class Paddle():

    def __init__(self):
        #self.image = pygame.image.load("scaledPaddle.png")
        self.image = pygame.Surface((100, 30))
        self.image.fill((255,0,0))

        self.rect = self.image.get_rect(x=335, y=550)
        self.x_change = 0
        self.y_change = 0

    def reset(self):
        self.rect.x = 335
        self.rect.y = 550

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def update(self):
        # Checking boudries of paddle
        self.rect.x += self.x_change

        if self.rect.left <= 0:
            self.rect.left = 0
        elif self.rect.right >= 800:
            self.rect.right = 800

class Score():

    def __init__(self):
        #self.font = pygame.font.Font("Neufreit-ExtraBold.otf", 24)
        self.font = pygame.font.SysFont(None, 24)
        self.value = 0
        self.x = 10
        self.y = 10

    def reset(self):
        self.value = 0

    def draw(self, screen):
        self.image = self.font.render("Score : " + str(self.value), True, (255,255,255))
        self.rect = self.image.get_rect(x=self.x, y=self.y)
        screen.blit(self.image, self.rect)

# --- functions ---

# empty

# --- main ---

pygame.init()
screen = pygame.display.set_mode((800, 600))

pygame.display.set_caption("Brick Breaker")
#icon = pygame.image.load("Brick Breaker Icon.png")
#pygame.display.set_icon(icon)

# Background Image

#background_image = pygame.image.load("realBackground.png")

background_image = pygame.Surface((800,600))
for y in range(5, 600, 25):
    for x in range(5, 800, 25):
        color = random.choice([(255,128,128), (128,255,128), (128,128,255)])
        background_image.fill(color, [x,y,15,15])

# Brick Images

#brick_images = [
#    pygame.image.load("yellowBrick.png"),
#    pygame.image.load("greenBrick.png"),
#    pygame.image.load("blueBrick.png"),
#    pygame.image.load("pinkBrick.png"),
#]

brick_images = [
    pygame.Surface((100, 30)),
    pygame.Surface((100, 30)),
    pygame.Surface((100, 30)),
    pygame.Surface((100, 30)),
    pygame.Surface((100, 30)),
    pygame.Surface((100, 30)),
]    

brick_images[0].fill((255,0,0))
brick_images[1].fill((0,255,0))
brick_images[2].fill((0,0,255))
brick_images[3].fill((255,255,0))
brick_images[4].fill((255,0,255))
brick_images[5].fill((0,255,255))

# Objects

paddle = Paddle()
ball   = Ball()
score  = Score()

# bricks
rows_number = 5
cols_number = 7

all_bricks = []

y = 0
for row in range(rows_number):
    x = 50
    for col in range(cols_number):
        color_image = random.choice(brick_images)
        brick = Brick(x, y, color_image)
        all_bricks.append(brick)
        x += 100
    y += 30

# Game Loop

clock = pygame.time.Clock()
running = True

while running:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # If keystroke is pressed check whether left or right
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                paddle.x_change = -5
            if event.key == pygame.K_RIGHT:
                paddle.x_change = 5
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                paddle.x_change = 0

    # --- updates ---

    paddle.update()
    ball.update()

    # Bricks Update
    for brick in all_bricks:
        brick.update()

    # Ball and Paddle Collision
    if ball.rect.colliderect(paddle):
        ball.y_change *= -1

    # Ball and Bricks Collision
    for brick in all_bricks:
        if ball.rect.colliderect(brick):
            brick.x = -400
            ball.y_change *= -1
            score.value += 1

    # --- draws ---

    # To change background colour
    # screen.fill((128, 128, 128)) # you don't need it if background fill all screen

    # background image
    screen.blit(background_image, (0, 0))

    for brick in all_bricks:
        brick.draw(screen)

    paddle.draw(screen)
    ball.draw(screen)

    score.draw(screen)

    pygame.display.flip()

    clock.tick(60) # 60 FPS (Frames Per Second) on all computers

# --- end ---

pygame.quit() 

enter image description here