Aprendendo a programar jogos em Unity: desenvolvendo o menu e funcionalidade de pause

Vamos iniciar a elaboração do menu de pause da fase, já com sua funcionalidade principal implementada.

em 09/12/2023
Seja bem-vindo(a) ao GameDev: Aprendendo a programar jogos em Unity de hoje! Dando prosseguimento ao processo de desenvolvimento de nosso platformer 2D, iremos começar a desenvolver a tela de pause das fases, para que o jogador possa interromper temporariamente a jogatina sem prejuízo ao tempo restante de partida.


Caso esta seja a primeira vez que você acessa esta série, já está convidado a juntar-se a nós nesta trilha de aprendizado. A partir do primeiro tópico, você acompanhará todo o processo de criação de um game, desde a instalação da ferramenta Unity para o desenvolvimento dos games em seu computador até a elaboração do jogo em si e de todos os itens que o compõem.

Nossa série é elaborada de forma a permitir, por meio de exemplos e projetos, que você possa criar “do zero” os games que sempre sonhou em tirar do papel. No momento, estamos desenvolvendo o game Motorista da Pesada, um platformer 2D cujo objetivo é coletar todas as caixas de presente de uma fase no menor tempo possível.


No tópico anterior de nossa jornada, codificamos e inserimos elementos importantes para o acompanhamento da partida, como o contador de tempo restante e da quantidade de presentes a serem coletados. Venha conosco e vamos juntos nesta jornada rumo a novos conhecimentos!

Botão de pause

Dando continuidade ao processo de “povoamento” de nosso Canvas com os itens que são relevantes no acompanhamento e controle de nossas fases e partidas, vamos começar a implementar a funcionalidade para pausar o jogo, por meio da interação do gamer com um botão estrategicamente posicionado no canto superior direito de nossa tela.

Para isso, vamos abrir o projeto Motorista da Pesada no editor. Abra o Unity Hub e clique duas vezes sobre o item referente ao projeto. Na interface inicial do Unity, na aba Project, abra a pasta Assets, Scenes e, por fim, clique duas vezes no ícone da cena Fase01.

Na aba Hierarchy, selecione o GameObject CanvasFase para criamos um novo GameObject subordinado a ele (nosso botão para pausar o game); clique com o botão direito em seu item e, no menu suspenso, selecione UI e, em seguida, Image, conforme imagem ilustrativa a seguir:


O nome do novo GameObject será “BotaoPause”, sem as aspas. Selecione-o e, na aba Inspector, vamos alterar alguns parâmetros de seu componente Rect Transform para que o objeto fique posicionado no canto superior direito da tela.

Altere os seguintes parâmetros de Rect Transform:
  • Âncora (ícone destacado em verde): Top Right;
  • Pivot X = 1, Y = 1;
  • Pos X = -12.5, Pos Y = -12.5, Pos Z = 0;
  • Width = 200; e
  • Height = 75.
Agora, nas propriedades do componente Image, vamos indicar em Source Image que iremos utilizar, como imagem do botão, o sprite de nome “barrinha”, conforme exemplo a seguir:


Feito isso, vamos inserir na parte frontal do botão um texto, indicando que aquele item é o botão para pausar o game. Como GameObjects que já apresentam um componente Image não podem receber simultaneamente um componente do tipo Text, iremos criar um objeto subordinado ao BotaoPause com o componente em questão. Para isso, na aba Hierarchy, clique com o botão direito sobre o objeto BotaoPause e, no menu suspenso, selecione a opção UI e, em seguida, Text.


O nome do GameObject será “PauseTexto”, sem as aspas. Em relação às propriedades de seu componente Rect Transform, altere-as para os seguintes valores:
  • Âncora (ícone destacado em verde): Stretch Stretch;
  • Pivot X = 0.5, Y = 0.5;
  • Left, Top, Right e Bottom = 5;
  • Pos Z = 0.
Já em relação às propriedades do componente Text, iremos alterar o valor textual para “Pause”, sem as aspas, e os demais atributos conforme indicado no exemplo a seguir:


Nosso botão para pausar a partida, visualmente falando, está ficando bem interessante; agora iremos adicionar a ele os componentes e códigos para que o comportamento desejado aconteça, ou seja, que se pause o game na hora em que for clicado o botão.

A primeira etapa será acrescentar ao GameObject BotaoPause o componente Button, para que ele possa detectar o recebimento de um clique e possa realizar determinadas ações. Para isso, selecione-o e, na aba Inspector, clique sobre o botão Add Component e, na janela apresentada, selecione a opção UI e, em seguida, Button, conforme imagem a seguir:

Tela de pausa

Agora, iremos criar a tela que será ativada ao clicar no botão de pause. Na aba Hierarchy, clique com o botão direito sobre o objeto CanvasFase e, no menu suspenso, selecione UI, Image, conforme exemplo:


O nome do objeto será “TelaPause”, sem as aspas. A seguir, os valores das propriedades de seu componente Rect Transform:
  • Âncora: Stretch Stretch;
  • Pivot X = 0.5, Y = 0.5;
  • Left, Top, Right e Bottom = 0;
  • Pos Z = 0.
Altere também o parâmetro Color de seu componente Image, clicando sobre ele e preenchendo os campos a seguir com os respectivos valores: R = 0, G = 0, B = 140 e A = 200.


Veja que inserimos uma tela semi transparente na cor azul escuro; agora, vamos povoá-la com alguns itens para torná-la, de fato, uma tela de pause.

Clique com o botão direito sobre o objeto TelaPause e, no menu suspenso, selecione a opção UI e, em seguida, Text. O nome do objeto será “Titulo”, sem as aspas.

Repita a operação mais duas vezes para criar os objetos cujos nomes serão “Voltar” e “Sair”, também sem as aspas, conforme exemplo a seguir:

Selecione o objeto Titulo e altere os parâmetros de seu Rect Transform para os descritos a seguir:
  • Âncora (ícone destacado em verde): Top Center;
  • Pos X = 0, Pos Y = -50, Pos Z = 0;
  • Width = 500;
  • Height = 150;
  • Pivot X = 0.5, Y = 1.

Agora selecione o GameObject Voltar para alterar seus parâmetros de Rect Transform:
  • Âncora (ícone destacado em verde): Middle Center;
  • Pos X = 0, Pos Y = 0, Pos Z = 0;
  • Width = 200;
  • Height = 80;
  • Pivot X = 0.5, Y = 0.5.

Por último, iremos alterar os parâmetros de Rect Transform do objeto Sair para os descritos a seguir:
  • Âncora (ícone destacado em verde): Middle Center;
  • Pos X = 0, Pos Y = -150, Pos Z = 0;
  • Width = 200;
  • Height = 80;
  • Pivot X = 0.5, Y = 0.5.

Em relação aos componentes Text dos três objetos, na imagem a seguir são apresentados os parâmetros referentes ao GameObject Titulo, à esquerda; Voltar, ao centro; e Sair, à direita:

Congelando o tempo

Posicionados os objetos gráficos de nosso menu, vamos codificar o método Pausar, que será responsável por avisar ao sistema se o jogo entrará em estado de suspensão temporária ou não. Para tal, na aba Project, abra a pasta Assets, Scripts e, por fim, clique duas vezes sobre o ícone do script ControladorFase para abri-lo no Visual Studio; assim, ele poderá receber esse novo método que iremos codificar.

Após o código da função void Update(), insira o seguinte trecho de código:

    public void Pausar(bool estado)
    {
        if (estado == true)
            Time.timeScale = 0;
        else Time.timeScale = 1;
    }

Esse código será responsável pela alteração da variável Time.timeScale. Esse parâmetro interno do jogo é um dos responsáveis por controlar o funcionamento do sistema de tempo do Unity.

Todas as funcionalidades que dependem do sistema de processamento de tempo, como funções envolvendo força, gravidade e deltaTime, são executadas levando em consideração a escala de tempo de Time.timeScale. Se ela apresenta valor igual a um, todas essas funcionalidades estarão “em harmonia” com o tempo real; caso ela tenha valor igual a zero, é como se o tempo parasse para o game.

Em termos práticos, com Time.timeScale = 0, o tempo em nosso cronômetro irá parar de ser decrescido e o carrinho ficará "congelado" na posição em que estiver (mesmo que suspenso no ar); ou seja, o game entrará em estado de espera, exatamente o que buscamos no momento. Em outros casos práticos, conceder valores intermediários a 0 e 1 para Time.timeScale deixaria o game em estado de slow-motion, e concedendo valores acima de 1, bem acelerado.

Para isso a função Pausar(bool estado) recebe o parâmetro estado: caso seu valor seja verdadeiro (true), Time.timeScale irá ter seu valor zerado e, por consequência, o jogo será pausado; caso seu valor seja falso (false), Time.timeScale voltará a ter valor igual a um, saindo do estado de congelamento.

Salve o script e minimize o Visual Studio, para voltarmos ao editor do Unity e prosseguirmos com a implementação da funcionalidade em questão.

Primeiro, iremos atrelar a funcionalidade de pausamento do game ao se clicar no botão “Pause”, da tela principal do jogo.

Selecione o GameObject BotaoPause e, na propriedade On Click () de seu componente Button, clique no símbolo de mais (+), sinalizado na imagem a seguir.

No novo campo apresentado, do lado esquerdo iremos preenchê-lo fazendo referência ao GameObject TelaPause (clique e arraste o ícone do objeto, da aba Hierarchy, até o campo). Após isso, selecione o menu do lado direito e, na lista de seleções, escolha GameObject e, em seguida, a opção SetActive(bool), conforme exemplo a seguir:

Deixe a caixa de seleção ativada, conforme destacado em verde no exemplo a seguir. Essa opção, quando ativada, passará o parâmetro verdadeiro (true) à função GameObject.SetActive(bool) do objeto TelaPause assim que houver um clique sobre o botão de pause, ativando o objeto correspondente e exibindo seu conteúdo na tela.


Agora repita o procedimento, clicando novamente no símbolo de mais (+) de On Click () para acrescentar mais um comando a ser realizado quando clicarmos no botão de pause. Na entrada do lado esquerdo, faremos referência ao GameObject Controlador e, no menu do lado direito, na lista de seleções, iremos escolher a opção ControladorFase e, em seguida, a opção Pausar(bool). Deixe a caixa de seleção em destaque ativada, conforme imagem abaixo:


Com esse comando, ao se clicar no botão de pause, iremos acionar a função que acabamos de criar (Pausar, do script ControladorFase) passando como parâmetro para a variável estado um valor positivo (true). Isso desencadeará o pausamento do game, por meio da alteração do valor de Time.timeScale para zero.

Agora, iremos fazer o caminho inverso: programar o item “Voltar” do menu de pause para retomar a partida, de onde ela parou. Primeiro, selecione o GameObject Voltar, subordinado ao objeto TelaPause, e acrescente um componente Button: na aba Inspector, clique sobre o botão Add Component e, na janela apresentada, selecione a opção UI e, em seguida, Button.

Na propriedade On Click () do componente Button, clique no símbolo de mais (+) sinalizado em verde na imagem a seguir.


No novo campo apresentado, do lado esquerdo iremos preenchê-lo fazendo referência ao GameObject Controlador. Após isso, selecione o menu do lado direito e, na lista de seleções, escolha ControladorFase e, em seguida, a opção Pausar(bool). Deixe a caixa de seleção do canto inferior direito sem seleção (destacado na imagem a seguir).

Desta forma, iremos fazer o inverso do comando executado ao se clicar no botão de pause. Ao se passar um parâmetro de valor falso (false) para a função Pausar(bool), Time.timeScale voltará a ter valor igual a um, “descongelando” a passagem de tempo para o game.

Agora, clique novamente no símbolo de mais (+) para criar uma nova entrada. No campo à esquerda, faremos referência ao GameObject TelaPause. Na lista de seleções do menu à direita, escolha GameObject e, em seguida, a opção SetActive(bool). Deixe a caixa de seleção do canto inferior direito sem seleção (em destaque, a seguir).


Além de desativar a pausa, por meio da chamada à função Pausar, ao se clicar na opção “Voltar”, o GameObject TelaPause será desativado, retomando-se o jogo de onde parou.

Por fim, na aba Hierarchy, selecione o GameObject TelaPause e, na aba Inspector, ao lado do nome do objeto, deixe a caixa de seleção vazia, conforme indicado na imagem a seguir. Vamos deixar inicialmente a tela de pause “desligada”, para que o jogo se inicie já em movimento.

Feito tudo isso, que tal vermos em ação a nova funcionalidade implementada? Para isso, vá à aba Game e pressione Play

Observe como é interessante o que ocorre ao se pausar o game: o tempo no cronômetro para de decrescer e o carrinho fica em compasso de espera, aguardando ansiosamente por seu “descongelamento”.

Finalize a simulação da execução, pressionando novamente o botão Play. Não se esqueça de salvar a cena (menu File, Save) e o projeto (menu File, Save Project) antes de fechar o Unity.

Próximos passos

Agora já temos um botão e uma tela de pausa funcionais em nossa primeira fase. Até chegarmos a sua implementação, aprendemos alguns conceitos sobre o gerenciamento de tempo no Unity que podem ser muito importantes não apenas para essa funcionalidade em específico, mas, também, para desenvolver interessantes dinâmicas nos jogos, como movimentos em slow-motion, por exemplo.

Em nossos próximos tópicos iremos prosseguir na montagem dos elementos de nossa primeira fase e, assim, chegaremos cada vez mais próximos ao ponto em que iremos criar as demais fases e, enfim, entregarmos uma aventura completa, cheia de desafios e emoção.

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

Revisão: Thais Santos

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. Escrevemos sob a licença Creative Commons BY-SA 3.0 - você pode usar e compartilhar este conteúdo desde que credite o autor e veículo original.