Devlog #1


Pasmem, pois ele disse que ia fazer e fez mesmo. Tirei algum tempo na sexta, no sábado e hoje para cumprir minha lista de próximos passos que comentei no devlog passado e dei conta de tudo. Evitei me empolgar demais para não me esgotar e para conseguir manter a consistência, mas só o tempo dirá se essa estratégia funciona.

---

Antes de comentar o progresso dos últimos dias, gostaria me aprofundar um pouco numa decisão importante que já tive que tomar a respeito do jogo. Certo mesmo seria ter puxado essa discussão no devlog #0, mas ainda estou me acostumando com o que vale ou não a pena escrever a respeito. A decisão em questão foi: que tipo de estrutura eu deveria usar para o jogador, a pedra, etc.?

Até o momento, o jogo que tenho em mente é top-down e de uma simplicidade emprestada de The Binding of Isaac, com controles simples para o jogador, movimentos simples dos inimigos, projéteis disparados por ambos que interagem ao colidir. No entanto, a fundação do meu jogo é a pedra presa ao elástico, que se comporta de uma forma mais mecânica, como os astros que se orbitam em Solar 2.

A engine Godot oferece, entre outras opções, dois nós para entidades de um jogo 2D: CharacterBody2DRigidBody2D. Sem entrar em muitos detalhes, até porque isso não é um tutorial e eu estou longe de ser um especialista, vou tentar explicá-los. O primeiro se comporta de forma intuitiva como como um personagem 2D, andando para uma direção específica, colidindo com outros objetos e reagindo a essas colisões através de código; pense em Super Mario Bros. O segundo está sujeito à simulação física da engine, sendo controlado e reagindo a forças e impulsos ao invés de diretamente manipulando-se sua velocidade; pense em Angry Birds.

Guia de Troféus: Super Mario Bros (NES) | Nintendo Amino🎮! Amino


Angry Birds 2' é lançado mais de 5 anos após 1º game; veja trailer


Escolher o CharacterBody2D me facilitaria implementar o controle do jogador e o movimento dos inimigos, mas dificultaria implementar a interação da pedra com eles. O impacto de uma colisão precisaria ser implementado manualmente, afetando a velocidade do objeto por uma quantidade determinada de frames. Por outro lado, escolher o RigidBody2D deixaria as interações mais naturais, mas agora o controle seria feito como o de um foguete, aplicando-se força em determinada direção e colhendo como consequência uma alteração na velocidade do objeto.

Acabei optando pela segunda abordagem e até agora ela me atendeu bem. Tentei compensar a estranheza do movimento (e.g. depois de soltar a tecla o jogador ainda desliza por um tempo) manipulando a intensidade da força e a fricção com o solo. No momento estou achando o movimento de tudo muito pesado, como se o jogo estivesse em câmera lenta em relação ao que busco, mas são muitos números para ajustar e acho que isso cabe a uma fase posterior de polimento do jogo.

Ainda tem chance de eu me arrepender da escolha pelo RigidBody2D quando for implementar a IA dos inimigos, em especial o pathfinding. Ao invés de "pare de se mover quando chegar aqui", precisarei fazer algo como "pare de se mover quando chegar aqui e aplique uma força contrária para ajustar sua posição". Mas a César do futuro o que é de César do futuro.

---

Enfim seguimos para o progresso pascoal! A começar por um estilo inédito de trabalho que decidi adotar: ao invés de protótipos crus que avançam no código, mas têm visuais horríveis, vou prezar por um polimento básico em todos os passos. Seja desenhando sprites, fazendo animações para movimento, emitindo sons num impacto, ou tocando uma música de fundo, quero que toda versão desse jogo seja uma experiência minimamente agradável e não um bololô de código no qual só um programador consegue ver beleza.

Eis aqui, então, o nosso herói preso à sua pedra através de um elástico, numa versão mais lapidada do GIF da semana passada:

Depois de alcançar uma estética que me deixou satisfeito, passei a trabalhar nas novas funcionalidades. Comecei criando um inimigo estático que serviria de cobaia para testar as mecânicas básicas de dano, knockback, vida e afins. O artista de Paint mirou num saco de areia, mas, segundo minha esposa, acabou acertando num saco de merenda de filme americano:


Graças à escolha pela abordagem do RigidBody2D, bastava que o saco de pancada fosse este tipo de nó para interagir automaticamente com a pedra e o herói sem necessidade de código adicional. E de fato funcionou, mas o impacto natural da pedra não causava o empurrão que eu gostaria. Minha intenção para o knockback é algo como Super Smash Bros., em que os bonecos são totalmente isolados da tela dependendo da situação. Implementei, então, um sistema de empurrão ajustável para ficar mais ou menos exagerado.

Segui para o sistema de vida e dano baseado na velocidade de colisão. Estou usando no jogo uma arquitetura de componentes, implementando nós independentes que tenham uma atribuição mínima e possam ser levados para outros objetos do jogo através de uma simples instanciação. Já trabalhei com um sistema assim em outro jogo, mas ainda estou aprendendo sobre quando aumentar um componente ou criar um novo.

Para atingir o que pretendia fazer ao longo do feriado, implementei quatro componentes:

  • Componente de vida;
  • Componente de ataque sofrido;
  • Componente de empurrão sofrido;
  • Componente de efeitos especiais de movimento.

Desta forma, consigo fazer combinações que deem a diferentes entidades comportamentos únicos. Por exemplo, uma entidade pode sofrer dano sem ser empurrada (e.g. uma parede) enquanto outra pode ser empurrada sem sofrer dano (e.g. um objeto do cenário) apenas pela escolha de quais componentes são adicionados a cada uma. Ainda não tenho certeza se esta é a granularidade certa para os componentes, mas devo descobrir à medida em que for criando novos inimigos.

O resultado final consiste em duas entidades diferentes (jogador e saco de pancadas) que têm os mesmos componentes instanciados e, portanto, compartilham comportamentos:


Por fim, completei o último item da lista ao implementar o sistema de morte quando a vida chega a zero. No momento o feedback é apenas visual, com os controles sendo desabilitados e algumas manipulações no sprite:


Ao longo do trabalho, também adicionei sons para a maioria das ações (movimento do jogador e da pedra, dano ao jogador e ao inimigo) e uma música de fundo, todas retiradas do site freesound. Como GIFs são mudos, só conseguirei sonorizar os devlogs quando gravar um vídeo de verdade. Até lá, façam a sonoplastia em suas próprias cabeças.

Está ilustrado neste último GIF tudo que fiz até agora. Cumpri o que pretendia fazer e acredito que de uma forma escalável e consistente. Meu código está enxuto e ainda não precisei pegar atalhos ou fazer gambiarras. O futuro promete.

---

O sol começa a se pôr e uma luz dourada, já inofensiva, ilumina as árvores da praça em frente à minha janela. Foram três dias raros em que tive poucos compromissos e muita disposição para trabalhar no jogo. Estou satisfeito com o que consegui atingir, mas tento me manter realista de que provavelmente avançarei em ritmo lento e inconsistente.

Um passo importante a ser tomado é fechar um loop de jogo com começo, meio e fim. Menu inicial, tela de pausamento e game over, essas coisas. É importante não demorar para fazer esse envelopamento de interface gráfica porque é ele que define como meus objetos entrarão e sairão de cena, como o jogo será salvo, entre outras estruturas importantes para um jogo.

Apesar dessas considerações, estou pensando em adiar um pouco a abordagem fim-a-fim e priorizar implementar novos inimigos e sistemas básicos como projéteis e IA. Ainda não estou certo da minha escolha pelo RigidBody2D e seria bom descobrir o quanto antes as dificuldades que vou encontrar por ter tomado esse caminho. Meus próximos passos devem ser:

  • Implementar um inimigo que siga o jogador e faça um ataque em área quando se aproximar;
  • Implementar um inimigo que mantenha certa distância do jogador e atire projéteis;
  • Implementar um inimigo que atire bombas que explodem em determinada área.

Esse me parece um conjunto básico de inimigos que dará à luz componentes que poderão ser combinados de outras formas no futuro para criar inimigos mais complexos. Esses diferentes sistemas, ainda que simples e diretos individualmente, também me mostrarão as consequências de interações encadeadas. O que acontece quando uma flecha atinge a pedra? E quando uma explosão empurra um inimigo em alta velocidade para cima da pedra? Veremos.

Até a próxima,

rorosborges

Leave a comment

Log in with itch.io to leave a comment.