Aprendendo a programar jogos em Unity: exibindo mensagens sobre os objetivos

Implementaremos a funcionalidade do mostrador de objetivos, por meio de intervenções em scripts controladores.

em 16/11/2025
Seja bem-vindo(a) ao GameDev: Aprendendo a programar jogos em Unity! Após realizarmos, no encontro anterior, interessantes intervenções sobre o comportamento dinâmico dos agentes de doenças, realizaremos hoje a implementação de uma nova funcionalidade que permitirá a exibição em tela dos objetivos a serem alcançados durante o tratamento do paciente atual.

Se hoje for a primeira vez que você está acessando conteúdos de nossa série, sinta-se especialmente convidado a mergulhar de cabeça conosco em um oceano de novos aprendizados sobre o mundo do desenvolvimento de jogos digitais.

Por meio do uso da ferramenta Unity, estamos desvendando diferentes maneiras de tirarmos do papel aqueles jogos que sempre sonhamos em ver tornarem-se realidade. Para isso, estamos desenvolvendo projetos práticos de programação de games, abordando a cada encontro novos tópicos que nos ajudarão a construir diferentes aventuras, dos mais variados estilos gráficos e de gameplay.

A partir do primeiro texto da série, são abordadas desde a instalação e a configuração da ferramenta em nossos computadores até as etapas que podem ser consideradas por alguns como mais “desafiadoras”, como a construção das fases, a configuração dos personagens e a codificação dos comportamentos e regras dos jogos.

No momento, o jogo em que estamos trabalhando chama-se Consultório do Dr. Tratanildo. Trata-se de um game inspirado em clássicos dos anos 1980 e 1990, como Pac-Man (Namco, 1980) e Dr. Mario (Nintendo, 1990), mas que lança mão de tecnologias atuais para a ambientação dos desafios em um consultório médico tridimensional.


Fique tranquilo caso ainda não tenha tido a oportunidade de aprender conceitos sobre codificação de jogos ou de sistemas digitais em geral, pois nossa série é desenvolvida de forma que, gradualmente, todos possam experimentar e aprender sobre o processo de criação de jogos, podendo aplicar as práticas exemplificadas em seus projetos pessoais.

Caso tenha gostado da ideia de criar um jogo do zero, não se acanhe e junte-se a nós em uma divertida jornada em busca de novos conhecimentos e muita diversão!

Mensagens na barra de informações

Um dos elementos que reservamos para ajudar o jogador a entender o que ele deve fazer para curar os pacientes de Tratanildo Doencita é a barra de informações, representada pelo GameObject BarraInformacoesAcao, cujos elementos são exibidos diretamente sobre o Canvas da cena, especificamente no canto superior da tela.

Dentre os elementos presentes na referida barra, o GameObject MensagemMomento é o responsável por exibir textualmente dicas sobre o que é necessário fazer naquele momento. Uma das possibilidades que podemos explorar é a sua utilização para indicação ao jogador de informações sobre quantos agentes de doenças precisam ser extirpados para curar o enfermo.

Por enquanto, como pudemos notar nos encontros anteriores, MensagemMomento ainda não foi utilizado adequadamente, apresentando apenas um texto genérico enquanto Tratanildo percorre o cenário em busca de pílulas miraculosas:

Para que o elemento possa funcionar da forma que esperamos, precisaremos realizar ajustes em códigos de diferentes scripts controladores, permitindo a comunicação entre alguns elementos e a troca de informações relevantes, como a quantidade de agentes restantes no labirinto.

Para tal, vamos abrir o 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 AssetsScenes e, por fim, clique duas vezes no ícone da cena ConsultorioScene.

Na aba Project, abra a pasta Assets e, em seguida, Scripts. O primeiro script a receber intervenções será o ControllerFase, portanto clique duas vezes sobre seu ícone para que possamos editá-lo, por intermédio do Visual Studio.

Inicialmente, logo após a primeira abertura de chaves do arquivo, acrescente as seguintes linhas de código:

    // Instância atual do script
    public static ControllerFase instance;

Para permitir que determinados scripts se comuniquem com o controlador de fases, incluímos uma variável estática de tipo ControllerFase no bloco de variáveis do script. Por meio de referências à variável instance, os agentes de doenças poderão comunicar ao controlador o momento em que foram eliminados do labirinto, atualizando o valor de agentes restantes a serem tratados.

Ainda sobre essa variável estática, logo após a abertura de chaves do método void Start, acrescente a seguinte linha de códigos:

        instance = this;

Dessa forma, garantiremos que, ao se acionar a variável instance, estaremos interagindo com o controlador de fases atualmente em execução durante a cena.

Antes de realizarmos as próximas intervenções no script, voltando ao bloco de declaração de variáveis de ControllerFase podemos notar a presença de um conjunto de variáveis de tipo int que foram reservadas para auxiliar no cálculo de elementos a serem tratados durante a fase que estiver sendo executada no momento:

Até o momento, essas variáveis não foram utilizadas para a construção de nenhum processo presente atualmente nas estruturas que construímos para o game, porém o grupo que representará a quantidade de monstrinhos restantes dentro do labirinto será útil tanto para a configuração do elemento visual que apresentará os desafios a serem solucionados na fase quanto para as lógicas que permitirão concluirmos um tratamento e avançarmos para o paciente seguinte.

A alteração dos valores de qtdMonstrosAzuisRestantes e de suas variáveis “irmãs” será realizada tanto no momento de construção dos labirintos quanto ao se eliminar um agente de doenças. Sobre o primeiro caso, iremos realizar a alteração descrita abaixo sobre um comando específico presente dentro da estrutura da Coroutine caminhadaPacienteLeito:

Comando a ser alterado:
        controladorLabirinto.ImportarValoresVetoresVariaveis(faseCorrente, PosicaoMonstrosAzuis, PosicaoMonstrosVerdes, PosicaoMonstrosRoxos, PosicaoMonstrosAmarelos, PosicaoMonstrosVermelhos, PosicaoObstaculos, DimensaoObstaculos, PosicaoInicialPilulas);

Conteúdo a substituí-lo:
        controladorLabirinto.ImportarValoresVetoresVariaveis(faseCorrente, PosicaoMonstrosAzuis, PosicaoMonstrosVerdes, PosicaoMonstrosRoxos, PosicaoMonstrosAmarelos, PosicaoMonstrosVermelhos, PosicaoObstaculos, DimensaoObstaculos, PosicaoInicialPilulas, out qtdMonstrosAzuisRestantes, out qtdMonstrosVerdesRestantes, out qtdMonstrosRoxosRestantes, out qtdMonstrosAmarelosRestantes, out qtdMonstrosVermelhosRestantes);

Para que haja a atualização dos valores, acrescentamos à chamada a função ImportarValoresVetoresVariaveis, de MontaLabirinto, indicações para as variáveis que quantificam os agentes de doenças restantes.

Note que, por meio da presença da palavra reservada out antes das variáveis, o script MontaLabirinto poderá alterar o valor das variáveis informadas, devolvendo-os de volta a ControllerFase após a execução de ImportarValoresVetoresVariaveis.

Logo após o bloco de texto inserido, introduza a seguinte linha de código, que será responsável por chamar uma função a ser implementada, responsável pela atualização da mensagem exibida em tela:

        AtualizarMensagemAgentesRestantes();

A linha vermelha ondulada presente abaixo do novo código inserido, também visível na linha de chamada ao comando introduzido há pouco, já nos dá indícios de que precisamos realizar ajustes para que os códigos possam ser executados adequadamente.

Para finalizarmos as intervenções a serem realizadas hoje sobre ControllerFase, antes do último fechamento de chaves do arquivo, introduza o seguinte bloco de comandos:


    public void ReduzirContadorDoenca(bool doencaVerde, bool doencaVermelha, bool doencaAmarela, bool doencaAzul, bool doencaRoxa)
    {
        if (doencaVerde) qtdMonstrosVerdesRestantes--;
        if (doencaVermelha) qtdMonstrosVermelhosRestantes--;
        if (doencaAmarela) qtdMonstrosAmarelosRestantes--;
        if (doencaAzul) qtdMonstrosAzuisRestantes--;
        if (doencaRoxa) qtdMonstrosRoxosRestantes--;
    }

    public void AtualizarMensagemAgentesRestantes()
    {
        string textoComposto = "A tratar:";

        if (qtdMonstrosAzuisRestantes > 0)
            textoComposto += " Azuis=" + qtdMonstrosAzuisRestantes;
        if (qtdMonstrosVerdesRestantes > 0)
            textoComposto += " Verdes=" + qtdMonstrosVerdesRestantes;
        if (qtdMonstrosRoxosRestantes > 0)
            textoComposto += " Roxos=" + qtdMonstrosRoxosRestantes;
        if (qtdMonstrosAmarelosRestantes > 0)
            textoComposto += " Amarelos=" + qtdMonstrosAmarelosRestantes;
        if (qtdMonstrosVermelhosRestantes > 0)
            textoComposto += " Vermelhos=" + qtdMonstrosVermelhosRestantes;

        textoMensagemMomento.text = textoComposto;
    }

Foram introduzidos ao código duas funções bem interessantes: ReduzirContadorDoenca, que será responsável por diminuir a contagem de monstrinhos restantes no labirinto; e AtualizarMensagemAgentesRestantes, que modificará o texto a ser exibido por textoMensagemMomento, dependendo de quantos agentes de doenças ainda estiverem presentes dentro do corpo do paciente.

Alterações em scripts auxiliares

Salve o script, minimize o Visual Studio e retorne ao editor do Unity. Na aba Project, ainda com a pasta Scripts em evidência, clique duas vezes sobre o ícone do script MontaLabirinto para editarmos seu conteúdo:

A primeira alteração a ser realizada refere-se à chamada do método ImportarValoresVetoresVariaveis. Como alteramos a quantidade de parâmetros a serem passados para o método, precisamos acrescentar informações sobre as variáveis que representam o quantitativo de agentes de doenças restantes.

Código a ser alterado:
      public void ImportarValoresVetoresVariaveis(int faseCorrente, Vector3[] PosicaoMonstrosAzuis, Vector3[] PosicaoMonstrosVerdes, Vector3[] PosicaoMonstrosRoxos, Vector3[] PosicaoMonstrosAmarelos, Vector3[] PosicaoMonstrosVermelhos, Vector3[] PosicaoObstaculos, Vector3[] DimensaoObstaculos, Vector2[] PosicaoInicialPilulas)

Conteúdo a substituí-lo:
      public void ImportarValoresVetoresVariaveis(int faseCorrente, Vector3[] PosicaoMonstrosAzuis, Vector3[] PosicaoMonstrosVerdes, Vector3[] PosicaoMonstrosRoxos, Vector3[] PosicaoMonstrosAmarelos, Vector3[] PosicaoMonstrosVermelhos, Vector3[] PosicaoObstaculos, Vector3[] DimensaoObstaculos, Vector2[] PosicaoInicialPilulas, out int m_azuis, out int m_verdes, out int m_roxos, out int m_amarelos, out int m_vermelhos)

Não se preocupe com a questão da linha vermelha ondulada logo abaixo de ImportarValoresVetoresVariaveis, pois trata-se apenas de um indicativo de que devemos realizar alterações para os parâmetros com a palavra reservada out, o que, de fato, faremos muito em breve.

Logo após a abertura de chaves do método, introduza o seguinte conjunto de comandos:

        // Zerar o valor inicial dos monstrinhos restantes
        m_azuis = 0;
        m_verdes = 0;
        m_roxos = 0;
        m_amarelos = 0;
        m_vermelhos = 0;

A partir da importação dos valores que comporão a estrutura do labirinto, serão acrescentadas unidades aos valores de cada uma das variáveis iniciadas por “m_”. Estando essas variáveis “conectadas” aos parâmetros informados ainda em ControllerFase, na prática, a alteração do valor de m_vermelhos, por exemplo, refletirá diretamente no valor de qtdMonstrosVermelhosRestantes, ocorrendo o mesmo para os outros contadores referentes aos agentes coloridos.

Para a efetiva alteração dos valores, será necessário acrescentar a cada bloco de importação de valores de tipo e de posicionamento dos agentes de doenças coloridos, as linhas descritas a seguir. Todas serão posicionadas logo após o comando “i++”, presente ao final de cada bloco:
  • Para monstros azuis:
    m_azuis++;
  • Para monstros verdes:
    m_verdes++;
  • Para monstros roxos:
    m_roxos++;
  • Para monstros amarelos:
    m_amarelos++;
  • Para monstros vermelhos:
    m_vermelhos++;
A imagem a seguir ilustra bem em qual posição cada linha deverá ser posicionada nas estruturas de importação de informações sobre os agentes de doenças:

Salve o script, inimize o Visual Studio e retorne ao editor do Unity. Desta vez, iremos abrir para edição o script ComportamentoDoenca, conforme indicado pela ilustração a seguir:

Realizaremos apenas duas intervenções sobre o código de 
ComportamentoDoenca, sendo o primeiro a inclusão de uma nova variável, responsável por verificar se o agente de doenças já entrou em processo de tratamento (em outras palavras, se será eliminado por intermédio de uma pílula de saúde):

Logo após a declaração das variáveis presentes no script, acrescente a seguinte linha:

    private bool iniciouProcessoDeTratamento = false;

Por fim, substitua o conteúdo presente dentro das chaves do método TratamentoCerto pelas linhas de código a seguir:

        if (!iniciouProcessoDeTratamento)
        {
            iniciouProcessoDeTratamento = true;

            // Atualiza contador de monstros restantes
            ControllerFase.instance.ReduzirContadorDoenca(isVerde, isVermelho, isAmarelo, isAzul, isRoxo);
            ControllerFase.instance.AtualizarMensagemAgentesRestantes();

            // Remover pílula do labirinto
            Destroy(pilula);

            // Remover agente de doenças do labirinto
            Destroy(gameObject);
        }

Em relação ao código que estava presente anteriormente dentro do escopo da função, a novidade é a presença do controle de início de processo de tratamento, que nos permitirá, posteriormente, introduzirmos novas interações durante a “morte” do agente (como animações do monstrinho sumindo), e as chamadas às funções ReduzirContadorDoenca e AtualizarMensagemAgentesRestantes, presentes em ControllerFase.

Conforme adiantamos durante as primeiras intervenções realizadas hoje em ControllerFase, por meio do uso da variável instance, conseguimos permitir a todos os monstrinhos presentes no labirinto o relato ao controlador da fase sobre a diminuição da quantidade de agentes de doenças, no ato da remoção do patógeno pela ação de uma pílula miraculosa.

Salve o script e feche o Visual Studio. Para realizarmos testes sobre a nova funcionalidade implementada, volte ao editor do Unity e selecione o GameObject ControladorFase, presente na listagem da aba Hierarchy. Via aba Inspector, altere o tamanho do vetor Posicao Monstros Amarelos do componente Controller Fase para 1 e conceda os seguintes valores aos atributos do novo elemento exibido:
  • Element 0: X = 5, Y = 5, Z = 0.
Experimente simular a execução do jogo, indo à aba Game e clicando sobre o ícone do botão Play:

Note que interessante: ao final do ciclo de execução, assim que o agente de doenças encosta na pílula de cor correspondente à sua, tanto ele some do labirinto quanto o “placar” de agentes vermelhos restantes é atualizado dinamicamente.

Finalize a execução da simulaçã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 Unity.

Próximos passos

Por meio de intervenções em três scripts, concluímos a construção de mais um módulo interessante de nosso game, responsável pela exibição de importantes informações ao jogador que irão auxiliá-lo a tomar decisões inteligentes, como a coleta das pílulas específicas para cada tipo de tratamento.

Em nossos próximos encontros, daremos sequência às implementações para conexão entre os diferentes módulos do jogo, tais como os responsáveis pela interação do jogador com os eixos de movimentação do labirinto.

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 4.0).