Implementando um pacman clássico do zero
O que você realmente precisa saber sobre pacman clássico
A maioria das pessoas acha que implementar um pacman clássico é só desenhar um labirinto e fazer uma bolinha comer pontos. Na prática, o desafio fica nos fantasmas. O caminho mínimo entre dois tiles não é trivial quando você tem paredes em todas as direções, e cada fantasma precisa de uma lógica diferente para parecer inteligente de verdade. Eu comecei varios projetos assim há anos. O primeiro erro comum é tentar usar pathfinding A* direto na grid inteira a cada frame. Funciona no papel, mas na prática você termina com 60 fps caindo pra 8 porque os fantasmas recalculam rotas completas sem necessidade. A solução real é pré-calculadar um grafo de conexões entre nós (interseções e terminais do labirinto) e usar those are aarests de arestas em vez de calcular tudo em tempo real. Isso reduz o custo computacional dos fantasmas em algo em torno de 80-90%.
Ghosts: o coração do problema
Cada fantasma no pacman tem um comportamento distinto que não é mera variação de velocidade. Blinky perssegue diretamente Pac-Man. Pinky tenta mirar quatro tiles à frente da direção atual dele. Inky usa a posição de Blinky como referência relativa. Clyde alterna entre perseguição e aleatoriedade dependendo da distância. Essa distinção importa porque define completamente a estrutura do seu sistema de IA. Se você colocar todos os fantasmas usando a mesma lógica de perseguição, o jogo fica chato rapidamente. A diferença entrePinkie e Blinky muda radicalmente como Pac-Man deve planejar rotas de fuga. Eu perdi duas semanas refatorando o módulo de fantasmas depois de perceber que Inky estava calculando o alvo errado porque a distância euclidiana entre ele e Blinky não convertia corretamente para coordenadas de grid. A correção foi converter ambos os pontos para coordenadas de tile antes de calcular o vetor de direção.
Estado dos fantasmas: scare e home
O estado de "scared" (fantasmas azuis) é onde a maioria dos tutoriais simplifica demais. A lógica básica é: quando Pac-Man come uma power pellet, todos os fantasmas viram azuis e fogem do centro do labirinto. Mas o detalhe importante é que eles não simplesmente invertem o pathfinding. Eles voltam para a casa dos fantasmas (a caixa no centro do mapa) e depois reentram no labirinto pelo mesmo caminho que saíram. Se você deixar os fantasmas presos tentando voltar para casa quando a porta está bloqueada por outros fantasmas, o jogo trava. Minha solução foi fazer com que fantasmas bloqueadores permitam que outros passem por cima deles temporariamente durante o retorno à casa, ou então forçar o fantasma a esperar até que o caminho libere antes de continuar. Isso adiciona um pequeno delay mas evita o bug de fantasmas congelados que todo mundo encontra na primeira implementação.
A duração do estado scared também segue um padrão fixo: os primeiros ciclos duram cerca de 7 segundos, depois diminuem para 5, depois 3, e finalmente os fantasmas voltam normal. É esse countdown que cria a tensão do jogo. Remover essa progressão torna o power pellet inútil porque os jogadores nunca sabem se vão conseguir comer o fantasma antes que ele volte ao normal.
Grid e detecção de colisão
O labirinto tradicional usa uma grid de 28 colunas por 31 linhas. Cada tile pode ser uma parede, um corredor, uma power pellet, um point dot, ou a casa dos fantasmas. O túnel nas laterais é outra mecânica que parece simples mas gera bugs constantes: Pac-Man e os fantasmas devem aparecer no lado oposto quando entram no túnel, e isso precisa funcionar independentemente da direção do movimento. Para colisão, use detecção baseada em tile com margem de tolerância. A bolinha do Pac-Man tem raio aproximado de metade do tamanho do tile, então ela pode estar parcialmente sobreposta a uma parede sem colidir se o centro ainda estiver dentro do corredor. Um teste ingênuo de "se o centro tocar uma parede, colidiu" vai fazer Pac-Man bater nas paredes visualmente quando ainda há espaço livre.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Túnel e wrap-around
O túnel é mais problemático do que parece. Quando um entidade entra no túnel pela esquerda, ela deve aparecer à direita. O truque é verificar a posição X da entidade a cada frame: se X menor que zero, definir X para largura do mapa. Se X maior ou igual à largura, definir X para zero. Isso vale para Pac-Man e todos os fantasmas. Um bug comum é o fantasma ficar preso no túnel porque o pathfinding não considera o túnel como conexão válida. Quando você pré-calcula o grafo de navegação, adicione explicitamente as arestas do túnel conectando os nós das bordas opostas. Sem isso, os fantasmas vão tentar contornar o labirinto inteiro pelo lado de fora.
Sons e sprites
O som do "waka waka" é um oscilador simples que alterna entre duas frequências. Não precisa de arquivos de áudio externos se você estiver fazendo uma implementação do zero — um oscilador de onda quadrada ou triangular gerando alternância rápida entre 440 Hz e 330 Hz soa bastante similar. Os efeitos de comer fantasma e morrer são mais fáceis de replicar com sintetização básica do que com samples, mas samples gravados ou extraídos do original dão um resultado mais autêntico. Os sprites originais são bitmap de 8x8 pixels por frame. O animação do Pac-Man abre e fecha a boca usando quatro frames. Os fantasmas têm dois frames de animação de "ondulação" na parte inferior e um frame extra de olhos aterrorizados quando estão no modo scared. Não adicione animações extras além disso — a simplicidade dos sprites originais é parte do charme e fugir disso só deixa o jogo com cara de clone genérico.
Estrutura de dados recomendada
Use uma matriz 2D para o mapa, um vetor de entidades para Pac-Man e fantasmas, e um buffer de input para capturar a próxima direção antes que o entidade chegue na interseção seguinte. O buffer de input é crucial: sem ele, o jogador precisa pressionar a tecla exatamente no momento em que Pac-Man está na interseção, o que é frustrantemente difícil. Para os fantasmas, cada um deve ter seu próprio target tile que é recalculado a cada interseção. O recalculo a cada interseção em vez de a cada frame é suficiente para dar a ilusão de inteligência sem sobrecarregar a CPU. Em hardware moderno isso não faz diferença, mas é boa prática manter o ciclo de atualização alinhado com a lógica do jogo.
Problema prático que encontrei
Num projeto meu, os fantasmas ficavam presos em loop quando Pac-Man entrava no modo teleport através do túnel enquanto os fantasmas estavam perseguindo. O pathfinding recalculava a rota mas o fantasma nunca chegava ao target porque o target se movia para o outro lado do mapa. A solução foi adicionar um timeout: se um fantasma não alcançasse o target em N frames, ele recalculava o path do zero em vez de continuar seguindo o target antigo. Isso resolveu o problema sem precisar de uma reinicialização completa do jogo.
Download e recursos
Para quem quer estudar a implementação completa, existem várias versões open-source no GitHub. Procure por recriações em JavaScript, Python ou C++ do pacman clássico. A versão mais didática costuma ser a que usa canvas HTML5 com cerca de 1500 linhas de código — suficiente para ver toda a lógica sem ser tão grande a ponto de perder o fio da meada. Também vale a pena consultar o documento technical specification do pacman original disponível online. Ele descreve os endereços de memória do jogo arcade, os valores de score, os timings exatos de cada ação e o comportamento detalhado de cada fantasma. Essas informações são mais precisas do que qualquer tutorial de terceiros porque vêm direto da source.
O que não funciona bem
Implementar o pacman clássico como um jogo multiplayer local funciona na teoria mas na prática o labirinto pequeno e a velocidade dos fantasmas tornam a experiência caótica muito rápido. Não vale o esforço adicional de sincronização de input e renderização duplicada. Melhor focar em fazer uma single-player sólida do que uma multiplayer ruim. Também evite adicionar power-ups extras tipo armas ou mudanças no mapa. O design original do pacman é equilibrado justamente pela sua simplicidade: comer pontos, evitar fantasmas, usar power pellets estrategicamente. Qualquer adição complexa tende a quebrar o timing original e deixar o jogo desbalanceado.