Aprendendo a programar jogos em Unity: implementando códigos para a transição entre as fases

Realizaremos modificações em scripts para permitir que o jogador conclua a fase e possa jogar sequencialmente as seguintes.

em 25/01/2026
Seja bem-vindo(a) ao GameDev: Aprendendo a programar jogos em Unity! Após concluirmos, em nosso encontro anterior, a implementação do subsistema de músicas e efeitos sonoros de nosso game, retomaremos o processo de configuração da ligação entre os módulos do jogo por meio de intervenções em scripts, visando permitir a realização da transição entre as fases do game.

Se esta for a primeira vez que você acessa textos de nossa série, sinta-se especialmente convidado a conhecer mais sobre nossa jornada de aprendizados práticos no universo do desenvolvimento de jogos digitais. Por meio da elaboração de divertidos projetos de codificação de games, aprendemos a cada encontro um pouco mais sobre as possibilidades que ferramentas como o Unity nos oferecem para criarmos jogos dos mais diversos estilos gráficos e de gameplay.

A partir do primeiro texto da série, são abordados diferentes tópicos sobre aspectos importantes no processo de elaboração de um game, tanto aqueles relacionados às questões técnicas do desenvolvimento, como a codificação de scripts controladores de comportamentos dos elementos de uma fase e a configuração de seus elementos multimídia, quanto os que envolvem, de forma mais ampla, aspectos voltados à elaboração do contexto do jogo em si, tais como a construção e o posicionamento de elementos em cena e a definição das regras de uma aventura.

Não se preocupe se você não teve oportunidades prévias de aprender sobre programação de jogos ou de sistemas, pois nossa série é voltada justamente a quem tem vontade de tirar do papel games que sempre sonhou em ver tornando-se realidade mas ainda não sabe bem nem por onde começar para alcançar esse objetivo. Para isso, estamos trabalhando em diferentes projetos práticos de programação de jogos, sendo que, em cada encontro, todos os passos e decisões tomadas são explicadas de forma detalhada, para que você possa aprender e aplicar as técnicas em seus projetos pessoais. 

Até o momento, dois games 2D já saíram do papel durante a série. Trata-se de Forest Ping Pong, um jogo inspirado no clássico Pong (Atari, 1972), e Motorista da Pesada, um simpático endless platformer inspirado no arcade japonês City Connection (Jaleco, 1985).

O terceiro projeto de nossa série chama-se Consultório do Dr. Tratanildo. Neste jogo, cujos aspectos de gameplay homenageiam clássicos como Pac-Man (Namco, 1980) e Dr. Mario (Nintendo, 1990), trabalhamos conceitos envolvendo cenários e câmeras tridimensionais, uso de multimídias em cena e aspectos de física do Unity. Vale muito a pena acompanhar seu desenvolvimento; para isso, recomendamos que acesse o índice disponibilizado no primeiro texto da série para conferir tudo sobre sua elaboração e, também, a dos outros games que já construímos.


Dito isso, fica aqui o convite para que junte-se a nós nessa jornada de aprendizados repleta de novos conhecimentos e de muita diversão!

Identificando o fim do tratamento

Dando sequência aos passos necessários para que haja uma ligação entre as fases de nosso jogo, será necessário codificarmos verificações a serem realizadas pelo script controlador da fase para que o game saiba se resta ou não algum agente de doenças dentro do labirinto.

Caso o organismo do paciente tenha sido “livrado” da presença dos monstrinhos coloridos, pode-se considerar que o jogador conseguiu vencer a fase. Assim, além de ser agraciado com alguns pontos a serem acrescidos a seu placar, o gamer será liberado para prosseguir para o próximo desafio clínico.

Para que esse sonho se torne realidade, precisaremos colocar a mão na massa nos códigos de nosso script. Para tal, vamos abrir o projeto para edição: no Unity Hub, clique duas vezes sobre o item referente a ele. Na interface inicial do editor, na aba Project, abra a pasta AssetsScenes e, por fim, clique duas vezes no ícone da cena ConsultorioScene.

Volte à aba Project, abra a pasta Assets e, em seguida, Scripts. Clique duas vezes sobre o ícone do script ControllerFase para iniciarmos sua edição no Visual Studio.

A primeira etapa de codificações que iremos realizar envolverá a criação de um método para a verificação das condições de finalização da fase. Nessa nova função, contabilizaremos a quantidade de monstros presentes no labirinto: caso todos tenham sido extirpados do corpo do paciente, daremos “sinal verde” ao game para prosseguir para a próxima etapa.

Antes do último fechamento de chaves do script, introduza o seguinte bloco de códigos:

    public void VerificarCondicoesFinalizacaoFase()
    {
        int qtdMonstros = 0;

        qtdMonstros += qtdMonstrosVerdesRestantes;
        qtdMonstros += qtdMonstrosVermelhosRestantes;
        qtdMonstros += qtdMonstrosAmarelosRestantes;
        qtdMonstros += qtdMonstrosAzuisRestantes;
        qtdMonstros += qtdMonstrosRoxosRestantes;

        if (qtdMonstros == 0)
        {
            Geral.ModoDeJogoCorrente = "Consultorio";
            ProximaEtapa();
        }        
    }

A verificação da quantidade de agentes de doenças restantes no organismo é feita por meio de soma simples das variáveis que representam o quantitativo individual de monstros por cor.

Em seguida, na parte inicial do arquivo do script, especificamente no bloco de declaração de variáveis correspondente à estrutura de composição das fases, introduza a seguinte linha de código logo após as variáveis correspondentes às falas dos pacientes e do doutor:

    public string[] FalaFinal;

O vetor de strings que acabamos de declarar servirá para armazenar as falas finais de cada paciente, a serem apresentadas pelo jogo logo após a conclusão com êxito dos tratamentos realizados por Tratanildo Doencita.

Quando o paciente for curado

Após as modificações realizadas, localize o código da função MostrarMensagemMedico no script. Logo após o fechamento de chaves de seu conteúdo, introduza o seguinte bloco de códigos:

    IEnumerator pacienteCurado()
    {
        // Reposicionar e/ou desligar elementos do cenário
        barraInfoAcoes.SetActive(false);
        FindObjectOfType<ConcedePilula>().barraInferior.gameObject.SetActive(false);
        doutorCenario.transform.localPosition = new Vector3(1f, 0f, -12.9f);
        doutorCenario.transform.localEulerAngles = new Vector3(0f, -45f, 0f);

        // Aguardar dois segundos
        yield return new WaitForSeconds(2);

        // Conta quantas pílulas ficaram no organismo (para descontar da pontuação)
        int qtdPilulasRestantesNoLab = 0;
        foreach (GameObject go in controladorLabirinto.pilulasCriadas)
            if (go != null) qtdPilulasRestantesNoLab++;

        // Concede os pontos ao jogador
        // Regra: serão concedidos 100 pontos, mais a quantidade de segundos restantes, menos 10 pontos
        // por cada pílula que permaneceu no corpo do paciente.
        // No mínimo, serão concedidos 10 pontos ao se passar de fase.

        Geral.PlacarCorrente += Mathf.Max(100 + Mathf.RoundToInt(tempoRestante) - (10 * qtdPilulasRestantesNoLab), 10);

        // Remover paciente da cama + desligar Canvas do labirinto
        pacienteNoLeito.SetActive(false);
        visualizacaoLabirinto.SetActive(false);

        // Posicionar e rotacionar paciente novamente no centro do cenário
        pacienteCenario.transform.position = posicaoDialogoPaciente;
        pacienteCenario.transform.LookAt(doutorConversa.transform);
        pacienteCenario.SetActive(true);
        pacienteCenario.GetComponent<Animator>().SetBool("caminharPeloCenario", false);

        doutorConversa.transform.LookAt(pacienteCenario.transform);
        doutorConversa.SetActive(true);

        // Troca de câmera
        camPacienteIndoAoLeito.gameObject.SetActive(true);

        // Ativa a mensagem, exibe na tela e liga o colisor do Canvas
        mensagemPapelDireita.transform.parent.gameObject.SetActive(true);
        mensagemPapelDireita.text = FalaFinal[faseCorrente];
        objetoColliderCanvas.SetActive(true);

        etapaAtual = "DialogoFinal";
    }

Para entendermos o funcionamento desse “megabloco”, vamos destrinchar seu comportamento em partes sequenciais:
  • Assim que a Coroutine pacienteCurado() é iniciada, alguns elementos do Canvas que estão sendo exibidos no momento em tela, tais como os elementos das barras inferior e superior, serão desativados. Já doutorCenario, que até então encontrava-se de fronte ao leito, terá posição e rotação configurados com seus valores originais.
  • A imagem do labirinto sem monstrinhos será exibida em tela durante dois segundos, antes das próximas ações se desenvolverem. Devido a essa necessidade de interrupção por dois segundos, todo o bloco de código foi elaborado como fazendo parte de uma Coroutine.
  • Em seguida, o jogo calcula a quantidade de pílulas que restaram dentro do labirinto. Essa etapa é importante para a composição da pontuação a ser concedida ao jogador, pois, se foram utilizados mais medicamentos do que o necessário durante o tratamento, haverá um desconto no cálculo.
  • É realizada a concessão dos pontos ao jogador pela conclusão da fase. A regra definida para a bonificação é a descrita a seguir:
    • 100 pontos pela conclusão da fase, mais a quantidade de segundos restantes (arredondada), menos dez pontos por pílula restante no labirinto.
    • Caso o valor calculado seja menor do que 10, no mínimo o jogo concederá 10 pontos ao jogador pela conclusão da fase.
  • O GameObject que representa o paciente no leito é desativado, assim como a visualização do labirinto em tela.
  • Em seguida, o objeto PacienteCenario, que anteriormente havia se deslocado em direção ao leito, é reposicionado ao centro do cenário, além de ter sua animação de caminhada desligada. Tanto o paciente quanto doutor Tratanildo têm seus GameObjects reativados, assim como ocorre com camPacienteIndoAoLeito.
  • É exibida a mensagem final do paciente em tela, dentro da estrutura de mensagemPapelDireita, com subsequente ativação do colisor do Canvas, permitindo ao jogador avançar para a próxima fase ao clicar na tela.

Ajustes para a transição entre fases

Em relação à mensagem e à câmera utilizados na exibição da fala final do paciente, será necessária a realização de um pequeno ajuste dentro do corpo do código de AtenderPaciente, para que não haja sobreposição dos elementos visuais ao se transitar entre fases.

Ao final do bloco de ativações e desativações de AtenderPaciente, acrescente as seguintes linhas de código:

        mensagemPapelEsquerda.transform.parent.gameObject.SetActive(false);
        mensagemPapelDireita.transform.parent.gameObject.SetActive(false);
        camDialogoPacienteDoutor.gameObject.SetActive(false);
        camPosicaoInicialPaciente.gameObject.SetActive(true);

Agora, iremos introduzir ao controlador de fases a função responsável por, de fato, permitir o avanço para a próxima fase do jogo. Sua funcionalidade vai além de simplesmente chamar o próximo desafio, pois, caso seja identificado que não há mais fases a serem jogadas, a tela de vitória será exibida, concluindo o desafio. 

No final do script, imediatamente antes do último fechamento de chaves, introduza o seguinte bloco de códigos:

    public void AvancarProximaFase()
    {
        Geral.ModoDeJogoCorrente = "Consultorio";
        faseCorrente++;

        // Caso não haja mais fases a cumprir, o jogador venceu o desafio;
        // Caso contrário, a próxima fase será chamada pelo game.
        if (faseCorrente == TipoPaciente.Length)
        {
            etapaAtual = "GanhouTudo";
            mensagemPapelDireita.transform.parent.gameObject.SetActive(false);
            doutorFelicidade.SetActive(true);
            telaVitoria.SetActive(true);
        }            
        else 
            AtenderPaciente();
    }

Por fim, a última edição que realizaremos hoje no script ControllerFase será dentro da estrutura da função ProximaEtapa. Acrescente o seguinte trecho de código dentro do conjunto de condições de tipo switch...case:

            case "Tratamento":
                StartCoroutine(pacienteCurado());
                break;
            case "DialogoFinal":
                AvancarProximaFase();
                break;

Os dois novos casos indicados na estrutura se referem à sequência posterior ao momento em que se observa o fim do tratamento do paciente atual (case "Tratamento") e aos passos seguintes às falas finais dos pacientes 
 (case "DialogoFinal").

Salve o script, feche o Visual Studio e volte ao editor do Unity. 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

Embora tenhamos finalizado as edições em ControllerFase relativas à execução da sequência de fases a ser percorrida durante a jogatina, ainda temos de realizar diferentes ajustes em scripts e em valores de atributos dos componentes atrelados a certos GameObjects para que possamos ver, na prática, o ciclo de ações do game se fechando. Essas intervenções serão realizadas em nosso próximo encontro, quando teremos, enfim, um vislumbre prático de como nosso game se comportará em sua forma final.

Nosso próximo encontro será no dia primeiro de fevereiro. Até mais! Fique sempre ligado nas novidades do 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).