Da ideia à implementação: a mecânica de margarina do Pãozito
A mecânica de jogo é um dos elementos mais importantes para criar uma experiência divertida e desafiadora para os jogadores. E com o avanço da tecnologia, os desenvolvedores têm mais ferramentas à sua disposição para criar mecânicas inovadoras e interessantes.
Neste artigo, vamos falar sobre uma nova mecânica de jogo desenvolvida em parceria com a marca Doriana, que faz parte do novo capítulo do jogo. Essa mecânica consiste em uma curva (de margarina) que pode ser usada tanto como um auxílio para o deslocamento do personagem quanto como um obstáculo a ser superado.
Ao colidir com a curva, o personagem é acelerado para seguir o trajeto dela até o fim. Além disso, há buracos na curva que possibilitam que o personagem atravesse para chegar ao outro lado. Essa mecânica oferece uma nova camada de estratégia e desafio ao jogo, tornando a jogabilidade ainda mais envolvente.
Ao longo deste artigo, vamos detalhar como essa mecânica foi desenvolvida e implementada usando a Unity. Se você é um desenvolvedor de jogos, entusiasta ou simplesmente está interessado em conhecer os bastidores do desenvolvimento de jogos, continue lendo!
Design da Mecânica
Antes de começar o desenvolvimento da mecânica, o Game Designer da equipe, Anderson Verissimo, desenhou a ideia inicial com a intenção de criar uma experiência única em que o jogador precisasse formular estratégias diferentes para interagir com a mecânica. Seria necessário pensar em como utilizar o fluxo de margarina da melhor forma possível para obter todos os coletáveis, enquanto se atentar também para os buracos que surgem ocasionalmente. Para isso, ele imaginou uma curva que pudesse ser facilmente manipulada para criar diferentes fases, com múltiplos fluxos de margarina e controle dos parâmetros de força da aceleração, tempo de surgimento dos buracos e velocidade de movimento dos buracos.
Com essas condições em mente, a equipe começou a planejar a implementação da mecânica. Foi decidido que a curva seria uma Bézier, uma curva matemática que permite criar formas suaves e flexíveis. Além disso, seria possível controlar a força da aceleração, o tempo de surgimento dos buracos e a velocidade de movimento dos buracos por meio de scripts na Unity.
Além disso, nesse estágio de desenvolvimento, a parte visual da mecânica ainda seria estudada e definida pela artista do time, Fernanda Rigler. A equipe ainda não sabia como iria fazer a movimentação visual do fluxo de manteiga. Seria via animação de texturas, shaders ou vértices? Essa seria uma questão a ser resolvida posteriormente, mas a equipe estava confiante de que encontraria uma solução que atendesse às expectativas visuais do jogo.
Com o planejamento definido, a equipe partiu para a implementação da mecânica, que será detalhada nas próximas seções.
Prototipagem
A fase de prototipagem é essencial em qualquer desenvolvimento de jogo. Ela tem como principais objetivos concluir se a mecânica é tecnicamente viável, se é divertida e, também, falhar rápido. É o momento de testar hipóteses e validar as ideias iniciais, a fim de evitar problemas no desenvolvimento futuro e garantir a qualidade do jogo final.
Durante essa fase, buscamos implementar a mecânica utilizando uma implementação de Spline obtida em um tutorial do Catlike Coding. Embora a Unity possua um pacote para isso, ele não era suportado na versão do projeto que estávamos utilizando (2021.3).
Para a renderização visual da curva, utilizamos um componente LineRenderer, que permite a renderização de uma linha por meio de pontos (que extrairíamos da curva). Ele é responsável por criar uma faixa visível que representa a curva ao longo do caminho definido pela Spline. O componente é bastante versátil, permitindo a customização de diversos parâmetros, como largura da linha, cor e material utilizado para renderização. Nossa intenção era utilizar essa ferramenta para dar forma visual à mecânica de curva que estávamos desenvolvendo.
Uma das primeiras coisas que testamos foi se era possível criar uma máscara visual na curva, para que pudéssemos criar buracos por onde o personagem pudesse atravessar. Essa máscara é responsável por criar um buraco na linha do LineRenderer, permitindo posteriormente que o personagem possa atravessar a curva. Para isso, o primeiro teste foi feito com um shader criado através do Shader Graph da Unity, utilizando a função SphereMask. Felizmente, tivemos sucesso no teste e foi possível criar a máscara com sucesso.
Com o sucesso do primeiro teste da máscara, partimos para a renderização da linha conforme os pontos da curva. Para isso, atualizamos os pontos do LineRenderer com os pontos da curva. Em paralelo, testamos criar um colisor (PolygonCollider2D) baseado nos pontos da curva, mas falhamos na implementação.
Então, decidimos usar um EdgeCollider2D e tivemos sucesso. O EdgeCollider2D é uma opção mais simples do que o PolygonCollider2D, pois só requer a definição dos mesmos pontos que foram usados no LineRenderer. Isso permitiu uma implementação mais eficiente e eficaz da mecânica.
Para fazer o personagem ser acelerado na curva, foi usado um SurfaceEffector2D, um componente nativo da Unity que permite definir uma força em objetos que entram em contato com superfícies. Dessa forma, a curva foi definida como uma superfície com um SurfaceEffector2D aplicado, e o personagem passou a ser acelerado ao entrar em contato com ela.
Além disso, realizamos testes adicionais de animação de textura na renderização da curva, movimentação da máscara e máscara de colisão. A animação da textura permitiria uma movimentação da textura junto com o fluxo de margarina, trazendo uma naturalidade para a experiência. Como definido no design, a máscara deve ser móvel e percorrer o trajeto todo definido pela curva, e deve ser possível que o personagem atravesse o buraco da máscara. A função SphereMask permite que movimentemos a máscara e também, adicionamos um colisor na máscara para que o personagem possa atravessar o colisor da curva ao passar por ela.
Dessa forma, a prototipagem permitiu concluir que a mecânica da curva era tecnicamente viável e divertida, além de possibilitar a identificação de falhas rapidamente, garantindo um processo mais eficiente e econômico. Em seguida, só faltava validar a implementação de fluxos múltiplos.
O Desafio
Para implementar os fluxos múltiplos, decidimos criar uma curva, um LineRenderer e um EdgeCollider2D para cada fluxo. Isso nos permitiu ter uma curva independente para cada fluxo, possibilitando diferentes caminhos e velocidades. Para a renderização visual, utilizamos um shader que implementava 4 máscaras, uma para cada fluxo. Essa solução nos trouxe um limite de fluxos na fase, e isso rapidamente se tornou um problema.
Nesse ponto, a mecânica já estava sendo estressada pelo Game Designer e seu primeiro feedback foi que ele precisaria de mais máscaras para cumprir o propósito esperado. Isso significa que teríamos que fazer o mascaramento de outra forma, preferencialmente que não tivesse o limite de 4 máscaras. Para isso, optamos por mudar a forma de mascaramento do shader para Stencil. No entanto, descobrimos que não havia suporte para Stencil no Shader Graph, o que significava que teríamos que escrever um shader manualmente.
Após algumas pesquisas, encontramos uma implementação de shader Stencil que poderíamos adaptar às nossas necessidades. O shader permitia que criássemos máscaras ilimitadas e de formatos diversos (o anterior era somente círculos). Com essa implementação, pudemos criar novos fluxos e, ao mesmo tempo, manter o desempenho do jogo, já que todos os fluxos utilizavam o mesmo material.
Isso nos permitiu criar níveis mais complexos e desafiadores para o jogador. A mudança também nos deu mais liberdade para experimentar novas ideias de fases e explorar as possibilidades da mecânica do jogo.
Polimento
Com as principais funcionalidades da mecânica concluídas, era hora de melhorar o visual. Ainda com a ideia visual incerta, decidimos testar algumas alternativas de animação da curva. A primeira delas foi tentar animar as posições dos pontos da curva para que “balançassem”. Para que isso funcionasse sem comprometer o desempenho, testamos usar o Job System da Unity, e acabou funcionando perfeitamente.
Porém, esse tipo de animação poderia também ser feito diretamente no shader sem termos que alterar nada no LineRenderer, ou seja, poderíamos ter uma melhoria de desempenho. Fizemos então um teste de animação seguindo a mesma lógica do experimento anterior, mas aplicando a movimentação nos vértices no shader. Também tivemos sucesso nesse teste.
Assim que a artista do time trouxe a solução visual, decidimos mudar mais uma vez a animação da curva, dessa vez para animação de textura. Esse tipo de animação deu mais liberdade à artista para que desenhasse o fluxo da forma que fizesse mais sentido dentro da solução proposta.
Com esses pontos concluídos, ainda melhoramos as texturas das máscaras e fizemos alguns ajustes pequenos de parametrização para chegarmos no estado que a mecânica está hoje no jogo.
Conclusão
A nossa experiência de desenvolvimento com a mecânica de fluxo de margarina nos mostrou que a prototipagem é essencial para validar ideias e testar a viabilidade técnica e diversão da mecânica. Além disso, tivemos que lidar com desafios inesperados, como o limite de máscaras e a necessidade de implementar um shader manualmente. No final, conseguimos superar esses obstáculos e chegar em um resultado que atendesse aos objetivos do jogo. Esperamos que nossa experiência possa inspirar outros desenvolvedores e incentivá-los a serem criativos e persistentes na busca por soluções.
E vocês, o que acharam de todo esse processo? No segundo capítulo do Pãozito ainda tivemos a introdução de outras mecânicas que também trouxeram experiências novas bem divertidas e interessantes. Querem saber mais? Comentem suas dúvidas e impressões e fiquem ligados nas nossas redes para mais novidades!