2

I recently started making Atari Breakout in Pygame. I encountered a problem that I don't know how to fix. Whenever I run my code, and the ball comes in contact with the block, the block that's colliding with it, doesn't disappear as it should, but the last block from the list. (I made a list of 21 pygame.Surfaces and iterate over it and blit every single one). Obviously, if the ball touches the last block from the list, the correct one disappears. Please can you help me?

This is my code:

import pygame, random, math

pygame.init()

screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('Atari Breakout')

player = pygame.image.load('player copy.png')
ball = pygame.image.load('poland.png')
blocks = [pygame.image.load('block.png') for i in range(21)]


x, y = 25,25
blockx, blocky = [], []
for i in range(21):
    if i % 7 == 0:
        y += 52
        x = 25
    blockx.append(x)
    blocky.append(y)
    x += (50 + 64)

ballx, bally = 400, 300

balldx, balldy = 4,4

score = 0
score_font = pygame.font.Font('freesansbold.ttf', 32)

def show_score():
    score_text = score_font.render('Score : {}'.format(score), True, (255,255,255))
    screen.blit(score_text, (0,0))

def isCollision(x1,y1,x2,y2):
    ballRect = ball.get_rect(topleft = (x1, y1))
    playerRect = player.get_rect(topleft = (x2, y2))
    return ballRect.colliderect(playerRect)

def isCollision2(x1,y1,x2,y2):
    ballRect = ball.get_rect(topleft = (x1,y1))
    blockRect = blocks[i].get_rect(topleft = (x2,y2))
    return ballRect.colliderect(blockRect)

def blit_blocks():
    for i in range(len(blocks)):
        screen.blit(blocks[i], (blockx[i], blocky[i]))
running = True

while running:

    if score >= 21:
        running = False
    screen.fill((0,0,0))


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

    pos = pygame.mouse.get_pos()

    for i, block in enumerate(blocks):

        if isCollision2(ballx, bally, blockx[i], blocky[i]):
            balldy *= -1
            score += 1
            blocks.pop(i)

    if isCollision(ballx, bally, pos[0], 525):
        balldy *= -1
    if bally <= 0:
        balldy *= -1
    if bally >= 570:
        running = False
    if ballx <= 0:
        balldx *= -1
    if ballx >= 770:
        balldx *= -1

    ballx += balldx
    bally += balldy

    screen.blit(player, (pos[0], 525))
    screen.blit(ball, (ballx,bally))
    blit_blocks()
    show_score()
    pygame.display.update()
OdatNurd
  • 21,371
  • 3
  • 50
  • 68
Stqrosta
  • 352
  • 2
  • 10

2 Answers2

1

it is a bad practice to pop from a list while you are iterating over this will cause unexpected behaviour, here:

for i, block in enumerate(blocks):

        if isCollision2(ballx, bally, blockx[i], blocky[i]):
            balldy *= -1
            score += 1
            blocks.pop(i)

you can use:

new_blocks = []
for i, block in enumerate(blocks):

        if isCollision2(ballx, bally, blockx[i], blocky[i]):
            balldy *= -1
            score += 1
        else:
            new_blocks.append(block)

blocks = new_blocks
kederrac
  • 16,819
  • 6
  • 32
  • 55
1

What you actually do ist manipulate a list (by pop) while you iterate it. I recommend to travers a copy of the list (blocks[:]) and to manipulate the original list. e.g:

i = 0
for x, y, block in zip(blockx[:], blocky[:], blocks[:]):

        if isCollision2(ballx, bally, x, y):
            blockx.pop(i)
            blocky.pop(i)
            blocks.pop(i)
            balldy *= -1
            score += 1
        else:
            i += 1

Anyway, I recommend to create a class Block:

class Block():
    def __init__(self, image, x, y)
        self.image = image
        self.x = x
        self.y = y

image = pygame.image.load('block.png')
x, y = 25,25
blocks = []
for i in range(21)
    if i % 7 == 0:
        y += 52
        x = 25
    blocks.append(Block(image, x, y))
    x += (50 + 64)
i = 0
for block in block[:]:
    if isCollision2(ballx, bally, block.x, block.y):
        balldy *= -1
        score += 1
        block.pop(i)
    else:
        i += 1
Rabbid76
  • 202,892
  • 27
  • 131
  • 174