Game Maker: Python com Pgzero para Crianças
Criando Telas de Menu e Game Over
Aprenda sobre criando telas de menu e game over
🎮 Criando Telas de Menu e Game Over
Olá, futuro Game Developer! 👋 Nesta aula prática, vamos dar um salto na qualidade dos nossos jogos, adicionando elementos essenciais para uma experiência de usuário mais completa e profissional: telas de menu e de Game Over.
Até agora, nossos jogos começam imediatamente e, quando acabam, simplesmente param. Mas e se quiséssemos dar ao jogador a opção de iniciar o jogo, ver instruções, ou jogar novamente após uma derrota? É exatamente isso que aprenderemos a fazer hoje!
🎯 O que vamos aprender:
- Gerenciar diferentes "estados" do jogo (Menu, Jogando, Game Over).
- Desenhar texto e "botões" interativos na tela.
- Detectar cliques do mouse para navegar entre os estados.
- Reiniciar o jogo de forma limpa.
Vamos colocar a mão na massa e transformar nossos protótipos em jogos mais robustos! 🛠️
1. 🧠 Gerenciando Estados do Jogo
A chave para ter telas diferentes é gerenciar o estado atual do jogo. Pense nisso como os diferentes "modos" em que seu jogo pode estar. Por exemplo:
MENU: O jogador está na tela inicial, pronto para começar.PLAYING: O jogo está acontecendo, com o jogador controlando o personagem.GAME_OVER: O jogo terminou, e o jogador vê a pontuação final e opções.
Podemos usar uma variável simples para guardar o estado atual do nosso jogo.
# No início do seu código
game_state = 'MENU' # O jogo começa no estado de menuE então, dentro das nossas funções draw() e update(), usaremos if/elif para decidir o que fazer com base no game_state.
2. 🎨 Desenhando Telas de Menu e Game Over
A função draw() é onde toda a mágica visual acontece. Vamos usá-la para desenhar elementos diferentes dependendo do game_state.
Exemplo: Desenhando um Menu Simples
Para o menu, precisaremos de um título e um botão "Iniciar Jogo".
def draw():
screen.clear() # Limpa a tela a cada frame
if game_state == 'MENU':
screen.draw.text("MEU JOGO INCRÍVEL", center=(WIDTH / 2, HEIGHT / 3), color="white", fontsize=60)
# Desenha um "botão" retangular
screen.draw.filled_rect(Rect((WIDTH / 2 - 100, HEIGHT / 2), (200, 50)), color="green")
screen.draw.text("Iniciar Jogo", center=(WIDTH / 2, HEIGHT / 2 + 25), color="white", fontsize=30)
elif game_state == 'PLAYING':
# Aqui desenhamos os elementos do jogo (jogador, inimigos, etc.)
player.draw()
screen.draw.text(f"Pontos: {score}", topleft=(10, 10), color="white", fontsize=30)
elif game_state == 'GAME_OVER':
screen.draw.text("GAME OVER!", center=(WIDTH / 2, HEIGHT / 3), color="red", fontsize=60)
screen.draw.text(f"Sua Pontuação: {score}", center=(WIDTH / 2, HEIGHT / 2 - 30), color="white", fontsize=40)
# Botão "Jogar Novamente"
screen.draw.filled_rect(Rect((WIDTH / 2 - 120, HEIGHT / 2 + 20), (240, 50)), color="blue")
screen.draw.text("Jogar Novamente", center=(WIDTH / 2, HEIGHT / 2 + 45), color="white", fontsize=30)Observações:
screen.draw.text(): Permite desenhar texto na tela. Você pode especificar a posição (center,topleft, etc.), cor e tamanho da fonte.screen.draw.filled_rect(): Desenha um retângulo preenchido. UsamosRectpara definir a posição e tamanho do nosso "botão".Rect((x, y), (width, height)): Cria um objeto retângulo.(x, y)é o canto superior esquerdo,(width, height)são as dimensões.
3. 🖱️ Interagindo com o Mouse: on_mouse_down()
Para que nossos botões funcionem, precisamos detectar quando o jogador clica neles. A função on_mouse_down(pos) do Pygame Zero é perfeita para isso. Ela é chamada sempre que o mouse é clicado, e pos é uma tupla (x, y) com as coordenadas do clique.
def on_mouse_down(pos):
global game_state, score, player # Precisamos acessar e modificar essas variáveis globais
if game_state == 'MENU':
# Define a área do botão "Iniciar Jogo"
start_button_rect = Rect((WIDTH / 2 - 100, HEIGHT / 2), (200, 50))
if start_button_rect.collidepoint(pos): # Verifica se o clique foi dentro do botão
game_state = 'PLAYING'
reset_game() # Reinicia o jogo quando começar
elif game_state == 'GAME_OVER':
# Define a área do botão "Jogar Novamente"
restart_button_rect = Rect((WIDTH / 2 - 120, HEIGHT / 2 + 20), (240, 50))
if restart_button_rect.collidepoint(pos):
game_state = 'PLAYING'
reset_game() # Reinicia o jogo
# Função para reiniciar o jogo
def reset_game():
global player, score
player.pos = (WIDTH / 2, HEIGHT / 2) # Posição inicial do jogador
score = 0 # Zera a pontuação
# Adicione aqui qualquer outra variável que precise ser reiniciadaExplicação:
global game_state, score, player: Declaramos que estamos usando as versões globais dessas variáveis, não criando novas locais.Rect.collidepoint(pos): Este é um método muito útil de um objetoRectque verifica se um ponto (pos) está dentro dos limites do retângulo.reset_game(): É uma boa prática criar uma função separada para reiniciar todas as variáveis do jogo para seus valores iniciais. Isso evita repetição de código.
4. 🕹️ Atualizando o Jogo: update()
A função update() deve conter a lógica do jogo (movimento de personagens, colisão, etc.) e só deve ser executada quando o jogo estiver no estado PLAYING.
def update(dt):
global game_state, score
if game_state == 'PLAYING':
# Lógica do jogo (movimento do jogador, inimigos, etc.)
# Exemplo simples: o jogador se move para a direita
player.x += 200 * dt
# Condição de Game Over (ex: jogador sai da tela)
if player.left > WIDTH:
game_state = 'GAME_OVER'
print("Game Over!")
# Exemplo de aumento de pontuação
score += 1🚀 Código de Exemplo Completo
Vamos juntar tudo em um exemplo completo. Neste jogo simples, um quadrado (player) se move para a direita. Se ele sair da tela, é "Game Over". Você pode clicar para iniciar e reiniciar.
# game_with_menus.py
import pgzrun # Importa o Pygame Zero
# --- Configurações da Tela ---
WIDTH = 800
HEIGHT = 600
TITLE = "Meu Jogo com Menus"
# --- Variáveis Globais do Jogo ---
game_state = 'MENU' # 'MENU', 'PLAYING', 'GAME_OVER'
player = Actor('player_square') # Usaremos um quadrado simples como jogador
score = 0
# --- Funções de Inicialização e Reinício ---
def reset_game():
"""Reinicia todas as variáveis do jogo para seus valores iniciais."""
global player, score
player.pos = (WIDTH / 4, HEIGHT / 2) # Posição inicial do jogador
player.image = 'player_square' # Garante que a imagem está correta
score = 0
print("Jogo reiniciado!")
# --- Funções do Pygame Zero ---
def draw():
"""Desenha todos os elementos na tela, baseado no estado do jogo."""
screen.clear() # Limpa a tela a cada frame (fundo preto)
if game_state == 'MENU':
screen.draw.text(TITLE, center=(WIDTH / 2, HEIGHT / 3), color="white", fontsize=60)
# Desenha o botão "Iniciar Jogo"
start_button_rect = Rect((WIDTH / 2 - 100, HEIGHT / 2), (200, 50))
screen.draw.filled_rect(start_button_rect, color="green")
screen.draw.text("Iniciar Jogo", center=(WIDTH / 2, HEIGHT / 2 + 25), color="white", fontsize=30)
elif game_state == 'PLAYING':
player.draw()
screen.draw.text(f"Pontos: {score}", topleft=(10, 10), color="white", fontsize=30)
elif game_state == 'GAME_OVER':
screen.draw.text("GAME OVER!", center=(WIDTH / 2, HEIGHT / 3), color="red", fontsize=60)
screen.draw.text(f"Sua Pontuação: {score}", center=(WIDTH / 2, HEIGHT / 2 - 30), color="white", fontsize=40)
# Desenha o botão "Jogar Novamente"
restart_button_rect = Rect((WIDTH / 2 - 120, HEIGHT / 2 + 20), (240, 50))
screen.draw.filled_rect(restart_button_rect, color="blue")
screen.draw.text("Jogar Novamente", center=(WIDTH / 2, HEIGHT / 2 + 45), color="white", fontsize=30)
def update(dt):
"""Atualiza a lógica do jogo, apenas quando o jogo está no estado PLAYING."""
global game_state, score
if game_state == 'PLAYING':
# Movimento simples do jogador para a direita
player.x += 150 * dt # dt é o tempo desde o último frame, para movimento suave
# Condição de Game Over: jogador sai da tela pela direita
if player.left > WIDTH:
game_state = 'GAME_OVER'
print("Game Over!")
# Aumenta a pontuação a cada frame
score += 1 # Poderíamos fazer com base em eventos ou tempo real
def on_mouse_down(pos):
"""Lida com cliques do mouse para interação com menus e botões."""
global game_state
if game_state == 'MENU':
# Área do botão "Iniciar Jogo"
start_button_rect = Rect((WIDTH / 2 - 100, HEIGHT / 2), (200, 50))
if start_button_rect.collidepoint(pos):
game_state = 'PLAYING'
reset_game() # Inicia o jogo e reinicia suas variáveis
elif game_state == 'GAME_OVER':
# Área do botão "Jogar Novamente"
restart_button_rect = Rect((WIDTH / 2 - 120, HEIGHT / 2 + 20), (240, 50))
if restart_button_rect.collidepoint(pos):
game_state = 'PLAYING'
reset_game() # Reinicia o jogo
# --- Inicia o Pygame Zero ---
pgzrun.go()Para rodar este código:
- Salve o código acima como
game_with_menus.py. - Crie uma pasta chamada
imagesno mesmo diretório do seu arquivo.py. - Dentro da pasta
images, adicione uma imagem quadrada simples (pode ser um quadrado branco, por exemplo) e salve-a comoplayer_square.png. Você pode criar uma imagem de 32x32 pixels, por exemplo, preenchida com uma cor.- Dica: Se não tiver uma imagem, pode usar um editor de imagens online simples (como Piskel ou Pixilart) para criar um quadrado e salvar como
player_square.png.
- Dica: Se não tiver uma imagem, pode usar um editor de imagens online simples (como Piskel ou Pixilart) para criar um quadrado e salvar como
- Abra o terminal na pasta onde você salvou o arquivo e execute:
pgzrun game_with_menus.py
📝 Exercícios e Desafios
Agora é a sua vez de praticar e expandir este conceito! 💪
Tarefas Básicas:
- Adicionar um botão "Sair" no menu:
- Crie um novo
Recte texto para um botão "Sair" na tela deMENU. - Na função
on_mouse_down, se ogame_stateforMENUe o clique for no botão "Sair", useexit()para fechar o jogo.
- Crie um novo
- Melhorar a aparência dos botões:
- Altere as cores dos botões.
- Adicione um contorno aos botões usando
screen.draw.rect()(desenhando um retângulo sem preenchimento). - Experimente diferentes tamanhos de fonte para o texto.
- Adicionar uma imagem de fundo:
- No estado
MENUeGAME_OVER, desenhe uma imagem de fundo (ex:screen.blit('background_image', (0,0))) antes de desenhar o texto e os botões. Lembre-se de colocar a imagem na pastaimages.
- No estado
Desafios Avançados:
- Tela de Pausa:
- Adicione um novo
game_state = 'PAUSED'. - Quando o jogador estiver em
PLAYING, se ele apertar a teclaP(useon_key_down), mude para o estadoPAUSED. - Na tela de pausa, desenhe a mensagem "JOGO PAUSADO" e um botão "Continuar".
- Quando o botão "Continuar" for clicado, volte para o estado
PLAYING. - Importante: Quando em
PAUSED, a funçãoupdate()NÃO deve executar a lógica do jogo!
- Adicione um novo
- High Score:
- Crie uma variável global
high_score = 0. - Quando o jogo for
GAME_OVER, verifique sescoreé maior quehigh_score. Se for, atualizehigh_score. - Exiba o
high_scorena tela deGAME_OVERe, opcionalmente, na tela deMENU.
- Crie uma variável global
- Menu de Opções:
- Adicione um botão "Opções" na tela de
MENU. - Ao clicar, mude para um novo
game_state = 'OPTIONS'. - Na tela de opções, você pode desenhar texto como "Volume: [ ]" ou "Dificuldade: [ ]" (sem funcionalidade real ainda, apenas visual).
- Adicione um botão "Voltar ao Menu" para retornar ao
MENU.
- Adicione um botão "Opções" na tela de
📝 Resumo e Próximos Passos
Nesta aula, aprendemos a:
- Utilizar uma variável de
game_statepara controlar o fluxo do jogo. - Desenhar interfaces de usuário simples, como títulos, mensagens e "botões" usando
screen.draw.text()escreen.draw.filled_rect(). - Implementar interatividade com o mouse usando
on_mouse_down()eRect.collidepoint(). - Criar uma função
reset_game()para garantir que o jogo possa ser reiniciado de forma limpa.
Com esses conceitos, seus jogos se tornam muito mais amigáveis e completos! 🎉
Na próxima aula, vamos explorar como adicionar sons e música aos nossos jogos, elevando ainda mais a imersão e a experiência do jogador! 🎶