Aprendendo a programar jogos em Unity: codificando a coleta de pílulas pelo cenário

Construiremos os códigos responsáveis por, de fato, conceder ao médico as pílulas que auxiliarão no tratamento de seus pacientes.

Seja bem-vindo(a) ao GameDev: Aprendendo a programar jogos em Unity de hoje! Dando sequência à construção da funcionalidade de coleta de pílulas, cujos elementos tridimensionais foram devidamente posicionados nas mãos de Doutor Tratanildo Doencita em nosso encontro anterior, iremos iniciar a codificação das regras dessa coleta por meio de intervenções nos scripts controladores das pílulas cenográficas e da barra inferior de nosso Canvas.

Caso hoje seja a primeira vez que você lê conteúdos de nossa série, sinta-se especialmente convidado a juntar-se a nós em uma interessante jornada de aprendizados sobre o mundo do desenvolvimento de jogos digitais.

Por meio do uso da ferramenta Unity, iremos aprender a elaborar projetos práticos de programação de games dos mais variados estilos gráficos e de gameplay.

No momento, estamos trabalhando na construção do game Consultório do Dr. Tratanildo. Trata-se de um jogo ambientado em um consultório médico tridimensional, cujo enredo gira em torno de Tratanildo Doencita, renomado médico que consegue tratar as mais variadas enfermidades do mundo virtual por meio da aplicação de suas pílulas de saúde.


Não se preocupe se você não tiver conhecimentos prévios de programação de jogos ou de sistemas: nossa série foi pensada justamente para auxiliar quem nunca teve contatos prévios com o mundo da criação de games a tirar do papel a aventura que sempre sonhou em tornar realidade.

A partir do primeiro texto da série, são demonstradas desde as etapas mais básicas do processo, como a instalação e configuração da ferramenta Unity em nossas máquinas, até a construção dos cenários e fases de um game com variados elementos multimídia, a codificação das regras do jogo e a configuração da interação entre os diferentes componentes presentes em uma cena.

Gostou dessa ideia? Então não perca tempo e junte-se a nós nesta caminhada rumo a novos conhecimentos!

Um remédio de cada vez

Já há alguns encontros, estamos construindo paulatinamente a funcionalidade de coleta das pílulas, seja através da inserção de elementos visuais subordinados a alguns dos GameObjects da cena principal, seja por meio da codificação de funcionalidades via scripts controladores. Em relação a este último, conseguimos codificar comportamentos interessantes, como, por exemplo, a exibição da barra inferior do Canvas ocorrer apenas ao chegar perto das pílulas das prateleiras do consultório.

Hoje, iremos ampliar o escopo de atuação dos scripts controladores das pílulas cenográficas e da barra inferior do Canvas, programando as regras que serão cumpridas por Tratanildo Doencita ao se deparar com determinados medicamentos em seu consultório, dependendo de quais pílulas ele esteja segurando no momento.

Para começarmos nossas intervenções, abra 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.

Vamos começar as atividades inserindo algumas variáveis importantes para ambos os scripts. Na aba Project, abra a pasta Assets e, em seguida, Scripts. Clique duas vezes sobre o ícone do script ControllerBarraInferior para iniciarmos sua edição no Visual Studio.

Em comparação a seu estado atual, nosso script sofrerá uma radical metamorfose, ganhando importância em meio ao fluxo de tarefas a serem realizadas pelo game para determinar qual pílula será designada a cada uma das mãos de Tratanildo. Por ora, vamos introduzir o seguinte trecho de código, logo após a declaração das duas variáveis de tipo Text já presentes em sua estrutura:

    public Transform grupoPilulasMaoEsquerda, grupoPilulasMaoDireita;
    public ControllerFase controladorFase;
    internal string tipoPilula;

Minimize o Visual Studio, volte ao editor do Unity e, ainda com a pasta Scripts em evidência na aba Project, clique duas vezes sobre o ícone do script PegaPilula.

Insira a seguinte linha de código, logo após a declaração das variáveis do script e antes da declaração da função OnTriggerEnter:

    public Transform grupoPilulasMaoEsquerda, grupoPilulasMaoDireita;

Note que, para ambos os scripts, indicamos que serão necessárias interações com os grupos de pílulas presentes nas duas mãos do médico — grupos esses que atrelamos ao GameObject do modelo 3D do médico em cena no último encontro.

Vamos realizar, agora, uma grande intervenção no código da função OnTriggerEnter. Localize a seguinte linha de código:

         if (other.name == "DoutorCenario" && Geral.ModoDeJogoCorrente == "BuscaMedicamentos")

Exclua o código que está posicionado dentro das chaves do comando (logo após a referida linha) para iniciarmos a inserção de novos códigos de controle, começando pelo seguinte trecho:

            // Variáveis de controle para verificar se o doutor já está segurando pílulas em suas mãos
            bool temPilulaMaoDir = false;
            bool temPilulaMaoEsq = false;

            // Variáveis de controle para verificar se, dentre os tipos de pílulas nas mãos do doutor, uma delas é
            // igual ao tipo da pílula que está com esse script atrelado
            bool jaPegouEssaPilulaMaoDir = false;
            bool jaPegouEssaPilulaMaoEsq = false;

            // Verificação de presença de pílula na mão direita do médico
            for (int i = 0; i < grupoPilulasMaoDireita.childCount; i++)
                if (grupoPilulasMaoDireita.GetChild(i).gameObject.activeSelf)
                {
                    temPilulaMaoDir = true;
                    if (grupoPilulasMaoDireita.GetChild(i).name == "Pilula_" + tipoPilula)
                        jaPegouEssaPilulaMaoDir = true;
                }

            // Verificação de presença de pílula na mão esquerda do médico
            for (int i = 0; i < grupoPilulasMaoEsquerda.childCount; i++)
                if (grupoPilulasMaoEsquerda.GetChild(i).gameObject.activeSelf)
                {
                    temPilulaMaoEsq = true;
                    if (grupoPilulasMaoEsquerda.GetChild(i).name == "Pilula_" + tipoPilula)
                        jaPegouEssaPilulaMaoEsq = true;
                }

A organização é a alma do negócio

Antes de entendermos melhor quais ações serão realizadas pelo trecho de código recém-introduzido, é importante definirmos algumas regras comportamentais que nosso personagem principal deverá cumprir no andamento da aventura, enquanto estiver coletando materiais para iniciar seus tratamentos:
  • Caso o médico esteja com uma pílula em uma de suas mãos do mesmo tipo da que ele se aproximar no cenário, na barra inferior do Canvas será exibida uma opção para que ele possa devolver a referida pílula à prateleira.
  • Caso contrário, o comportamento poderá variar, dependendo da situação concreta observada:
    • Se o médico estiver com uma de suas mãos desocupada (ou ambas), ao chegar próximo a uma das pílulas do cenário, na barra inferior do Canvas será exibida uma opção para que ele possa pegar a pílula.
    • Se o médico estiver com as duas mãos ocupadas, a barra inferior não será exibida na tela.
Ao obrigarmos Tratanildo a devolver eventuais pílulas erradas coletadas pelo médico nas posições adequadas, manteremos o ambiente de trabalho organizado e limpo, evitando que nosso excêntrico doutor administre medicamentos errados a seus pacientes de forma involuntária. Isso é que é preocupação com a saúde dos pacientes, não?

Sobre o código introduzido no script, trata-se da estruturação de rotinas iniciais para que sejam verificadas as presenças de pílulas nas mãos do médico, por meio da aferição de GameObjects ativos subordinados a grupoPilulasMaoEsquerda ou a grupoPilulasMaoDireita.

Caso sejam encontrados medicamentos em uma ou ambas as mãos de Tratanildo, serão atualizados os valores das variáveis temPilulaMaoDir e temPilulaMaoDir, além dos valores de jaPegouEssaPilulaMaoDir e jaPegouEssaPilulaMaoEsq, caso a pílula que estiver segurando seja do mesmo tipo ao qual ele se aproximar no cenário.

Logo após o bloco de comandos inserido, introduza as seguintes linhas de código:

            // Regras do algoritmo a seguir:
            //   Caso já tenha pegado uma pílula do tipo da que está com esse script atrelado:
            //   - Opção a ser exibida: Devolver pílula
            //   Caso não tenha pego uma pílula desse tipo, e uma das mãos está vazia:
            //   - Opção a ser exibida: Pegar pílula
            //   Caso tenha duas pílulas nas mãos de outros tipos:
            //   -  Não exibir barra de opções

            bool ativarBarraInferior = true;

            if (!jaPegouEssaPilulaMaoDir & !jaPegouEssaPilulaMaoEsq)
            {
                if (temPilulaMaoDir & temPilulaMaoEsq)
                    ativarBarraInferior = false;
                else barraInferior.TextoBarraInferior.text = "Pegar pílula " + tipoPilula;
            }
            else
                barraInferior.TextoBarraInferior.text = "Devolver pílula " + tipoPilula;

            if (ativarBarraInferior)
            {
                barraInferior.TextoTeclaOpcao.text = "X";
                barraInferior.tipoPilula = tipoPilula;
                barraInferior.gameObject.SetActive(ativarBarraInferior);
            }


Basicamente, o novo trecho de código será responsável por colocar em ação as regras que descrevemos agora há pouco, interagindo, para isso, com variáveis e parâmetros de barraInferior, de forma semelhante a como a versão anterior do código do script PegaPilula interagia com os elementos visuais da barra inferior.

Salve o script e volte ao editor do Unity. Novamente, clique duas vezes sobre o ícone do script ControllerBarraInferior para concluirmos sua edição no Visual Studio.

Grandes intervenções

Logo após as linhas que contêm declarações de variáveis (antes do último fechamento de chaves do arquivo), introduza o seguinte conjunto de códigos:

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.X))
        {
            // Caso a opção informada no texto da barra inferior seja para pegar pílula,
            // será verificado se já tem pílula na mão direita:
            // Se positivo, a outra mão (esquerda) receberá a pílula de tipo 'tipoPilula'
            // Se negativo, a própria mão direita é que segurará a pílula

            if (TextoBarraInferior.text.StartsWith("Pegar pílula"))
            {
                bool jaAtivouDir = false;

                for (int i = 0; i < grupoPilulasMaoDireita.childCount; i++)
                    if (grupoPilulasMaoDireita.GetChild(i).gameObject.activeSelf)
                        jaAtivouDir = true;

                if (!jaAtivouDir)
                {
                    for (int i = 0; i < grupoPilulasMaoDireita.childCount; i++)
                        if (grupoPilulasMaoDireita.GetChild(i).name == "Pilula_" + tipoPilula)
                        {
                            grupoPilulasMaoDireita.GetChild(i).gameObject.SetActive(true);
                            controladorFase.pilulaMaoDireita = tipoPilula;
                        }
                }
                else
                {
                    for (int i = 0; i < grupoPilulasMaoEsquerda.childCount; i++)
                        if (grupoPilulasMaoEsquerda.GetChild(i).name == "Pilula_" + tipoPilula)
                        {
                            grupoPilulasMaoEsquerda.GetChild(i).gameObject.SetActive(true);
                            controladorFase.pilulaMaoEsquerda = tipoPilula;
                        }
                }
            }

            // Caso a opção informada no texto da barra inferior seja para devolver a pílula,
            // será verificado de qual mão do médico será retirada a pílula em questão,
            // além de se apagar o conteúdo da variável controladorFase.pilulaMaoDireita
            // ou controladorFase.pilulaMaoEsquerda, caso aplicável.

            else if (TextoBarraInferior.text.StartsWith("Devolver pílula"))
            {
                for (int i = 0; i < grupoPilulasMaoDireita.childCount; i++)
                    if (grupoPilulasMaoDireita.GetChild(i).name == "Pilula_" + tipoPilula)
                    {
                        grupoPilulasMaoDireita.GetChild(i).gameObject.SetActive(false);
                        controladorFase.pilulaMaoDireita = "";
                    }
                        
                for (int i = 0; i < grupoPilulasMaoEsquerda.childCount; i++)
                    if (grupoPilulasMaoEsquerda.GetChild(i).name == "Pilula_" + tipoPilula)
                    {
                        grupoPilulasMaoEsquerda.GetChild(i).gameObject.SetActive(false);
                        controladorFase.pilulaMaoEsquerda = "";
                    }
            }          
            
            // Por fim, desliga-se a barra inferior
            gameObject.SetActive(false);
        }
    }


O código introduzido em ControllerBarraInferior opera quase que de forma sequencial ao comportamento de PegaPilula: caso a barra inferior do Canvas tenha sido ativada por ação de PegaPilula, assim que o jogador pressionar a tecla X serão realizadas verificações sobre a natureza da ação solicitada (apanhar ou devolver o medicamento) e a mão à qual será concedida (ou tomada) a pílula em questão.

Uma adição interessante realizada no código de ControllerBarraInferior refere-se às variáveis de controle pilulaMaoEsquerda e pilulaMaoDireita de ControllerFase (aqui, representado pela instância controladorFase). Assim que a pílula é coletada ou devolvida, a informação referente à ação realizada será registrada em uma dessas variáveis, permitindo, posteriormente, que utilizemos essas informações para definir quais pílulas aparecerão no labirinto, ao se iniciar o tratamento dos pacientes.

Salve o script e feche o Visual Studio. Volte ao editor do Unity para realizarmos as últimas intervenções de hoje em nosso projeto.

Na aba Hierarchy, selecione os cinco objetos que representam as pílulas das prateleiras e que se encontram subordinados a PilulasCenograficas, em CenarioFixo. Para cada um dos GameObjects selecionados, modifique o valor dos atributos de Pega Pilula listados a seguir via aba Inspector, de acordo com o exemplificado:
  • Grupo Pilulas Mao Esquerda: clique sobre o campo, selecione a opção Scene e, na barra de pesquisa, localize o item ContainerCapsulaEsq.
  • Grupo Pilulas Mao Direita: repita os passos descritos para o atributo anterior, selecionando ao fim o item ContainerCapsulaDir.
Voltando à aba Hierarchy, selecione o objeto BarraInferiorInfo, subordinado a Canvas. Na aba Inspector, modifique o valor dos atributos de seu componente Controller Barra Inferior conforme listado a seguir:
  • Grupo Pilulas Mao Esquerda: ContainerCapsulaEsq;
  • Grupo Pilulas Mao Direita: ContainerCapsulaDir;
  • Controlador Fase: indique o objeto de nome ControladorFase.
Por fim, na aba Hierarchy, precisaremos localizar os objetos ContainerCapsulaEsq e ContainerCapsulaDir para que possamos desativar os medicamentos que estavam sendo exibidos nas mãos de nosso querido médico, permitindo a correta execução dos códigos que elaboramos em nosso encontro de hoje.

Talvez você tenha pensado ser uma tarefa difícil lembrar de cabeça onde posicionamos os dois objetos, visto que eles foram alocados em uma sequência longa de objetos subordinados a DoutorCenario. Para casos como esse, podemos lançar mão da ferramenta de busca da aba Hierarchy; mas, caso prefira, vamos relembrar a sequência hierárquica que devemos percorrer para encontrar o objeto subordinado à mão esquerda do personagem:
  • ContainerCapsulaEsq:
    • ROOTJ;
    • Spine01J;
    • Spine02J;
    • Spine03J;
    • Spine04J;
    • lClavicleJ;
    • lShoulderJ;
    • lElbowJ;
    • lWristJ.
A seguir, a sequência hierárquica para o objeto subordinado à mão direita do personagem:
  • ContainerCapsulaDir:
    • ROOTJ;
    • Spine01J;
    • Spine02J;
    • Spine03J;
    • Spine04J;
    • rClavicleJ;
    • rShoulderJ;
    • rElbowJ;
    • rWristJ.
Desative todos os GameObjects subordinados aos dois objetos informados, tal como ilustrado a seguir:


É chegada a hora de testarmos a execução de nosso game para vermos em ação as intervenções realizadas hoje. Para tal, vá até a aba Game e clique sobre o ícone do botão Play:

Após interromper a simulação, clicando novamente sobre o ícone do botão Play e voltando a 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

Temos, enfim, um sistema de coleta de medicamentos no cenário funcional, com interações reais entre os elementos tridimensionais do consultório, a barra inferior do Canvas e as variáveis que utilizaremos em breve para informar ao game quais serão as pílulas a serem fornecidas aos pacientes durante os tratamentos. Parabéns por ter chegado a esta etapa!

Nos próximos encontros, vamos aproveitar que iniciamos a implementação em código das interações entre o médico e as pílulas para programar, também, a sequência definitiva de ações a serem realizadas pelo game para que a ação se inicie de fato.

Nosso próximo texto já encontra-se disponível, continue conosco nessa jornada de conhecimento e fique ligado sempre aqui no GameBlast!

Revisão: Ives Boitano
Siga o Blast nas Redes Sociais
Rodrigo Garcia Pontes
Entendo videogames como sendo uma expressão de arte e lazer e, também, como uma impactante ferramenta de educação. No momento, doutorando em Sistemas da Informação pela EACH-USP, desenvolvendo jogos e sistemas desde 2020. Se quiser bater um papo comigo, nas redes sociais procure por @RodrigoGPontes.
Este texto não representa a opinião do GameBlast. Somos uma comunidade de gamers aberta às visões e experiências de cada autor. Você pode compartilhar este conteúdo creditando o autor e veículo original (BY-SA 3.0).