Joguinho De Ping Pong - Jogos De Ping Pong Poki _ HEADS ARENA: SOCCER ALL STARS – NXVRGK
Jogos De Ping Pong Poki _ HEADS ARENA: SOCCER ALL STARS – NXVRGK

Criando um joguinho de ping pong simples do zero

Todo mundo que começa a programar acaba fazendo esse jogo. É o rito de passagem. Não tem mistério, mas tem um monte de detalhe chato que você descobre na marra quando o código não funciona como você esperava. Vou explicar como eu fazia quando tava aprendendo, com as coisas que funcionaram e as que não funcionaram. A ideia básica é: uma canvas, duas raquetes que seguem o mouse (ou as teclas W e S / setas), uma bola que quica nas paredes e um placar. Fazer isso rodar em JavaScript puro num canvas HTML5 leva uns 150 linhas de código se você não complicar.

O que você precisa saber antes de começar o joguinho de ping pong

Você não precisa de engine nenhuma. Um requestAnimationFrame no loop principal já resolve 90% do problema. O erro mais comum de iniciante é usar setInterval pra animação. setInterval não sincroniza com o refresh rate do monitor e aí você ganha input lag e framerate travando quando não deveria. O loop real funciona assim: limpa a tela, atualiza posições das coisas, desenha tudo de novo. Repete. A cada frame você calcula a nova posição da bola baseado na velocidade dela, verifica colisão com as paredes (invertendo a componente Y da velocidade) e colisão com as raquetes (invertendo a componente X e talvez adicionando um pouco de ângulo baseado em onde a bola bateu na raquete).

Tem um detalhe que todo mundo esquece e que causa problemas depois: delta time. Se você simplesmente some a velocidade ao position a cada frame, o jogo vai rodar mais rápido em monitores de 144Hz do que em 60Hz. A solução é multiplicar a velocidade pelo deltaTime entre frames. Num setup típico isso faz a diferença entre o jogo parecer consistente ou parecer que a bola às vezes sai voando pela tela inteira em um frame só. Aqui vai um exemplo prático de como eu estruturava o loop:

Primeiro defino o estado do jogo numa variável simples. Bola com x, y, vx, vy. Duas raquetes com y definido. Placar zerado. Aí no loop eu atualizo a bola, verifico se ela saiu pela esquerda ou direita (gol pra um dos lados, reseta a bola no centro), verifico colisão com as raquetes transformando a posição Y do ponto de impacto num ângulo de rebote, e renderizo tudo. Um problema que eu tive uma vez e demorei pra resolver: a bola ficava presa dentro da raquete. Acontece quando a velocidade horizontal é alta o suficiente pra bola pular de um lado da raquete pro outro num único frame. A verificação de colisão simples de "se sobreposição então inverte velocidade" não captura isso porque a bola já entrou e saiu da zona de colisão antes do próximo frame rodar.

👉 Clique no botão abaixo para saber mais sobre o assunto!

A solução que funcionou foi calcular a trajetória predictiva. Em vez de só verificar se a bola está dentro da raquete, eu calculava onde ela estaria no próximo frame e verificava se aquela trajetória intersectava o retângulo da raquete. Se intersects, reposicionava a bola pra fora da raquete e invertia a velocidade. Isso eliminou o bug completamente em velocidades que eu considerava normais pro jogo. Para o controle, eu preferia teclado pros dois jogadores. Mouse é mais fácil pra um jogador só mas cria assimetria se quiser multiplayer local. Teclas W/S pro jogador da esquerda e setas pra cima/baixo pro da direita. Leitura de input fica num objeto separado que o loop consulta, não direto nos handlers de evento. Isso evita queue de teclas pressionadas que deixa o controle pegajoso.

Se quiser algo pronto pra rodar agora, dá pra achar código fonte disso em repositórios públicos no GitHub procurando por "pong javascript canvas". A maioria segue a estrutura que descrevi. Tem versão em Python com pygame também que é boa se preferir não mexer com browser.

Por que seu joguinho de ping pong parece travado mesmo rodando liso

Isso acontece por um motivo específico: o bounding box da colisão com a raquete. Se você usa o retângulo completo da raquete como área de colisão, a bola pode entrar por baixo ou por cima e não detectar o rebate. A solução é ajustar o hitbox pra ficar levemente menor que o visual da raquete, ou usar colisão por distância ao invés de AABB (axis-aligned bounding box) nos cantos. Também vale checar se o fundo tá sendo redesenhado completo a cada frame ou se você tá fazendo cache. Num jogo tão simples isso não faz diferença perceptível, mas se você adicionar mais elementos depois pode se tornar gargalo.

A parte de placar é trivial: variável que incrementa quando a bola sai pela lateral, reseta posição da bola e continua. O que as pessoas não pensam é no reset. Se você só reseta x e y da bola mas deixa vx e vy como estavam, a bola pode sair na direção errada ou com velocidade estranha. Sempre reseta a velocidade também, num vetor padrão que pointe pro jogador que recebeu o gol. Se o objetivo é só um joguinho de ping pong pra passar tempo e aprender, esse nível já basta. Se quer algo mais elaborado com física realista de efeito na bola, spin, ou IA adversária, o código cresce rápido e aí você começa a considerar se não vale mais a pena migrar pra algo como Phaser ou até Unity. Mas pro básico, canvas puro resolve sem dor de cabeça.