Este projeto foi desenvolvido na disciplina Computação Orientada a Objetos (ACH2003) na EACH-USP, com o objetivo de aplicar, na prática, conceitos de orientação a objetos por meio da refatoração de um sistema existente.
O projeto consiste na reestruturação de um jogo do tipo shoot ’em up originalmente implementado de forma procedural, migrando para uma arquitetura orientada a objetos mais modular, extensível e de fácil manutenção.
O principal objetivo foi transformar um código com baixa organização e alta redundância em um sistema com:
- separação clara de responsabilidades
- redução de acoplamento
- aumento de coesão
- maior escalabilidade
- melhor manutenibilidade
A implementação original, embora escrita em Java, seguia um modelo procedural com as seguintes limitações:
- Repetição de lógica para colisão, atualização de estado e movimentação
- Uso extensivo de arrays estáticos para gerenciamento de entidades
- Ausência de encapsulamento (dados globais e mutáveis)
- Forte acoplamento entre componentes
- Baixa extensibilidade (adição de novas entidades exigia alterações em múltiplos pontos)
- Complexidade crescente na manutenção
A refatoração foi estruturada com base em princípios de orientação a objetos, priorizando composição, abstração e modularização.
O sistema foi organizado em pacotes com responsabilidades bem definidas:
jogo: ponto de entrada, loop principal e gerenciamento geralmecanicas.bases: classes base reutilizáveis (movimento, vida, colisão, disparo)mecanicas.jogador: implementação da entidade jogadormecanicas.inimigos: inimigos comunsmecanicas.chefes: entidades com comportamento complexomecanicas.powerups: itens coletáveismecanicas.projetil: modelagem e gerenciamento de projéteismecanicas.interfaces: contratos entre componentesmecanicas.constantes: enums e estados do sistema
Essa divisão reduz acoplamento e permite evolução independente de cada módulo.
As entidades do jogo foram modeladas com base em composição ao invés de herança profunda.
Classe responsável por encapsular atributos e comportamentos comuns:
- posição (x, y)
- raio (para colisão)
- estado (ACTIVE, EXPLODING, INACTIVE)
Funcionalidades foram extraídas para classes independentes:
MovimentoBase: atualização baseada em velocidade e delta de tempoVidaBase: controle de vida, dano e invulnerabilidadeExplosaoBase: controle temporal de explosõesDisparadorBase: gerenciamento de cadência de tiro
Essa abordagem reduz duplicação e permite reutilização entre diferentes entidades.
Interfaces foram utilizadas para definir contratos claros entre componentes:
Colidivel: padroniza verificação de colisãoEntidadeInimigo: comportamento comum de inimigosPowerUp: ciclo de vida de itens coletáveisChefe: definição de comportamento de bosses
Essa estratégia desacopla implementação de uso e facilita extensão do sistema.
O código original utilizava arrays estáticos, o que introduzia limitações de tamanho e complexidade de controle.
A refatoração substituiu essa abordagem por estruturas do Java Collections Framework:
List<Projetil>para projéteisList<EntidadeInimigo>para inimigosList<PowerUp>para power-ups
- Crescimento dinâmico das estruturas
- Eliminação de controle manual de índices
- Uso de
removeIfpara remoção eficiente - Uso de
Iteratorpara remoção segura durante iteração - Redução de erros como
ArrayIndexOutOfBoundsException
O GameManager centraliza o fluxo do jogo:
- atualização de entidades (update)
- detecção de colisões
- gerenciamento de spawns
- remoção de entidades inativas
- controle de fases
A lógica foi estruturada para minimizar efeitos colaterais e manter previsibilidade do estado do jogo.
O sistema de fases foi projetado para ser orientado a dados.
- Arquivos externos (
fase1.txt,fase2.txt) definem eventos de spawn - Cada entrada contém tipo de entidade, posição, tempo e parâmetros
- Um carregador (
CarregadorFase) interpreta os dados e popula estruturas internas
Essa abordagem permite adicionar ou modificar fases sem alterar código.
Chefes foram modelados como extensões de entidades inimigas com comportamento especializado:
- lógica de múltiplas fases baseada em vida
- padrões de ataque dinâmicos
- movimentação específica
- barra de vida independente
O comportamento é encapsulado em classes próprias, evitando impacto em outras partes do sistema.
Power-ups seguem um ciclo de vida bem definido:
- spawn
- atualização por tempo
- detecção de colisão com jogador
- ativação de efeito
- expiração e remoção
Os efeitos são desacoplados da lógica principal do jogador, permitindo fácil adição de novos tipos.
A migração para orientação a objetos trouxe ganhos significativos:
- redução de redundância
- maior legibilidade
- facilidade de manutenção
- extensibilidade sem modificação de código existente
- separação clara de responsabilidades
- melhor organização estrutural
- Java
- Java Collections Framework
- Biblioteca gráfica GameLib (fornecida pela disciplina)
O projeto depende da biblioteca GameLib fornecida pela disciplina.
Para execução, basta compilar os arquivos .java e executar a classe principal.
- Eduardo Almeida
- Diogo Leonel dos Santos
Projeto desenvolvido para a disciplina:
Computação Orientada a Objetos (ACH2003)
Professor: Flávio Luiz Coutinho
EACH – Universidade de São Paulo