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