Visão Geral do Projeto
Este guia demonstra como desenvolver um jogo estilo "Avião de Guerra" utilizando Python e a biblioteca Pygame. O foco é aplicar conceitos de programação orientada a objetos (POO) e compreender a estrutura básica de desenvolvimento de jogos.
Preparação do Ambiente
Primeiro, é necessário instalar a biblioteca Pygame. Execute o seguinte comando no terminal:
$ pip install pygame
Para verificar a instalação, execute um exemplo integrado:
$ python -m pygame.examples.aliens
Conceitos Fundamentais do Pygame
A criação de uma janela de jogo segue uma sequência lógica:
- Inicializar os módulos do Pygame com
pygame.init(). - Criar a superfície principal (tela) com
pygame.display.set_mode(). - Implementar um game loop infinito para manter o jogo em execução.
- Dentro do loop, processar eventos (teclado, mouse), atualizar a lógica do jogo e redesenhar a tela.
- Utilizar um relógio (
pygame.time.Clock) para controlar a taxa de quadros (FPS).
As coordenadas no Pygame têm a origem (0,0) no canto superior esquerdo, com o eixo X crescendo para a direita e o eixo Y crescendo para baixo.
Estrutura do Jogo
O jogo será estruturado em dois arquivos principais:
sprites_jogo.py: Contém as classes dos personagens e elementos do jogo (sprites).main_aviao.py: Contém a classe principal do jogo e o loop.
Definição dos Sprites (sprites_jogo.py)
Criaremos uma classe base para todos os sprites móveis e classes específicas para o fundo, inimigos, herói e projéteis.
import pygame
import random
# Constantes de configuração
AREA_TELA = pygame.Rect(0, 0, 480, 700)
TAXA_QUADROS = 60
EVENTO_CRIAR_INIMIGO = pygame.USEREVENT
EVENTO_ATIRAR = pygame.USEREVENT + 1
class SpriteBase(pygame.sprite.Sprite):
"""Classe base para sprites com imagem e velocidade."""
def __init__(self, arquivo_imagem, velocidade=1):
super().__init__()
self.image = pygame.image.load(arquivo_imagem)
self.rect = self.image.get_rect()
self.velocidade = velocidade
def atualizar(self, *args, **kwargs):
self.rect.y += self.velocidade
class Fundo(SpriteBase):
"""Sprite para o fundo do jogo, com rolagem contínua."""
def __init__(self, alternado=False):
super().__init__("./imagens/cenario.png", 1)
if alternado:
self.rect.bottom = 0
def atualizar(self):
super().atualizar()
if self.rect.top >= AREA_TELA.height:
self.rect.bottom = 0
class Inimigo(SpriteBase):
"""Sprite dos inimigos, com posição e velocidade aleatórias."""
def __init__(self):
super().__init__("./imagens/inimigo.png", random.randint(1, 3))
self.rect.x = random.randint(0, AREA_TELA.width - self.rect.width)
self.rect.bottom = 0
def atualizar(self):
super().atualizar()
if self.rect.top > AREA_TELA.height:
self.kill()
class Heroi(SpriteBase):
"""Sprite do herói, controlado pelo jogador."""
def __init__(self):
super().__init__("./imagens/aviao_jogador.png", 0)
self.rect.centerx = AREA_TELA.centerx
self.rect.bottom = AREA_TELA.bottom - 100
self.grupo_projeteis = pygame.sprite.Group()
def atualizar(self):
self.rect.x += self.velocidade
# Limita o movimento dentro da tela
self.rect.clamp_ip(AREA_TELA)
def disparar(self):
for i in range(3):
projetil = Projetil()
projetil.rect.bottom = self.rect.top - i * 20
projetil.rect.centerx = self.rect.centerx
self.grupo_projeteis.add(projetil)
class Projetil(SpriteBase):
"""Sprite dos projéteis disparados pelo herói."""
def __init__(self):
super().__init__("./imagens/projetil.png", -5)
def atualizar(self):
super().atualizar()
if self.rect.bottom < 0:
self.kill()
Lógica Principal do Jogo (main_aviao.py)
A classe principal greencia a inicialização, o game loop e a interação entre os sprites.
import pygame
from sprites_jogo import *
pygame.init()
class JogoAviao:
"""Classe principal que gerencia todo o jogo."""
def __init__(self):
self.tela = pygame.display.set_mode(AREA_TELA.size)
self.relogio = pygame.time.Clock()
self._iniciar_sprites()
# Configuração dos eventos de tempo
pygame.time.set_timer(EVENTO_CRIAR_INIMIGO, 1000)
pygame.time.set_timer(EVENTO_ATIRAR, 500)
def _iniciar_sprites(self):
"""Cria e organiza todos os grupos de sprites."""
self.grupo_fundo = pygame.sprite.Group(
Fundo(),
Fundo(alternado=True)
)
self.grupo_inimigos = pygame.sprite.Group()
self.jogador = Heroi()
self.grupo_jogador = pygame.sprite.Group(self.jogador)
def iniciar(self):
"""Inicia e mantém o game loop ativo."""
while True:
self.relogio.tick(TAXA_QUADROS)
self._processar_eventos()
self._verificar_colisoes()
self._atualizar_sprites()
pygame.display.flip()
def _processar_eventos(self):
"""Lida com todos os eventos (teclado, mouse, tempo)."""
for evento in pygame.event.get():
if evento.type == pygame.QUIT:
self._finalizar()
elif evento.type == EVENTO_CRIAR_INIMIGO:
self.grupo_inimigos.add(Inimigo())
elif evento.type == EVENTO_ATIRAR:
self.jogador.disparar()
teclas = pygame.key.get_pressed()
if teclas[pygame.K_LEFT]:
self.jogador.velocidade = -3
elif teclas[pygame.K_RIGHT]:
self.jogador.velocidade = 3
else:
self.jogador.velocidade = 0
def _verificar_colisoes(self):
"""Detecta colisões entre sprites usando grupos."""
# Projéteis atingem inimigos
pygame.sprite.groupcollide(
self.jogador.grupo_projeteis,
self.grupo_inimigos,
True, # Remove o projétil
True # Remove o inimigo
)
# Herói colide com inimigos
if pygame.sprite.spritecollide(
self.jogador,
self.grupo_inimigos,
dokill=True
):
self._finalizar()
def _atualizar_sprites(self):
"""Atualiza a posição e desenha todos os sprites na tela."""
self.tela.fill((0, 0, 0)) # Limpa a tela
for grupo in [self.grupo_fundo, self.grupo_inimigos, self.grupo_jogador]:
grupo.update()
grupo.draw(self.tela)
# Atualiza e desenha os projéteis
self.jogador.grupo_projeteis.update()
self.jogador.grupo_projeteis.draw(self.tela)
@staticmethod
def _finalizar():
"""Encerra o Pygame e o programa."""
pygame.quit()
exit()
if __name__ == "__main__":
jogo = JogoAviao()
jogo.iniciar()
Conceitos-Chave Implementados
- Herança e Polimorfismo: A classe
SpriteBaseé estendida por todas as outras, sobrescrevendo o métodoatualizarconforme necessário. - Gerenciamento de Grupos:
pygame.sprite.Groupsimplifica a atualização em massa (update()) e o desenho (draw()) de múltiplos sprites.` - Colisões: Funções como
groupcollideespritecollideencapsulam a lógica de detecção de colisão antre retângulos. - Temporização:
pygame.time.set_timerdispara eventos personalizados (como criar inimigos) em intervalos regulares, separando a lógica do tempo do game loop. - Controle de Jogo: O loop principal segue o padrrão: eventos -> lógica -> renderização, garantindo uma estrutura clara e eficiente.