projeto

PROJETO FINAL: Seu Primeiro Jogo Completo

Aprenda sobre projeto final: seu primeiro jogo completo

90 min
Aula 5 de 5

PROJETO FINAL: Seu Primeiro Jogo Completo 🚀

Olá, futuros game makers! 👋 Chegamos ao nosso projeto final, a cereja do bolo do nosso curso! 🎉

Depois de aprender sobre Actors, movimento, eventos de teclado e muito mais, é hora de juntar tudo o que vimos e criar um jogo completo do zero. Este é o momento perfeito para você ver como todas as peças se encaixam para formar uma experiência interativa e divertida!

🎯 Objetivo da Aula

Nesta aula, vamos construir um jogo simples, mas completo, chamado "Esquiva Espacial". Nele, você controlará uma nave espacial que precisa desviar de asteroides que caem do céu. Se você colidir com um asteroide, é Game Over! Mas não se preocupe, você poderá tentar de novo para bater seu recorde de pontos!

Vamos aprender a:

  1. Estruturar um jogo completo com diferentes "estados" (tela inicial, jogo ativo, game over).
  2. Gerenciar múltiplos objetos (nave e vários asteroides).
  3. Detectar colisões entre objetos.
  4. Implementar um sistema de pontuação.
  5. Criar uma experiência de jogo reiniciável.

Prepare-se, porque a aventura de criar seu próprio jogo começa agora! ✨


🧐 1. Entendendo a Estrutura de um Jogo com Pgzero

Um jogo não é apenas um monte de código; ele tem uma estrutura! Com Pgzero, algumas funções são o "coração" do seu jogo:

  • WIDTH, HEIGHT: Definem o tamanho da sua janela de jogo.
  • TITLE: O título que aparece na janela.
  • draw(): Esta função é chamada muitas vezes por segundo para desenhar tudo na tela (sua nave, asteroides, pontuação, etc.).
  • update(): Também é chamada muitas vezes por segundo, mas aqui é onde a "lógica" do jogo acontece: mover a nave, fazer os asteroides caírem, verificar colisões, atualizar a pontuação.
  • on_key_down(), on_key_up(): Funções que respondem quando você aperta ou solta uma tecla.

Estados do Jogo 🚦

Um jogo geralmente não começa direto na ação. Ele tem uma tela inicial, depois o jogo em si, e talvez uma tela de "Game Over". Chamamos isso de estados do jogo. Gerenciar estados nos ajuda a mostrar coisas diferentes e fazer o jogo se comportar de maneiras diferentes dependendo de onde o jogador está.

Vamos definir três estados para o nosso jogo:

  • GAME_STATE_TITLE: A tela inicial onde o jogador vê o título e as instruções.
  • GAME_STATE_PLAYING: Onde a ação acontece! A nave se move, os asteroides caem.
  • GAME_STATE_GAME_OVER: A tela que aparece quando o jogador perde, mostrando a pontuação final e a opção de jogar novamente.

Teremos uma variável, por exemplo, game_state, que armazenará qual é o estado atual do jogo.


🛠️ 2. Mão na Massa: Construindo o "Esquiva Espacial"

Vamos construir nosso jogo passo a passo. Lembre-se de que você precisará de algumas imagens simples para a nave e o asteroide. Crie uma pasta chamada images na mesma pasta do seu arquivo .py e coloque as imagens lá. Se não tiver, pode desenhar retângulos coloridos como placeholders!

Sugestões de nomes de arquivos:

  • player.png (para a nave)
  • asteroid.png (para o asteroide)

🚀 Tarefas do Projeto Principal

Aqui está a lista de tarefas que vamos seguir para construir o jogo:

  • 1. Configurar o ambiente e as variáveis globais.
  • 2. Criar a nave do jogador e implementar seu movimento.
  • 3. Gerenciar os asteroides: criar, mover e remover.
  • 4. Detectar colisões entre a nave e os asteroides.
  • 5. Implementar o sistema de pontuação.
  • 6. Gerenciar os estados do jogo (Título, Jogando, Game Over).
  • 7. Adicionar funcionalidade de reiniciar o jogo.

Vamos começar!

📝 1. Configuração Inicial e Variáveis Globais

Primeiro, vamos definir o tamanho da nossa tela, o título do jogo e algumas variáveis importantes para o nosso jogo, incluindo os estados.

# game.py
 
# 📏 Dimensões da tela do jogo
WIDTH = 800
HEIGHT = 600
TITLE = "Esquiva Espacial!" # 🎮 Título da janela
 
# 🌈 Cores comuns (usaremos para texto e retângulos)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)
 
# 🚦 Estados do jogo
GAME_STATE_TITLE = 0 # Tela de título
GAME_STATE_PLAYING = 1 # Jogo em andamento
GAME_STATE_GAME_OVER = 2 # Tela de Game Over
 
# 🚀 Variáveis do jogo
player = None # Nossa nave espacial (será um Actor)
asteroids = [] # Uma lista para guardar todos os asteroides
score = 0 # Pontuação do jogador
game_state = GAME_STATE_TITLE # Começamos na tela de título
 
# 🕹️ Variáveis de controle de movimento da nave
player_moving_left = False
player_moving_right = False
 
# ⏰ Variáveis para controlar a geração de asteroides
asteroid_spawn_interval = 1.0 # A cada 1 segundo um novo asteroide
last_asteroid_spawn_time = 0 # Tempo da última geração de asteroide

🧑‍💻 2. Criando a Nave do Jogador e Movimento

Vamos criar a nave e adicionar a lógica para que ela se mova.

# game.py (continuação)
 
# 🚀 Função para inicializar o jogo ou reiniciar
def init_game():
    global player, asteroids, score, game_state, player_moving_left, player_moving_right
    global last_asteroid_spawn_time
 
    player = Actor("player", (WIDTH / 2, HEIGHT - 50)) # Posiciona a nave no centro inferior
    asteroids.clear() # Limpa a lista de asteroides
    score = 0 # Zera a pontuação
    game_state = GAME_STATE_PLAYING # Mudar para o estado de jogo
    player_moving_left = False
    player_moving_right = False
    last_asteroid_spawn_time = 0 # Reseta o tempo de geração
 
# 🔄 A função update() é chamada constantemente para atualizar a lógica do jogo
def update(dt):
    global score, game_state
 
    if game_state == GAME_STATE_PLAYING:
        # Movimento do jogador
        if player_moving_left:
            player.x -= 500 * dt # Move 500 pixels por segundo
        if player_moving_right:
            player.x += 500 * dt
        
        # Garante que a nave não saia da tela
        if player.left < 0:
            player.left = 0
        if player.right > WIDTH:
            player.right = WIDTH
 
        # 🌠 Movimento dos asteroides e remoção
        for asteroid in list(asteroids): # Usamos list() para poder remover itens enquanto iteramos
            asteroid.y += 200 * dt # Asteroides caem a 200 pixels por segundo
            if asteroid.top > HEIGHT:
                asteroids.remove(asteroid) # Remove asteroides que saem da tela
                score += 1 # Ganha ponto por desviar!
 
        # 💥 Detecção de colisão
        for asteroid in asteroids:
            if player.colliderect(asteroid):
                game_state = GAME_STATE_GAME_OVER # Game Over se colidir!
                break # Sai do loop de asteroides
 
        # ⏰ Geração de novos asteroides
        spawn_asteroids(dt)
 
# ⌨️ Funções para controlar o movimento da nave com o teclado
def on_key_down(key):
    global player_moving_left, player_moving_right, game_state
 
    if game_state == GAME_STATE_PLAYING:
        if key == keys.LEFT:
            player_moving_left = True
        elif key == keys.RIGHT:
            player_moving_right = True
    elif game_state == GAME_STATE_TITLE:
        if key == keys.SPACE: # Pressione ESPAÇO para começar o jogo
            init_game()
    elif game_state == GAME_STATE_GAME_OVER:
        if key == keys.SPACE: # Pressione ESPAÇO para reiniciar
            init_game()
 
def on_key_up(key):
    global player_moving_left, player_moving_right
    if key == keys.LEFT:
        player_moving_left = False
    elif key == keys.RIGHT:
        player_moving_right = False

☄️ 3. Gerenciando os Asteroides

Vamos criar a função para gerar asteroides e integrá-la ao update.

# game.py (continuação)
 
import random # Precisamos do random para posicionar os asteroides
 
# ☄️ Função para gerar um novo asteroide
def spawn_asteroids(dt):
    global last_asteroid_spawn_time
 
    last_asteroid_spawn_time += dt
    if last_asteroid_spawn_time >= asteroid_spawn_interval:
        # Cria um asteroide em uma posição X aleatória no topo da tela
        x_pos = random.randint(50, WIDTH - 50)
        asteroid = Actor("asteroid", (x_pos, -20)) # Começa um pouco acima da tela
        asteroids.append(asteroid)
        last_asteroid_spawn_time = 0 # Reseta o contador
 
# Chamamos init_game() uma vez para configurar o jogo quando ele inicia
init_game() # Importante para inicializar o player e o estado inicial como PLAYING
            # Mas vamos mudar para GAME_STATE_TITLE no init_game()
            # E chamar init_game() apenas quando iniciar de fato.
 
# Vamos ajustar o init_game para não começar no PLAYING, mas sim no TITLE.
# E o primeiro init_game() será chamado quando o jogador apertar ESPAÇO.
# Então, vamos REMOVER o init_game() daqui de baixo e deixar apenas a chamada no on_key_down.
# E no início do script, game_state já é GAME_STATE_TITLE.

🎨 4. Desenhando Tudo na Tela (draw())

Agora, a função draw() que desenha tudo, dependendo do estado do jogo.

# game.py (continuação)
 
# 🖼️ A função draw() é chamada constantemente para redesenhar a tela
def draw():
    screen.fill(BLACK) # Limpa a tela com preto a cada frame
 
    if game_state == GAME_STATE_TITLE:
        screen.draw.text("ESQUIVA ESPACIAL!", center=(WIDTH / 2, HEIGHT / 2 - 50), color=YELLOW, fontsize=60)
        screen.draw.text("Pressione ESPAÇO para começar", center=(WIDTH / 2, HEIGHT / 2 + 20), color=WHITE, fontsize=30)
    
    elif game_state == GAME_STATE_PLAYING:
        player.draw() # Desenha a nave do jogador
        for asteroid in asteroids:
            asteroid.draw() # Desenha cada asteroide
 
        # Desenha a pontuação na parte superior da tela
        screen.draw.text(f"Pontuação: {score}", topleft=(10, 10), color=WHITE, fontsize=30)
    
    elif game_state == GAME_STATE_GAME_OVER:
        screen.draw.text("GAME OVER!", center=(WIDTH / 2, HEIGHT / 2 - 50), color=RED, fontsize=80)
        screen.draw.text(f"Sua Pontuação Final: {score}", center=(WIDTH / 2, HEIGHT / 2 + 20), color=WHITE, fontsize=40)
        screen.draw.text("Pressione ESPAÇO para jogar novamente", center=(WIDTH / 2, HEIGHT / 2 + 80), color=YELLOW, fontsize=30)

🧩 Código Completo (para referência)

Aqui está o código completo do nosso jogo "Esquiva Espacial". Certifique-se de ter as imagens player.png e asteroid.png na pasta images ao lado do seu script.

import pgzrun
import random
 
# 📏 Dimensões da tela do jogo
WIDTH = 800
HEIGHT = 600
TITLE = "Esquiva Espacial!" # 🎮 Título da janela
 
# 🌈 Cores comuns
WHITE = (255, 255, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)
 
# 🚦 Estados do jogo
GAME_STATE_TITLE = 0 # Tela de título
GAME_STATE_PLAYING = 1 # Jogo em andamento
GAME_STATE_GAME_OVER = 2 # Tela de Game Over
 
# 🚀 Variáveis do jogo
player = None # Nossa nave espacial (Actor)
asteroids = [] # Lista para guardar todos os asteroides
score = 0 # Pontuação do jogador
game_state = GAME_STATE_TITLE # Começamos na tela de título
 
# 🕹️ Variáveis de controle de movimento da nave
player_moving_left = False
player_moving_right = False
 
# ⏰ Variáveis para controlar a geração de asteroides
asteroid_spawn_interval = 1.0 # A cada 1 segundo um novo asteroide
last_asteroid_spawn_time = 0.0 # Tempo da última geração de asteroide
 
# 🚀 Função para inicializar o jogo ou reiniciar
def init_game():
    global player, asteroids, score, game_state, player_moving_left, player_moving_right
    global last_asteroid_spawn_time
 
    player = Actor("player", (WIDTH / 2, HEIGHT - 50)) # Posiciona a nave no centro inferior
    asteroids.clear() # Limpa a lista de asteroides
    score = 0 # Zera a pontuação
    game_state = GAME_STATE_PLAYING # Mudar para o estado de jogo
    player_moving_left = False
    player_moving_right = False
    last_asteroid_spawn_time = 0.0 # Reseta o tempo de geração
 
# ☄️ Função para gerar um novo asteroide
def spawn_asteroid():
    x_pos = random.randint(50, WIDTH - 50) # Posição X aleatória
    asteroid = Actor("asteroid", (x_pos, -20)) # Começa um pouco acima da tela
    asteroids.append(asteroid)
 
# 🔄 A função update() é chamada constantemente para atualizar a lógica do jogo
def update(dt):
    global score, game_state, last_asteroid_spawn_time
 
    if game_state == GAME_STATE_PLAYING:
        # Movimento do jogador
        if player_moving_left:
            player.x -= 500 * dt # Move 500 pixels por segundo
        if player_moving_right:
            player.x += 500 * dt
        
        # Garante que a nave não saia da tela
        if player.left < 0:
            player.left = 0
        if player.right > WIDTH:
            player.right = WIDTH
 
        # 🌠 Movimento dos asteroides e remoção
        # Criamos uma cópia da lista para iterar com `list(asteroids)`
        # Assim podemos remover elementos da lista original sem causar erros
        for asteroid in list(asteroids): 
            asteroid.y += 200 * dt # Asteroides caem a 200 pixels por segundo
            if asteroid.top > HEIGHT:
                asteroids.remove(asteroid) # Remove asteroides que saem da tela
                score += 1 # Ganha ponto por desviar!
 
        # 💥 Detecção de colisão
        for asteroid in asteroids:
            if player.colliderect(asteroid):
                game_state = GAME_STATE_GAME_OVER # Game Over se colidir!
                break # Sai do loop de asteroides para evitar múltiplas colisões no mesmo frame
 
        # ⏰ Geração de novos asteroides
        last_asteroid_spawn_time += dt
        if last_asteroid_spawn_time >= asteroid_spawn_interval:
            spawn_asteroid()
            last_asteroid_spawn_time = 0.0 # Reseta o contador
 
# ⌨️ Funções para controlar o movimento da nave com o teclado
def on_key_down(key):
    global player_moving_left, player_moving_right, game_state
 
    if game_state == GAME_STATE_PLAYING:
        if key == keys.LEFT:
            player_moving_left = True
        elif key == keys.RIGHT:
            player_moving_right = True
    elif game_state == GAME_STATE_TITLE:
        if key == keys.SPACE: # Pressione ESPAÇO para começar o jogo
            init_game()
    elif game_state == GAME_STATE_GAME_OVER:
        if key == keys.SPACE: # Pressione ESPAÇO para reiniciar
            init_game()
 
def on_key_up(key):
    global player_moving_left, player_moving_right
    if key == keys.LEFT:
        player_moving_left = False
    elif key == keys.RIGHT:
        player_moving_right = False
 
# 🖼️ A função draw() é chamada constantemente para redesenhar a tela
def draw():
    screen.fill(BLACK) # Limpa a tela com preto a cada frame
 
    if game_state == GAME_STATE_TITLE:
        screen.draw.text("ESQUIVA ESPACIAL!", center=(WIDTH / 2, HEIGHT / 2 - 50), color=YELLOW, fontsize=60)
        screen.draw.text("Pressione ESPAÇO para começar", center=(WIDTH / 2, HEIGHT / 2 + 20), color=WHITE, fontsize=30)
    
    elif game_state == GAME_STATE_PLAYING:
        player.draw() # Desenha a nave do jogador
        for asteroid in asteroids:
            asteroid.draw() # Desenha cada asteroide
 
        # Desenha a pontuação na parte superior da tela
        screen.draw.text(f"Pontuação: {score}", topleft=(10, 10), color=WHITE, fontsize=30)
    
    elif game_state == GAME_STATE_GAME_OVER:
        screen.draw.text("GAME OVER!", center=(WIDTH / 2, HEIGHT / 2 - 50), color=RED, fontsize=80)
        screen.draw.text(f"Sua Pontuação Final: {score}", center=(WIDTH / 2, HEIGHT / 2 + 20), color=WHITE, fontsize=40)
        screen.draw.text("Pressione ESPAÇO para jogar novamente", center=(WIDTH / 2, HEIGHT / 2 + 80), color=YELLOW, fontsize=30)
 
pgzrun.go() # Inicia o jogo

👩‍💻 5. Desafios Extras: Leve seu Jogo Além!

Parabéns! Você acabou de criar seu primeiro jogo completo! 🎉 Mas a diversão não precisa parar por aqui. Que tal tentar alguns desafios para deixar seu jogo ainda mais incrível?

  • Adicionar Sons:
    • Crie uma pasta sounds e adicione arquivos .ogg ou .wav.
    • Use sounds.nome_do_som.play() para tocar um som quando um asteroide é desviado, ou quando o jogo acaba.
  • Diferentes Tipos de Inimigos:
    • Crie mais imagens de asteroides ou inimigos (asteroid2.png, enemy.png).
    • Na função spawn_asteroid(), escolha aleatoriamente qual imagem usar.
    • Dica: você pode até dar velocidades diferentes para cada tipo!
  • Tiros do Jogador:
    • Crie um Actor para um "tiro".
    • Quando o jogador aperta uma tecla (ex: SPACE), crie um tiro que se move para cima.
    • Detecte a colisão entre o tiro e o asteroide. Se colidir, ambos desaparecem e o jogador ganha pontos.
  • Níveis de Dificuldade:
    • Faça com que a velocidade dos asteroides aumente com o tempo ou com a pontuação.
    • Diminua o asteroid_spawn_interval para gerar asteroides mais rapidamente.
  • Melhorar os Gráficos:
    • Encontre ou desenhe sprites mais detalhados para a nave e os asteroides.
    • Adicione um fundo estelar que se move lentamente para dar a sensação de espaço.

🌟 6. Resumo e Próximos Passos

Uau! Você chegou ao fim do curso e criou um jogo completo! Isso é um grande feito e mostra o quanto você aprendeu.

Nesta aula, você:

  • Compreendeu a estrutura de um jogo com Pgzero.
  • Implementou estados de jogo para controlar o fluxo.
  • Gerenciou múltiplos objetos e suas interações.
  • Detectou colisões e atualizou a pontuação.
  • Criou uma experiência de jogo completa com telas de título e game over.

O que vem a seguir?

  1. Continue Explorando: A documentação oficial do Pgzero (pgzero.readthedocs.io) é uma ótima fonte para aprender mais.
  2. Crie Seus Próprios Jogos: Use as habilidades que você aprendeu para inventar e construir seus próprios jogos! Pense em ideias, desenhe seus personagens e comece a codificar.
  3. Compartilhe Suas Criações: Mostre seu jogo para amigos e familiares! É uma ótima maneira de receber feedback e se inspirar para novos projetos.
  4. Explore Outras Áreas: Python é uma linguagem poderosa. Você pode explorar outras bibliotecas de jogos (como Pygame) ou até mesmo outras áreas da programação.

Parabéns, Game Maker! Você tem as ferramentas para criar mundos e aventuras. Continue praticando e se divertindo! 🚀✨

© 2025 Escola All Dev. Todos os direitos reservados.

PROJETO FINAL: Seu Primeiro Jogo Completo - Game Maker: Python com Pgzero para Crianças | escola.all.dev.br