Como a Rubber Duck Games desenvolveu uma luta de chefe no Evil Wizard

A Rubber Duck Games, uma das vencedoras do prêmio Best in Play da GDC 2023, revela como eles criaram uma luta de chefes interessante. Neste blog de convidados, os membros da equipe Banki e Sergio Wajswol guiam você por toda a jornada, desde o design e a prototipagem até a animação, os testes, o balanceamento e a finalização dos efeitos visuais e de áudio do Evil Wizard.
Olá, leitores! Sou o Banki, designer de jogos e produtor da Rubber Duck Games. Nosso RPG de ação cheio de humor Evil Wizard já está disponível no Steam e no Xbox, e eu queria dar uma olhada nos bastidores de como desenvolvemos uma luta de chefe.
Evil Wizard é um jogo inspirado em Metroidvania que coloca você na pele de um "chefe final" derrotado em sua busca por vingança contra o herói amaldiçoado.
Essa busca por vingança leva os jogadores a ambientes encantadores em pixel-art repletos de hordas de inimigos que eles precisam vencer para recuperar o que é deles. Embora o personagem principal já tenha sido um mago poderoso, uma batalha perdida nas mãos do herói o privou de seus poderes, e ele precisa recuperá-los enquanto trabalha para se infiltrar no castelo e desencadear uma vingança devastadora.
O primeiro herói a ser derrotado no jogo é Hailga, a poderosa feiticeira do gelo. Nós a usaremos como exemplo de chefe para este mergulho profundo.
Vamos começar do início. A criação de um chefe (e de todos os inimigos) para o Evil Wizard foi um pouco complicada. Mesmo que os jogadores estejam lutando contra os mocinhos, sabíamos que eles ainda deveriam parecer ameaçadores o suficiente para serem reconhecidos como inimigos.
Para os chefes, buscamos inspiração e referências entre heróis de jogos conhecidos. Com a Hailga, nos inspiramos muito na Jaina do Warcraft, pois ambas compartilham muitas semelhanças.
O primeiro passo foi preparar uma planilha (algo que usamos para todos os chefes do jogo) na qual detalhamos as principais características, a mecânica e algumas referências do personagem.

Com a mecânica projetada, poderíamos passar para a próxima etapa: prototipagem.
Chegou a hora de apresentar à equipe o projeto do novo chefe, então entramos em uma reunião e eu analiso o documento e explico algumas das minhas decisões.
Aqui, ajustamos um pouco o design - em alguns casos, uma mecânica pode ser muito difícil de desenvolver, ou uma animação muito complicada de desenhar, etc. Tentamos fazer as coisas no prazo, portanto, há alguns aspectos que devem ser levados em consideração para criar o melhor chefe possível no tempo que temos.
Quando se tratava de prototipagem, eis o que nosso programador principal, Diego Ordóñez, tinha a dizer: "Hailga foi nosso primeiro chefe no Evil Wizard e a primeira vez que programei um chefe em minha vida. Eu sabia que era uma tarefa difícil, então comecei fazendo o que todo programador faz: dividir os ataques em tarefas simples e executá-las separadamente. Esse chefe tem ataques que eram simples de fazer reutilizando projéteis."
"Os ataques da bala de gelo e do míssil de gelo são muito diferentes para os jogadores - um é fácil de desviar, enquanto o outro representa um desafio durante a luta", continuou. "A principal diferença é como o componente de ataque gera os projéteis de gelo e a quantidade de projéteis voltados para o jogador. Com ajustes simples, conseguimos reutilizar um sistema inteiro para apresentar dois ataques diferentes. Tudo isso funcionou muito bem até que tive que começar a fazer o ataque da nevasca."
Para a luta de Hailga, queríamos trazer algo novo para o encontro e achamos que o vento poderia ser interessante. Isso era muito diferente de tudo o que havíamos feito no Evil Wizard, então tive que começar do zero. A ideia básica era gerar vento a partir de uma direção aleatória para mover o jogador em direção a uma parede cheia de espinhos que poderiam causar danos. A melhor maneira de combater esse ataque é se proteger, por isso colocamos algumas estalactites no campo de batalha para serem usadas como bloqueadores de vento. Se os jogadores ficarem atrás de uma estalactite de gelo, o vento não emitirá mais força sobre eles.
Começamos criando um componente de ataque para ser responsável pelo gerenciamento dos diferentes sistemas que usamos. Os sistemas usaram estalactites, emissor de vento e efeitos visuais de nevasca. Vou me concentrar nos dois primeiros, e o VFX será abordado por Sergio Wajswol mais adiante nesta postagem do blog.
As estalactites são geradas usando um colisor de círculo para obter pontos aleatórios dentro dele e, em seguida, usando essas posições para criar uma estalactite com um deslocamento no eixo Y. Aplicando uma corrotina, fazemos com que os objetos caiam diminuindo o eixo Y - coisas simples. Depois que as estalactites foram geradas, passamos para o controlador de vento. Esse componente funciona como um grande ventilador com uma forma retangular que gira em torno da borda de um círculo.

Como precisávamos soprar o vento de direções aleatórias, tivemos que apontar o emissor para o centro para que tudo dentro da área fosse afetado. O controlador de vento tem um emissor de vento que armazena a rotação, a direção e a posição do vento. À medida que giramos o componente, o emissor calcula esses valores e os aplica ao vento (que é apenas uma direção e uma força). Basicamente, um Vector3 e um float.
O vento também pode ser bloqueado, conforme mencionado, por um bloqueador de vento. Esse componente tem um BoxCollider2D que verifica as colisões com o jogador. Se o jogador se aproximar de um bloqueador de vento, o OnTriggerEnter2D ativará o bloqueador de vento e, quando o jogador sair do colisor, o OnTriggerExit2D o desativará. Isso é ilustrado pela linha ciano entre o jogador e o emissor na imagem abaixo. Enquanto a linha estiver verde, o jogador estará protegido.

Por fim, precisávamos fazer com que o jogador recebesse a força do vento e se movesse na direção do vento. Para isso, temos um componente WindReceiver. Ele é responsável por verificar a intensidade do impacto do vento sobre o jogador e de que direção. Essas informações são coletadas por meio de um Raycast do jogador em direção ao receptor de vento. As informações são então usadas para saber se o emissor de vento está impactando o receptor, com quanta força e de que direção. Quando tivermos todas as informações, aplicaremos a força do vento usando nosso próprio controlador de movimento e moveremos o jogador na direção que precisamos.
Quando Diego começou a cometer os primeiros ataques, comecei a dar algum comportamento a Hailga.
Para a IA do Evil Wizard, usamos um recurso muito útil chamado Behavior Designer. Não posso recomendar o suficiente. É perfeito para designers de jogos que não codificam, de modo que o programador pode trabalhar na mecânica e o designer a coloca na árvore de comportamento do personagem, fazendo com que ela funcione como eles precisam sem codificação. Você pode aprender os conceitos básicos aqui.
Aqui está a árvore de comportamento da Hailga:

É uma árvore grande, mas não se assuste - é mais fácil do que parece.
Basicamente, usamos algumas tarefas no início da árvore para preparar a batalha. Por exemplo, para definir o chefe em sua primeira fase, reproduza a animação de introdução e redefina algumas variáveis.

Essas tarefas são executadas somente no início do combate, portanto, adicionamos um repetidor que teria o comportamento real do chefe, como você pode ver na próxima imagem.

A prioridade do comportamento do chefe é sempre a saúde. Com ele, controlamos se o chefe deve mudar para outra fase ou até mesmo se deve morrer. Portanto, primeiro perguntamos se o chefe tem mais de 75% de vida. Em caso afirmativo, executamos as tarefas da primeira fase, que são ice spikes, ice missiles e summon snow slimes (lacaios do chefe). Quando a saúde do chefe cai para menos de 75%, a árvore vai para o seletor a seguir na parte inferior da imagem e executa as tarefas correspondentes à segunda fase, e assim por diante, até que o chefe atinja sua fase final e o personagem morra com 0 de saúde.
Antes de passar para a próxima etapa, gostaria de mencionar o recurso de árvore de comportamento externo, que é uma maneira interessante de organizar grandes árvores de comportamento como esta.
Você já os viu na imagem anterior - os ícones com três caixas são árvores de comportamento externo.

Pense nas árvores de comportamento externo como um método em seu código: você chama o método em vários lugares em toda a lógica do jogo e ele executa o mesmo código em cada lugar, mas você só tem esse código em um lugar. Se você precisar alterar algo nessa lógica, altere o código desse método e ele será alterado em todos os locais em que o método for chamado. Aqui funciona da mesma forma. Você tem uma árvore de comportamento externo, que contém o comportamento para executar uma ação específica, por exemplo, "summon snow slimes".
Se eu entrar em nossa árvore de comportamento externo, encontrarei isso:

É como uma miniárvore de comportamento que verifica se um chefe não repete o mesmo ataque muitas vezes e se não há muitos lacaios no campo de batalha, depois convoca os lacaios, reproduz as falas de Hailga ou termina colocando o chefe em modo inativo.
Se eu quiser alterar a quantidade de lacaios que podem estar no campo de batalha de uma só vez, só preciso alterá-la na tarefa "Check Enemy Amount of Type" (Verificar quantidade de tipo de inimigo) dentro dessa árvore de comportamento externo, e isso funcionará para todas as partes da árvore que são usadas para convocar lacaios.
Para a criação de Hailga, nosso artista principal, Ruben Gómez, começou com a premissa de fazer referência a personagens existentes na esperança de que os jogadores os reconhecessem.
Nesse caso, usamos Jaina de Warcraft (como mencionado) e Elsa de Frozen como referências de personagens.
Isso é o que Ruben tem a dizer:
"Tendo a premissa em mente, comecei com o design do Hailga", disse Ruben. "Pegamos algumas características das roupas e dos penteados de cada referência, elementos que podem ser facilmente reconhecíveis em um sprite pixelado muito pequeno, e preenchemos o restante com imaginação (sem IA, apenas imaginação humana, a mesma que eu usava quando era criança)."

Durante a animação, precisávamos que os movimentos fossem rápidos sem perder a suavidade entre os quadros, então tentamos ganhar tempo com iterações mais rápidas para a ação de cada personagem. Sempre começamos com a versão final, cortando, reorganizando, dimensionando e girando cada parte do personagem para cada quadro da animação usando a interpolação mais próxima com a intenção de reutilizar alguns elementos e evitar o antialiasing.
Depois disso, fizemos um teste rápido de movimentos e ajustamos da mesma forma.

Quando o rascunho da animação ficou pronto, refinamos cada elemento, preenchemos os espaços vazios e acrescentamos detalhes.
Você pode ver a versão final de cada quadro na próxima imagem.

Enquanto as animações estavam em andamento, continuei testando e equilibrando a luta contra o chefe. Para isso, criamos uma cena chamada "Combat Zone", que usamos para testar chefes, inimigos, feitiços e muito mais. Basicamente, é uma pequena área que tem todas as ferramentas e recursos de que precisamos para testar sem tocar no jogo real.
Esta é a aparência do primeiro chefe Hailga quando testamos o personagem na cena Combat Zone:


Finalmente, quando estávamos satisfeitos com seu comportamento, funcionalidade e dificuldade, integramos a Hailga em seu lugar no jogo real.

Quando terminamos o comportamento e as animações da Hailga, começamos a integrar as animações do chefe usando o AnimatorImporterque é uma ótima ferramenta para integrar animações de pixel art feitas no Aseprite. Com ele, em apenas algumas etapas você tem tudo pronto.
Agora é hora de dar um toque especial ao chefe, e foi aí que nosso artista de efeitos visuais, Teky, entrou em ação. Leve-o embora, Teky:
Ei! Sergio Wajswol (também conhecido como Teky) aqui, programador e artista VFX da Evil Wizard.
O VFX de Hailga foi realmente desafiador, não apenas porque foi o primeiro chefe da equipe, mas também porque foi uma das minhas primeiras tarefas no jogo. Há várias sequências de efeitos visuais empregadas durante a luta contra o chefe - pelo menos uma por ataque -, mas vou concentrar minha atenção em apenas algumas.
Um dos momentos mais marcantes da batalha é a última transição de fase, na qual Hailga se enfurece e lança um raio de gelo contra o Evil Wizard, deixando o campo de batalha congelado.

Acredito que esse é um efeito muito bom para ser desmontado e mostrar as peças que fizeram a mágica acontecer. Para isso, dividimos a transição em duas partes de efeitos visuais: feixe de gelo e congelamento do piso.
Para a primeira peça, meu trabalho começava assim que Diego terminava de programar o ataque e geralmente vinha com um espaço reservado de boa aparência (nesse caso, um retângulo alongado), além de ele me desejar boa sorte. A partir daí, comecei a usar as ferramentas que eu sabia que já tinha em minha caixa de ferramentas. Mas, como era o início do desenvolvimento, eu estava com pouco material. No passado, eu havia usado o componente Line Renderer da Unity para renderizar uma linha entre dois pontos controlados por script, então comecei com isso e depois o combinei com um sombreador básico para adicionar cor às bordas e ao centro da linha.

Não é bem assim, como você pode ver acima. Algo que entendi rapidamente em VFX é que (ao contrário da filosofia clássica), "o todo é a soma das partes". Com isso, quero dizer que podem ser necessários vários sistemas para produzir o efeito desejado, não apenas um shader ou uma partícula.
Em seguida, eu precisava que o efeito se parecesse mais com um feixe (e que fosse menos sólido), então brinquei com o Shader Graph para conseguir isso. Tentarei explicar isso brevemente.
Para realizar o que eu queria, o sombreador precisava de três partes principais. Primeiro, usei uma textura desenhada anteriormente que era apenas um gradiente de espelho horizontal (você pode vê-la na próxima imagem como MainTex). Ao usar o nó "Pow", pude controlar facilmente a largura do feixe (a textura se multiplica e, como é um gradiente, encolhe o feixe).

Em seguida, usei o Simple Noise animado com o nó Tiling And Offset para duas finalidades:
Para dissolver o feixe em determinadas partes (sempre controlado por uma variável pública)
Para modificar o UV do feixe, fazendo com que ele pareça distorcido

Continuando, multipliquei o feixe resultante por uma cor HDR para controlar o brilho emitido. Por fim, peguei as bordas do feixe usando o nó de etapa e as multipliquei para obter uma cor diferente, deixando o centro do feixe em destaque.
Quando terminei, eu tinha algo assim para brincar com diferentes cores e variáveis.

Foi quando comecei a sentir que estava chegando a algum lugar, mas percebi que estava perdendo algo: o feixe estava sendo lançado do meio do nada.
Então, com a ajuda de partículas, criei uma esfera de gelo para que ela pudesse ser o ponto de lançamento do feixe:

Por fim, precisávamos de partículas ao longo do feixe para integrá-lo ao restante da área.

A segunda parte é mais curta, mas mais complicada. Para completar o efeito principal, precisávamos ser capazes de ler entre duas texturas - um piso não congelado e um congelado - mas em um ângulo radial seguindo a trajetória e a velocidade do feixe.
Para corresponder à velocidade, usamos scripts regulares para controlar a velocidade da viga em relação a uma variável de 0 a 1, ou seja, o quanto o piso deve ser congelado de acordo com a rotação atual da viga. Para ler as texturas, precisamos de um shader curto. Veja como dividimos o sombreador em duas partes para obter um gradiente radial e a leitura real.

Veja a seguir a fórmula aplicada para calcular o gradiente radial, levando em conta a posição do UV e indo exatamente de 0 a 1. Isso sincroniza o movimento do feixe com o valor congelado.

Esta é a aparência no local:

Para completar a cena, juntamos tudo e conseguimos um efeito legal, que serve tanto como transição para a fase final quanto como um dos ataques desse chefe.
Depois que tudo ficou pronto, Haakon Davidsen, o compositor do jogo, deu o toque final: uma música alucinante que faz com que os jogadores sintam o "calor" da batalha. Você pode ouvi-la aqui. E, é claro, uma atriz de voz - Breanna MacDowall - fez um trabalho incrível dando voz a Hailga.
Esperamos que você tenha gostado deste blog!
Experimente você mesmo a luta contra o chefe de Hailga ao conferir o Evil Wizard no Steam ou Xbox - e fique atento ao lançamento em outras plataformas. Leia mais histórias do Made with Unity diretamente dos desenvolvedores aqui.
