Implementação de um Jogo de Avião de Guerra com Pygame

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:

  1. Inicializar os módulos do Pygame com pygame.init().
  2. Criar a superfície principal (tela) com pygame.display.set_mode().
  3. Implementar um game loop infinito para manter o jogo em execução.
  4. Dentro do loop, processar eventos (teclado, mouse), atualizar a lógica do jogo e redesenhar a tela.
  5. 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

  1. Herança e Polimorfismo: A classe SpriteBase é estendida por todas as outras, sobrescrevendo o método atualizar conforme necessário.
  2. Gerenciamento de Grupos: pygame.sprite.Group simplifica a atualização em massa (update()) e o desenho (draw()) de múltiplos sprites.`
  3. Colisões: Funções como groupcollide e spritecollide encapsulam a lógica de detecção de colisão antre retângulos.
  4. Temporização: pygame.time.set_timer dispara eventos personalizados (como criar inimigos) em intervalos regulares, separando a lógica do tempo do game loop.
  5. Controle de Jogo: O loop principal segue o padrrão: eventos -> lógica -> renderização, garantindo uma estrutura clara e eficiente.

Tags: Pygame Python jogo-2d programacao-orientada-a-objetos game-loop

Publicado em 6-23 21:43