Como Criar um Jogo em Python com Pygame: Tutorial para Iniciantes

Aprenda como criar um jogo em Python com Pygame: instalação, game loop, movimento, colisão e placar em um jogo real de desviar de obstáculos, passo a passo.
Se você aprendeu Python na escola, na faculdade ou em um curso de lógica, a pergunta aparece rápido: dá para usar isso em um jogo? Dá, e este guia mostra como criar um jogo em Python de verdade usando o Pygame. Não é um "hello world" disfarçado: você vai montar um jogo completo de desviar de obstáculos, com movimento, colisão, placar e reinício, em menos de 100 linhas de código que rodam em qualquer computador.
Por que Python é a porta de entrada de tanta gente
Python virou a primeira linguagem de quase todo mundo por um motivo simples: a sintaxe sai da frente. Sem chaves, sem ponto e vírgula, sem tipos obrigatórios em todo lugar. Escolas técnicas, cursinhos de lógica e disciplinas introdutórias de faculdade adotaram Python em massa, então milhares de pessoas chegam ao desenvolvimento de jogos já sabendo escrever um if e um for em Python.
A boa notícia: esse conhecimento serve, sim, para jogos. O Pygame é uma biblioteca que dá ao Python o que falta para um jogo funcionar: janela, desenho na tela, leitura de teclado e mouse, som e controle de tempo. Com isso você consegue fazer jogos 2D completos: clones de Pong, Snake, Breakout, jogos de plataforma simples e o jogo de desviar que vamos construir aqui.
O que o Pygame não é: uma engine. Ele não tem editor visual, não tem sistema de física pronto, não tem animação por keyframes nem export para celular. Isso importa, e vamos falar disso com honestidade no final. Mas para aprender a lógica que sustenta qualquer jogo, ele é uma das melhores ferramentas que existem, justamente porque nada acontece por mágica: cada pixel na tela está lá porque o seu código mandou.
Se você ainda está decidindo por onde começar, o comparativo de qual linguagem aprender para fazer jogos coloca o Python no contexto das outras opções.
Instalação e o esqueleto de todo jogo
Você precisa do Python 3 instalado (qualquer versão a partir da 3.9 serve). Depois, um único comando no terminal:
pip install pygame
Pronto. Agora o esqueleto mínimo, que é a fundação de literalmente todo jogo já feito: uma janela, um relógio e um loop que roda até o jogador fechar. Salve como desvia.py e execute com python desvia.py:
import pygame
LARGURA = 480
ALTURA = 640
FPS = 60
COR_FUNDO = (20, 20, 30)
def main() -> None:
pygame.init()
tela = pygame.display.set_mode((LARGURA, ALTURA))
pygame.display.set_caption("Desvia!")
relogio = pygame.time.Clock()
rodando = True
while rodando:
for evento in pygame.event.get():
if evento.type == pygame.QUIT:
rodando = False
tela.fill(COR_FUNDO)
pygame.display.flip()
relogio.tick(FPS)
pygame.quit()
if __name__ == "__main__":
main()
Quatro coisas para entender aqui, porque elas se repetem em qualquer engine que você usar na vida:
- Game loop: o
while rodandoé o coração do jogo. A cada volta ele processa entradas, atualiza o estado e redesenha tudo. Um jogo é isso, dezenas de vezes por segundo. - Eventos:
pygame.event.get()entrega tudo que aconteceu desde o último quadro: teclas, cliques, o X da janela. Sem esse loop de eventos, a janela congela. - Desenho:
tela.fill()pinta o fundo epygame.display.flip()mostra o quadro pronto. Você desenha tudo primeiro e exibe de uma vez. - Clock:
relogio.tick(FPS)limita o jogo a 60 quadros por segundo. Sem ele, o loop roda na velocidade máxima do processador e o jogo fica injogável em máquinas rápidas.
Rode e você verá uma janela escura de 480x640. Parece pouco, mas o esqueleto está vivo. Agora vem o jogo.
Como criar um jogo em Python na prática: o projeto Desvia!
A ideia do Desvia! cabe em uma frase: você controla um quadrado na parte de baixo da tela, blocos caem do topo em posições e velocidades aleatórias, cada bloco que você deixa passar vale 1 ponto, e encostar em um bloco encerra a partida. Simples de descrever, e completo o bastante para exercitar movimento, spawn, colisão, placar e estado de fim de jogo.
O jogador e o movimento
O jogador é um pygame.Rect, a estrutura mais útil do Pygame: um retângulo com posição e tamanho que já sabe detectar colisão e se manter dentro de limites. Adicione estas constantes e funções ao arquivo, acima de main:
VEL_JOGADOR = 6
COR_JOGADOR = (80, 200, 120)
AREA_TELA = pygame.Rect(0, 0, LARGURA, ALTURA)
def criar_jogador() -> pygame.Rect:
return pygame.Rect(LARGURA // 2 - 25, ALTURA - 70, 50, 50)
def mover_jogador(jogador: pygame.Rect) -> None:
teclas = pygame.key.get_pressed()
if teclas[pygame.K_LEFT]:
jogador.x -= VEL_JOGADOR
if teclas[pygame.K_RIGHT]:
jogador.x += VEL_JOGADOR
jogador.clamp_ip(AREA_TELA)
Repare na diferença de abordagem: para movimento contínuo usamos pygame.key.get_pressed(), que pergunta a cada quadro "essa tecla está apertada agora?". O loop de eventos serve para coisas que acontecem uma vez (fechar a janela, apertar ENTER); o estado das teclas serve para movimento que dura enquanto o dedo estiver na seta. A linha clamp_ip(AREA_TELA) prende o retângulo dentro da tela, então o jogador não escapa pelas bordas.
Dentro do loop, antes do tela.fill, chame mover_jogador(jogador) e desenhe com pygame.draw.rect(tela, COR_JOGADOR, jogador). Crie o jogador antes do loop com jogador = criar_jogador(). Rode: o quadrado verde já obedece às setas.
Obstáculos caindo do céu
Cada obstáculo é um retângulo com uma velocidade própria, então vamos representá-lo como uma lista de dois itens: [rect, velocidade]. Para criar obstáculos em intervalos regulares, o Pygame tem um recurso elegante: um evento customizado disparado por timer, que cai no mesmo loop de eventos do QUIT.
import random
VEL_MINIMA = 3
VEL_MAXIMA = 7
INTERVALO_SPAWN_MS = 600
EVENTO_SPAWN = pygame.USEREVENT + 1
COR_OBSTACULO = (220, 80, 80)
def criar_obstaculo() -> list:
largura = random.randint(40, 90)
x = random.randint(0, LARGURA - largura)
rect = pygame.Rect(x, -30, largura, 30)
velocidade = random.randint(VEL_MINIMA, VEL_MAXIMA)
return [rect, velocidade]
O obstáculo nasce com y = -30, ou seja, logo acima da borda superior, e desce a cada quadro somando a própria velocidade. Larguras e velocidades sorteadas deixam o jogo imprevisível sem precisar de nenhum sistema de dificuldade: às vezes vem um bloco largo e lento, às vezes um estreito e rápido.
Dentro de main, logo depois de criar o relógio, ligue o timer com pygame.time.set_timer(EVENTO_SPAWN, INTERVALO_SPAWN_MS). A cada 600 milissegundos, o Pygame coloca um EVENTO_SPAWN na fila e o seu loop de eventos cria um obstáculo novo. Quer o jogo mais difícil? Diminua o intervalo.
O jogo completo
Agora a versão final, juntando tudo com placar, colisão e reinício por ENTER. Este é o arquivo desvia.py inteiro, pronto para rodar:
import random
import pygame
LARGURA = 480
ALTURA = 640
FPS = 60
VEL_JOGADOR = 6
VEL_MINIMA = 3
VEL_MAXIMA = 7
INTERVALO_SPAWN_MS = 600
EVENTO_SPAWN = pygame.USEREVENT + 1
COR_FUNDO = (20, 20, 30)
COR_JOGADOR = (80, 200, 120)
COR_OBSTACULO = (220, 80, 80)
COR_TEXTO = (240, 240, 240)
AREA_TELA = pygame.Rect(0, 0, LARGURA, ALTURA)
def criar_jogador() -> pygame.Rect:
return pygame.Rect(LARGURA // 2 - 25, ALTURA - 70, 50, 50)
def criar_obstaculo() -> list:
largura = random.randint(40, 90)
x = random.randint(0, LARGURA - largura)
rect = pygame.Rect(x, -30, largura, 30)
velocidade = random.randint(VEL_MINIMA, VEL_MAXIMA)
return [rect, velocidade]
def mover_jogador(jogador: pygame.Rect) -> None:
teclas = pygame.key.get_pressed()
if teclas[pygame.K_LEFT]:
jogador.x -= VEL_JOGADOR
if teclas[pygame.K_RIGHT]:
jogador.x += VEL_JOGADOR
jogador.clamp_ip(AREA_TELA)
def main() -> None:
pygame.init()
tela = pygame.display.set_mode((LARGURA, ALTURA))
pygame.display.set_caption("Desvia!")
relogio = pygame.time.Clock()
fonte = pygame.font.Font(None, 36)
pygame.time.set_timer(EVENTO_SPAWN, INTERVALO_SPAWN_MS)
jogador = criar_jogador()
obstaculos: list = []
placar = 0
game_over = False
rodando = True
while rodando:
for evento in pygame.event.get():
if evento.type == pygame.QUIT:
rodando = False
elif evento.type == EVENTO_SPAWN and not game_over:
obstaculos.append(criar_obstaculo())
elif evento.type == pygame.KEYDOWN and game_over:
if evento.key == pygame.K_RETURN:
jogador = criar_jogador()
obstaculos.clear()
placar = 0
game_over = False
if not game_over:
mover_jogador(jogador)
sobraram = []
for obstaculo in obstaculos:
obstaculo[0].y += obstaculo[1]
if obstaculo[0].top > ALTURA:
placar += 1
else:
sobraram.append(obstaculo)
obstaculos = sobraram
for obstaculo in obstaculos:
if jogador.colliderect(obstaculo[0]):
game_over = True
tela.fill(COR_FUNDO)
pygame.draw.rect(tela, COR_JOGADOR, jogador)
for obstaculo in obstaculos:
pygame.draw.rect(tela, COR_OBSTACULO, obstaculo[0])
texto = fonte.render(f"Placar: {placar}", True, COR_TEXTO)
tela.blit(texto, (10, 10))
if game_over:
aviso = fonte.render("Bateu! ENTER para reiniciar", True, COR_TEXTO)
tela.blit(aviso, (LARGURA // 2 - aviso.get_width() // 2, ALTURA // 2))
pygame.display.flip()
relogio.tick(FPS)
pygame.quit()
if __name__ == "__main__":
main()
Três detalhes que valem sua atenção nessa versão final:
- Colisão em uma linha:
jogador.colliderect(obstaculo[0])faz todo o trabalho de checar sobreposição entre retângulos. É por isso que usarRectdesde o início compensa. - Limpeza da lista: obstáculos que passam do fundo da tela viram ponto e saem da lista
sobraram. Sem essa remoção, a lista cresce para sempre e o jogo trava depois de alguns minutos. - Estado de game over: em vez de fechar o jogo na colisão, a flag
game_overcongela a lógica e mantém o desenho rodando, mostrando a mensagem de reinício. Máquinas de estado começam assim, com um booleano honesto.
Rode, jogue, e depois mexa nos números do topo do arquivo. Aumentar VEL_MAXIMA, encolher o jogador, acelerar o spawn: cada constante é um botão de game design. Essa é a parte mais valiosa do exercício, porque ajustar a sensação do jogo mexendo em valores é o trabalho diário de quem faz jogos.
Os limites honestos do Pygame
Aqui vai a parte que muitos tutoriais escondem: o Pygame é ótimo para aprender e fraco para publicar. Os limites são concretos:
- Sem editor: não existe cena, hierarquia visual nem inspector. Tudo é código, incluindo posicionar cada elemento na tela por coordenada. Em um projeto pequeno isso é até didático; em um jogo com 30 telas, vira sofrimento.
- Export limitado: transformar seu
.pyem um executável já exige ferramentas externas como PyInstaller. Levar para celular, console ou navegador vai de "muito difícil" a "na prática, inviável". Engines modernas exportam para essas plataformas com poucos cliques. - Física e animação manuais: gravidade, pulo, rampas, knockback, animação de personagem: tudo isso você escreve do zero. De novo, didático em dose pequena, improdutivo em jogo real.
- Desempenho: Python é interpretado e o Pygame desenha na CPU. Para centenas de objetos simultâneos ou efeitos visuais elaborados, o quadro cai antes do que você imagina.
Nada disso é defeito escondido: o Pygame nunca prometeu ser engine. Ele é uma camada fina sobre a biblioteca SDL, feita para você tocar cada engrenagem do jogo com a mão. Como ferramenta de aprendizado, isso é uma qualidade rara.
E depois do Pygame?
A resposta depende do que você quer, e vale ser direto sobre os dois caminhos.
Se o seu objetivo é aprender programação, ficar no Pygame por um bom tempo é uma escolha legítima. Faça um Snake, um Pong, um clone de Breakout. Cada projeto vai aprofundar estruturas de dados, funções e organização de código, e isso vale para qualquer carreira em tecnologia, não só jogos.
Agora, se o que você quer é fazer jogos de verdade, jogos que outras pessoas baixam e jogam no celular ou na Steam, em algum momento você migra para uma engine. E aqui o Python te dá uma vantagem concreta: o GDScript, linguagem da engine Godot, tem sintaxe abertamente inspirada em Python. Indentação define blocos, if e for funcionam do mesmo jeito, e a função _process(delta) da Godot é o primo direto do seu game loop. Quem fez o Desvia! deste tutorial refaz ele na Godot em uma tarde, com a diferença de que lá o jogo exporta para Windows, web e celular sem drama.
O raciocínio para decidir a hora certa de trocar de ferramenta é o mesmo que explicamos no guia sobre quando migrar do Scratch para a Godot: a troca faz sentido quando a ferramenta atual vira o teto do seu projeto, não antes. Se os seus jogos no Pygame começaram a esbarrar nos limites da lista acima, o teto chegou.
E se você quer encurtar esse caminho com acompanhamento, currículo estruturado e projetos guiados do zero até o export, veja nossa análise de qual é o melhor curso de desenvolvimento de jogos para entender o que separa um curso sério de uma playlist de tutoriais soltos.
O resumo é este: Python com Pygame é um excelente primeiro passo, talvez o melhor disponível para quem já sabe a linguagem. Só não confunda o primeiro passo com o destino. Faça o Desvia!, faça mais dois ou três jogos, e quando sentir o teto, pule para uma engine sabendo que quase tudo que você aprendeu vai junto.
Perguntas frequentes
Preciso saber muito Python antes de usar o Pygame?
Não. Se você já entende variável, condicional, loop e função, consegue seguir este tutorial. O Pygame não exige orientação a objetos nem bibliotecas avançadas. Na prática, fazer um jogo pequeno é uma das melhores formas de consolidar exatamente esses fundamentos, porque cada conceito aparece com um propósito visível na tela.
Dá para fazer jogo profissional com Python?
Dá, mas é raro e trabalhoso. Existem jogos comerciais feitos com Python, mas são exceção: o Pygame não tem editor de cenas, o export para consoles e mobile é praticamente inviável e o desempenho limita projetos maiores. Para aprender lógica, Python é excelente. Para lançar um jogo comercial, uma engine como Godot, Unity ou Unreal resolve distribuição, física e animação que no Pygame você teria que construir na mão.
Python ou Godot para começar?
Depende do objetivo. Se você quer aprender programação e já usa Python na escola ou faculdade, começar com Pygame aproveita o que você sabe. Se o objetivo é fazer jogos de verdade, vale ir direto para a Godot: o GDScript tem sintaxe muito parecida com Python, então quase nada do que você aprendeu se perde, e a engine entrega editor, física, animação e export que o Pygame não tem.
O Pygame roda em qualquer computador?
Roda em praticamente qualquer máquina com Windows, Linux ou macOS, incluindo computadores antigos e modestos. Como os jogos de estudo usam formas geométricas ou sprites 2D simples, não há exigência de placa de vídeo dedicada. Você só precisa do Python 3 instalado e de um pip install pygame no terminal.
Por que meu jogo no Pygame fica lento ou travando?
As causas mais comuns são esquecer o clock.tick() no loop, carregar imagens dentro do loop principal em vez de uma vez no início, ou acumular objetos em uma lista sem nunca remover os que saíram da tela. No jogo deste tutorial, os obstáculos que passam do fundo da janela são removidos da lista a cada quadro justamente para evitar esse acúmulo.


