Se hoje for a primeira vez que você tem contato com nossa série, sinta-se especialmente convidado a juntar-se a nós em um divertido processo de aprendizagem sobre conceitos de desenvolvimento de games. Por meio da elaboração de projetos práticos, aprenderemos juntos sobre como a ferramenta Unity pode nos auxiliar a tirar do papel jogos dos mais diferentes estilos de gameplay.
No momento, estamos desenvolvendo o projeto Consultório do Dr. Tratanildo. Trata-se de um game que mescla características de um platformer tridimensional e desafios inspirados em jogos clássicos do gênero puzzle, como Dr. Mario. Por meio de seu desenvolvimento, estamos aprendendo sobre diversos aspectos da construção de um jogo, tais como sobre o posicionamento e configuração de elementos 3D no cenário e a programação de seus comportamentos na aventura.
Nossa série é construída visando atender a todos que tenham interesse em aprender sobre programação de games, mesmo àqueles que não tiveram oportunidades de ter contato com algum conteúdo sobre o tema anteriormente.
A partir do primeiro texto da série, abordamos desde conceitos considerados mais simples, como a instalação e configuração da ferramenta em nossos computadores, até tópicos considerados mais desafiadores, como a programação de scripts controladores de regras e comportamentos dos elementos do game, a inserção e configuração de elementos multimídia nas fases e a interação entre todos os elementos que compõem o projeto como um todo.
Aperte os cintos e venha conosco para que, juntos, possamos seguir nesta caminhada rumo a novos conhecimentos!
Acrescentando papeis a um script controlador
Após as alterações que realizamos em nossos últimos encontros, já temos em nosso projeto os principais elementos que serão importantes no momento em que o jogador controlar, de fato, o maquinário responsável pelos excêntricos tratamentos de Tratanildo Doencita no game: os caminhos do labirinto, os agentes de doenças e as pílulas de saúde. Realizamos, inclusive, alguns testes práticos, ao posicionarmos manualmente medicamentos e micróbios de cores diferentes no labirinto, como podemos ver na ilustração a seguir:
Da mesma forma que, por meio de um script controlador, permitimos ao game criar dinamicamente os caminhos internos do labirinto, também iremos possibilitar ao jogo o surgimento de microrganismos e medicamentos na representação interna dos corpos dos pacientes de acordo com as coordenadas que indicarmos, por meio de alterações que realizaremos no script MontaLabirinto. Essa intervenção será importante para permitir que, futuramente, consigamos criar desafios personalizados para cada paciente que vier a ser atendido no consultório.
Vamos começar, então, abrindo nosso projeto para edição: no Unity Hub, clique duas vezes sobre o item referente ao projeto Consultório do Dr. Tratanildo. Na interface inicial do editor, na aba Project, abra a pasta Assets, Scenes e, por fim, clique duas vezes no ícone da cena ConsultorioScene.
Na aba Project, abra a pasta Assets e, em seguida, a pasta Scripts. Clique duas vezes sobre o ícone de MontaLabirinto para editarmos o script no Visual Studio.
No momento, o script está configurado para controlar apenas a criação dos caminhos internos do labirinto, por meio da inserção e posicionamento de cubos “clonados” de um cubo padrão (cuboReferencia). A atual estrutura do script pode ser observada na imagem a seguir:
Para que o script possa controlar, também, o aparecimento e posicionamento dos monstrinhos e dos remédios em cena, precisaremos adicionar e alterar uma quantidade considerável de novas linhas de código; porém, a lógica de inserção e posicionamento dos novos elementos será semelhante à que utilizamos na construção inicial do script.
Começando as intervenções no código, logo após as declarações das variáveis referentes aos cubos que compõem os caminhos do labirinto (imediatamente antes de “public void Montar()”), introduza as seguintes linhas de código:
public Vector3[] posicoesPilulas, posicoesDoencas;
public GameObject[] pilulasReferencia, doencasReferencia;
public Transform grupoMedicamentos, grupoDoencas;
internal GameObject[] pilulasCriadas = new GameObject[0];
internal GameObject[] doencasCriadas = new GameObject[0];
O código que acabamos de inserir no script representa a declaração de algumas variáveis voltadas ao posicionamento no labirinto para as pílulas e agentes de doenças a serem inseridos (posicoesPilulas e posicoesDoencas), quais serão os tipos de medicamentos e micróbios a serem criados em cada posição (pilulasReferencia e doencasReferencia) e outras variáveis que nos auxiliarão, por exemplo, a organizar hierarquicamente os novos GameObjects em cena (grupoMedicamentos e grupoDoencas) e a “limpar” o conteúdo do labirinto ao trocarmos de paciente (pilulasCriadas e doencasCriadas).
Agora, dentro da estrutura da função Montar(), vamos trocar o código responsável por apagar os cubos previamente criados (em destaque, no lado esquerdo da próxima imagem) pelo código descrito a seguir:
// Apagar cubos, pílulas e agentes de doenças, se já houver
foreach (GameObject go in cubosCriados)
DestroyImmediate(go);
foreach (GameObject go in pilulasCriadas)
DestroyImmediate(go);
foreach (GameObject go in doencasCriadas)
DestroyImmediate(go);
Além de remover da estrutura interna do labirinto os obstáculos que poderiam estar presentes em cena (devido a algum paciente que, ali, fora anteriormente atendido), agora serão removidos, também, eventuais pílulas e microrganismos presentes ali antes do início da atividade.
O uso da função DestroyImmediate, em substituição à função Destroy que foi utilizada na versão anterior do trecho de código, nos servirá para garantir que os objetos “antigos” tenham sido concretamente retirados de cena antes da inserção de novos elementos, evitando problemas de colisão entre objetos que “estão de saída” e GameObjects recém-inseridos.
Por fim, logo após o código responsável pela criação dos cubos no labirinto, introduza o seguinte bloco de códigos no script:
// Posicionar no labirinto as novas pílulas e agentes de doenças
pilulasCriadas = new GameObject[posicoesPilulas.Length];
doencasCriadas = new GameObject[posicoesDoencas.Length];
for (int i = 0; i < posicoesPilulas.Length; i++)
{
pilulasCriadas[i] = Instantiate(pilulasReferencia[i], grupoMedicamentos);
pilulasCriadas[i].SetActive(true);
pilulasCriadas[i].name = "PilulaSaude_" + i;
pilulasCriadas[i].transform.localPosition = posicoesPilulas[i];
}
for (int i = 0; i < posicoesDoencas.Length; i++)
{
doencasCriadas[i] = Instantiate(doencasReferencia[i], grupoDoencas);
doencasCriadas[i].SetActive(true);
doencasCriadas[i].name = "AgenteDoencas_" + i;
doencasCriadas[i].transform.localPosition = posicoesDoencas[i];
}
Ao compararmos os novos comandos introduzidos no script com o trecho de código responsável pela montagem dos caminhos internos do labirinto, encontraremos diversas semelhanças entre ambos: tanto para pílulas e micróbios quanto para os cubos que compõem os caminhos, serão criados novos GameObjects em cena baseados em seus elementos de referência, atrelados a um grupo de objetos do labirinto e posicionados de acordo com as coordenadas programadas. Porém, existem algumas diferenças notáveis entre os grupos de código, cujos detalhes serão listados a seguir:
- Para a inserção dos cubos utilizamos apenas um objeto de referência (cuboReferencia), devido ao fato de que a “composição física” dos caminhos é sempre igual; já para os medicamentos e para os agentes de doenças, foi necessário utilizamos vetores de objetos de referência (pilulasReferencia[] e doencasReferencia[]), justamente pelo fato de podermos escolher diferentes tipos de remédios e de micróbios para compormos o ambiente do labirinto.
- Ao criarmos cada novo cubo em cena, por meio da função Instantiate(), utilizamos cuboReferencia.transform.parent como elemento-base para subordinarmos hierarquicamente os novos GameObjects inseridos. Já para as pílulas e para os agentes de doenças, iremos subordinar os novos objetos criados aos objetos relacionados às variáveis grupoMedicamentos e grupoDoencas. Na prática, o resultado final será o mesmo (pílulas subordinadas a Medicamentos e agentes de doenças subordinados a Doencas), mas isto nos permitirá utilizarmos Prefabs ainda não inseridos em cena como objetos de referência na criação de medicamentos e monstrinhos no labirinto, o que veremos mais adiante.
- Por fim, não será realizada a alteração do parâmetro transform.localScale de pílulas e micróbios, pois suas proporções físicas serão as mesmas de seus objetos de referência.
Mantenha intactos os códigos presentes após o fechamento da última chave da função Montar(), tais como os pertencentes à função OnEnable(). Salve o script, feche o Visual Studio e retorne ao editor do Unity para continuarmos as configurações das novas funcionalidades adicionadas ao game.
Configurando a criação de pílulas e micróbios
Depois de atrelarmos novas “responsabilidades” ao script MontaLabirinto, vamos realizar algumas modificações na estrutura e na hierarquia dos objetos inseridos em cena, permitindo ao novo código ser executado corretamente.
Na aba Hierarchy, exclua todos os objetos subordinados a Medicamentos e, também, os subordinados a Doencas:
Agora, ainda na aba Hierarchy, selecione o GameObject Labirinto. Na aba Inspector, modifique o valor dos atributos Grupo Medicamentos e Grupo Doencas indicando a cada elemento os GameObjects de nomes Medicamentos e Doencas, respectivamente, conforme exemplificado a seguir:
Como forma de experimentarmos a inserção dinâmica de pílulas e agentes de doença no labirinto, vamos ordenar ao game a inserção de cinco pílulas e de cinco agentes de doenças no game. Modifique o valor numérico presente ao lado direito dos atributos Posicoes Pilulas, Posicoes Doencas, Pilulas Referencia e Doencas Referencia para 5:
Exiba o conteúdo de Posicoes Pilulas, clicando sobre a setinha presente ao lado esquerdo do atributo. Para cada um dos elementos do vetor apresentado, introduza os seguintes valores de posicionamento:
- Element 0: X = -2, Y = 0.5, Z = -6;
- Element 1: X = -7.5, Y = 0.5, Z = -7;
- Element 2: X = 2, Y = 0.5, Z = -3;
- Element 3: X = 7.5, Y = 0.5, Z = -7;
- Element 4: X = 0, Y = 0.5, Z = 4.75.
Realizaremos operação semelhante para Posicoes Doencas, concedendo dessa vez os seguintes valores de posicionamento:
- Element 0: X = 5, Y = 0, Z = 0;
- Element 1: X = -4, Y = 0, Z = 0;
- Element 2: X = 5, Y = 0, Z = 8;
- Element 3: X = 4, Y = 0, Z = -8;
- Element 4: X = -7, Y = 0, Z = 7.
Agora, iremos modificar os valores dos elementos do atributo Pilulas Referencia, indicando qual tipo de medicamento será introduzido no labirinto, respeitando os posicionamentos indicados anteriormente. Porém, talvez você esteja se perguntando sobre como iremos indicar ao jogo os medicamentos de referência se realizamos a exclusão dos GameObjects subordinados a Medicamentos anteriormente.
Aproveitando o fato de que, nos encontros anteriores, configuramos Prefabs que contemplam todos os componentes e características necessários para que as pílulas se comportem de forma adequada no labirinto, o Unity permite a utilização desse tipo de Asset diretamente como “molde” para gerar novos itens em cena.
Para isso, ao clicarmos na bolinha ao lado do elemento cujo valor queremos alterar, indicaremos ao Unity que iremos criar um objeto a partir de um Asset, clicando na aba destacada em laranja na imagem a seguir. Para Element 0, por exemplo, escolha o Prefab de nome Pilula_azul_lab:
Repita a operação para cada um dos demais elementos do vetor Pilulas Referencia, concedendo os seguintes valores:
- Element 1: Prefab de nome Pilula_amarela_lab;
- Element 2: Prefab de nome Pilula_vermelha_lab;
- Element 3: Prefab de nome Pilula_roxa_lab;
- Element 4: Prefab de nome Pilula_verde_lab.
Por fim, vamos modificar os valores dos elementos do atributo Doencas Referencia da mesma forma que realizamos agora há pouco para Pilulas Referencia, utilizando Assets como base para a criação dos objetos. Conceda ao atributo os seguintes valores:
- Element 0: Prefab de nome DoencaRoxa;
- Element 1: Prefab de nome DoencaAmarela;
- Element 2: Prefab de nome DoencaVerde;
- Element 3: Prefab de nome DoencaVermelha;
- Element 4: Prefab de nome DoencaAzul.
Chegou a tão esperada hora de testarmos as novas funcionalidades desenvolvidas. Para isso, vá à aba Game e clique sobre o ícone do botão Play:
Pela simulação da execução, é possível notar, observando os elementos da aba Hierarchy, que os medicamentos e os micróbios são criados dinamicamente, sendo subordinados automaticamente a Medicamentos e Doencas, respectivamente.
Encerre a simulação da execução, clicando novamente sobre o ícone do botão Play e retornando à aba Scene. Não se esqueça de salvar a cena (menu File, opção Save) e o projeto (menu File, opção Save Project) antes de fechar o editor.
Próximos passos
A cada rodada de alterações que realizamos em nosso projeto, acrescentamos interessantes funcionalidades à nossa aventura. Hoje não foi diferente, ao possibilitarmos o surgimento dinâmico dos agentes de doenças e dos remédios dentro da estrutura do labirinto, o que, futuramente, irá facilitar o processo de construção de diferentes conjuntos de “fases” em nosso game, representadas pelos pacientes que vierem visitar o consultório.
Em nossos próximos encontros, continuaremos a desenvolver melhorias em relação ao comportamento entre micróbios e pílulas, além de iniciarmos a configuração do controlador geral do game, que irá contemplar aspectos importantes da aventura, como o tempo restante e a pontuação.
Nosso próximo encontro será no dia 2 de fevereiro. Até mais! Fique sempre ligado nas novidades do GameBlast!
Revisão: Davi Sousa