Detectando Colisões - Adicionando Interação entre Elementos

30/04/2026
iniciante pygame python 2d guia série

No capítulo anterior alimentamos a lista de meteoros automaticamente pelo timer que configuramos. Nossa chuva de meteoros já tem vida própria.

Os meteoros caem, giram e se renovam sem que o jogador precise fazer nada. Só falta o jogo perceber quando um deles acertar a nave.

Neste capítulo, vamos fazer com que o jogo seja encerrado caso a nave seja atingida por um meteoro.

Ao longo deste capítulo você aprenderá a:

Vamos começar configurando as colisões para a nave e os meteoros.

Configurando as Colisões


Para configurar as colisões corretamente, vamos usar o pygame.Rect que vimos no capítulo onde criamos a base dos meteoros.

O pygame.Rect vai além de posicionar imagens na tela. Ele também traz funções prontas para gerenciar colisões.

Adicionando Colisão para a Nave


Primeiro vamos configurar a colisão da nave. Para isso usamos o pygame.Rect para determinar sua area de colisão.

A área de colisão é chamada de hitbox no desenvolvimento de jogos. Ela não precisa ter o mesmo tamanho visual da imagem.

Na estrutura da nave vamos adicionar uma nova chave para armazenar sua colisão.

nave = {
    "imagem": img_nave,
    "x": janela.get_width() // 2 - img_nave.get_width() // 2,
    "y": janela.get_height() // 2 - img_nave.get_height() // 2,
    "velocidade": 5,
    "colisao": pygame.Rect((0, 0), (74, 33))
}

Criamos um novo Rect, sua posição inicialmente está zerada o que significa que ele está no canto superior esquerdo da janela.

Criamos a colisão com 74x33 pixels de tamanho, ele se baseia no espaço disponível entre as asas da nave.

Precisamos fazer com que a colisão sempre fique posicionada no centro da nave. Então vamos adicionar a lógica abaixo dentro do game loop.

nave["colisao"].centerx = nave["x"] + nave["imagem"].get_width() // 2
nave["colisao"].centery = nave["y"] + nave["imagem"].get_height() // 2

Somamos a posição da nave com metade de sua largura (ou altura). O resultado é o ponto central da nave. É nesse ponto que ancoraremos a área de colisão.

Hitbox da nave

Agora podemos adicionar a mesma lógica para os meteoros.

Adicionando Colisões para os Meteoros


Primeiro vamos adicionar a colisão no dicionário que a função criar_meteoro() retorna.

def criar_meteoro():
    meteoro_img = pygame.image.load("img/meteoro.png")
    meteoro = {
        "imagem": meteoro_img,
        "x": random.randint(0, janela.get_width()),
        "y": -100,
        "velocidade": 2,
        "rotacao": 0,
        "dir_rotacao": random.randint(-1, 1),
        "colisao": pygame.Rect((0, 0), (64, 50))
    }
    return meteoro

Para os meteoros, também criamos uma hitbox um pouco menor que a imagem: 64x50 pixels.

Agora vamos centralizar a colisão com o meteoro. Isso deve ser feito dentro do loop onde atualizamos a lista de meteoros.

for meteoro in meteoros:
        meteoro["y"] += meteoro["velocidade"]
        meteoro["rotacao"] += meteoro["dir_rotacao"]

        meteoro["colisao"].centerx = meteoro["x"]
        meteoro["colisao"].centery = meteoro["y"]

        imagem_rotacionada = pygame.transform.rotate(meteoro["imagem"], meteoro["rotacao"])
        retangulo_rotacionado = imagem_rotacionada.get_rect(center = (meteoro["x"], meteoro["y"]))
        janela.blit(imagem_rotacionada, retangulo_rotacionado)

Diferente da nave, os meteoros já são centralizado quando são rotacionados. Então apenas deixamos a colisão na mesma posição do meteoro.

Hitbox do meteoro

Com as áreas de colisão criadas e posicionadas, temos tudo o que precisamos para detectar o impacto.

Detectando as Colisões


Vamos ver se um meteoro atingiu a nave. Com a base do pygame.Rect já estabelecida para posicionar e rotacionar os meteoros, podemos agora explorar outra de suas capacidades: a função colliderect().

Imagine que cada elemento do jogo carrega uma caixa invisível ao redor de si. A função colliderect() verifica se a caixa de um elemento invadiu o espaço da caixa do outro. É como dois blocos físicos que não podem ocupar o mesmo lugar.

Dentro do loop de atualização dos meteoros, verificamos se a colisão do meteoro sobrepôs com a da nave. Caso isso aconteça, vamos encerrar o jogo.

for meteoro in meteoros:
        meteoro["y"] += meteoro["velocidade"]
        meteoro["rotacao"] += meteoro["dir_rotacao"]

        meteoro["colisao"].centerx = meteoro["x"]
        meteoro["colisao"].centery = meteoro["y"]

        if meteoro["colisao"].colliderect(nave["colisao"]):
            print("Fim de jogo!")
            rodando = False

        imagem_rotacionada = pygame.transform.rotate(meteoro["imagem"], meteoro["rotacao"])
        retangulo_rotacionado = imagem_rotacionada.get_rect(center = (meteoro["x"], meteoro["y"]))
        janela.blit(imagem_rotacionada, retangulo_rotacionado)

Ao executar o jogo, quando um meteoro atingir a nave, a janela será fechada e a mensagem Fim de jogo! aparecerá no console.

O que Aprendemos até Agora?


Agora o jogo sabe o que fazer quando a nave for atingida por um meteoro.

Neste capítulo você:

Código Completo


import pygame
import random

pygame.init()
janela = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

img_nave = pygame.image.load("img/nave.png")
nave = {
    "imagem": img_nave,
    "x": janela.get_width() // 2 - img_nave.get_width() // 2,
    "y": janela.get_height() // 2 - img_nave.get_height() // 2,
    "velocidade": 5,
    "colisao": pygame.Rect((0, 0), (74, 33))
}

def criar_meteoro():
    img_meteoro = pygame.image.load("img/meteoro.png")
    meteoro = {
        "imagem": img_meteoro,
        "x": random.randint(0, janela.get_width()),
        "y": -100,
        "velocidade": 2,
        "rotacao": 0,
        "dir_rotacao": random.randint(-1, 1),
        "colisao": pygame.Rect((0, 0), (64, 50))
    }
    return meteoro

meteoros = []

criar_novo_meteoro = pygame.USEREVENT + 1
pygame.time.set_timer(criar_novo_meteoro, 1500)

rodando = True
while rodando:
    for evento in pygame.event.get():
        if evento.type == pygame.QUIT:
            rodando = False

        if evento.type == criar_novo_meteoro:
            meteoro = criar_meteoro()
            meteoros.append(meteoro)

    teclas = pygame.key.get_pressed()

    if teclas[pygame.K_w]:
        nave["y"] -= nave["velocidade"]
    if teclas[pygame.K_s]:
        nave["y"] += nave["velocidade"]
    if teclas[pygame.K_a]:
        nave["x"] -= nave["velocidade"]
    if teclas[pygame.K_d]:
        nave["x"] += nave["velocidade"]

    if nave["x"] <= 0:
        nave["x"] = 0
    elif nave["x"] + nave["imagem"].get_width() >= janela.get_width():
        nave["x"] = janela.get_width() - nave["imagem"].get_width()

    if nave["y"] <= 0:
        nave["y"] = 0
    elif nave["y"] + nave["imagem"].get_height() >= janela.get_height():
        nave["y"] = janela.get_height() - nave["imagem"].get_height() 

    nave["colisao"].centerx = nave["x"] + nave["imagem"].get_width() // 2
    nave["colisao"].centery = nave["y"] + nave["imagem"].get_height() // 2

    janela.fill("black")

    janela.blit(nave["imagem"], (nave["x"], nave["y"]))

    for meteoro in meteoros:
        meteoro["y"] += meteoro["velocidade"]
        meteoro["rotacao"] += meteoro["dir_rotacao"]

        meteoro["colisao"].centerx = meteoro["x"]
        meteoro["colisao"].centery = meteoro["y"]

        if meteoro["colisao"].colliderect(nave["colisao"]):
            print("Fim de Jogo!")
            rodando = False

        imagem_rotacionada = pygame.transform.rotate(meteoro["imagem"], meteoro["rotacao"])
        retangulo_rotacionado = imagem_rotacionada.get_rect(center = (meteoro["x"], meteoro["y"]))
        janela.blit(imagem_rotacionada, retangulo_rotacionado)

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Próximo Passo: Atirando com a Nave


A nave já sente os impactos. Mas ainda não pode reagir.

No próximo capítulo vamos fazer a nave ganhar a capacidade de atirar e destruir os meteoros antes que eles cheguem.