Doug's Game Dev Log
Sobre
EN|PT-BR
2026-06-11

Fantasmas, Balas Radiais e o Estranho Caso do LIFETIME

Essa atualização tocou em três sistemas diferentes, e os três tinham a mesma vibe: "isso funciona perfeitamente... exceto por um caso específico que ninguém pensou."

MULTISHOT: 360 graus de caos, menos um

O novo upgrade MULTISHOT dispara projéteis extras num espalhamento radial — empilha 20 vezes e você dispara 20 balas, igualmente espaçadas, 18° entre cada uma, formando um círculo completo ao redor da sua nave. Extremamente satisfatório. Bem "eu sou a morte, destruidora de cubos".

Só tem uma regra: a primeira bala sempre sai reto pra frente, não importa quantos stacks você tenha. Todas as outras balas se abrem simetricamente ao redor dela. Então em vez de um spray que parece totalmente aleatório, o padrão sempre tem uma bala "de frente" ancorando tudo — o que, sem surpresa, dá uma sensação de mira muito melhor do que um círculo sem direção óbvia. Construímos isso com uma função pequena de matriz de rotação que calcula a direção de cada bala a partir da quantidade de stacks, e até desenhamos o ícone do upgrade à mão no Python — seis raiozinhos amarelos saindo de um núcleo laranja. Olha, nem todo asset precisa de Photoshop.

Os inimigos que não queriam ficar mortos

Aqui vai uma boa: projéteis com ricochete continuavam quicando nos inimigos depois que eles morriam. O sprite do inimigo já tinha ido pra cucuia, a barra de vida marcava zero, o jogo claramente considerava aquilo "falecido" — e mesmo assim as balas continuavam ricocheteando no cadáver como se ele tivesse assuntos pendentes.

A causa: marcar o inimigo como PreventCollision na hora da morte não era suficiente, porque o collider dele continuava lá, plantado no mundo físico, sólido, só... invisível. A correção foi chamar explicitamente collider.clear() no exato momento em que o inimigo morre, além da troca do tipo de colisão. Já que estávamos ali, também ajustamos a condição de vitória — antes ela checava status !== 'alive', o que tecnicamente conta inimigos que nem spawnaram ainda como "não vivos" (verdade, mas inútil). Agora ela checa especificamente 'dying' ou 'dead', então a fase não declara vitória só porque metade dos inimigos ainda está carregando.

LIFETIME: o upgrade que não leu o manual

Todo upgrade do jogo segue a mesma regra de escala: mais ou menos ±5% por stack, redondinho e previsível. Exceto o LIFETIME, o upgrade que aumenta quanto tempo seus projéteis ficam vivos antes de desaparecer. Esse aí escala num +250ms fixo por stack, começando de uma base de 750ms, batendo o teto de 5500ms no stack máximo de 19.

Por quê? Porque "5% do tempo de vida de um projétil" é um número profundamente insatisfatório de calcular de cabeça enquanto você joga, e um bônus fixo de tempo é algo que o jogador realmente sente. Então o LIFETIME ganhou seu próprio caso especial no código de escala, com sua própria constante nomeada, e um comentário que basicamente resume "sim, esse aqui é diferente, não, não vamos arrumar, é uma feature." Também encontramos — e corrigimos — um bug em que o seletor de upgrades pós-vitória recebia um objeto de controle de upgrades novinho e vazio em vez do seu de verdade, então ele continuava oferecendo upgrades que você já tinha estourado em 19 stacks. Ninguém precisa de um 20º LIFETIME. Ninguém.

Na próxima: um menu de Opções de verdade, sliders de volume que aplicam ao vivo, e um pequeno ajuste de qualidade de vida pra resolver a pior sensação de qualquer roguelike — perder uma run e cair de paraquedas de volta na estaca zero.