Menu

11 – Tutorial Intermediário – Pause

Este tutorial é para tirar a dúvida de algumas pessoas sobre como pausar o jogo. Porém esse é um script tão pequeno que vocês vão se surpreender.

A ideia aqui será utilizar aquela mesma fase de testes do HUD. Nele iremos criar um objeto vazio chamado Pause e dentro dele teremos um Painel chamado Menu (Digamos que quando o nosso Pause for ativado, vai aparecer um menu com as opções Voltar/ Menu de Fases / Menu Principal):

01- Tutorial Pause

Dentro dele iremos adicionar um texto com o nome Pause e outros 3 botões conforme podem ver no Inspector:

02 - Tutorial Pause

Agora só precisamos criar um único Script, chamado GCPause dentro da pasta controlador:

03 - - Tutorial Pause

Script: GCPause.cs

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class GCPause : MonoBehaviour {

    public GameObject menu;

    void Update() {

    }

    public void botaoVoltar() {

    }

    public void botaoMenuFases() {

    }

    public void botaoMenuPrincipal() {

    }
}

O Script vai pegar o objeto Menu para ativa-lo e desativa-lo quando o pause estiver ou não ativo. E no Update iremos ativar o pause caso o jogador aperto a tecla “ESC” (Também conhecido como escape e sendo o botão Cancel lá nas configurações do Input). E temos também as ações dos 3 botões do nosso menu (Reparem também que já adicionei o using UnityEngine.SceneManagement; para podermos trabalhar com a troca de fases).

A ideia do Pause no Unity é trocar a escala do tempo de 100% para 0%. Ou seja, tudo que usar o Time.deltaTime, Time.time e os outros times, não vão mais funcionar. Para fazer isso, basta aplicar o Time.timeScale = 0f;
Com isso no Update, verificamos se a pessoa apertou o botão “Cancel” (ESC). Caso sim ativamos o Menu e mudamos o Time.timeScale para zero.

Já nos botões, temos que voltar o nosso jogo para a velocidade normal 100% (1f). No caso do botão voltar é só desativar o menu. Nos outros dois botões, chamamos a scene correspondente:

Script: GCPause.cs

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class GCPause : MonoBehaviour {

    public GameObject menu;

    void Update() {
        if (Input.GetButtonDown("Cancel")) {
            menu.SetActive(true);
            Time.timeScale = 0f;
        }  
    }

    public void botaoVoltar() {
        Time.timeScale = 1f;
        menu.SetActive(false);
    }

    public void botaoMenuFases() {
        Time.timeScale = 1f;
        SceneManager.LoadScene("MenuFases");
    }

    public void botaoMenuPrincipal() {
        Time.timeScale = 1f;
        SceneManager.LoadScene("Main");
    }
}

Agora é só voltar ao Unity adicionar o Script ao objeto Pause e informar quem é o Menu:

04 - Tutorial Pause

Ah, não se esqueça de dizer aos botões para usarem os métodos do GCPause no objeto Pause, ok?

Já pode testar. Inicie a fase e aperte ESC. O personagem e o que se mover utilizando o Time (Ou seja, tudo que criamos com movimentação que passa pelo Time.deltaTime) e as animações vão parar:

05 - Tutorial Pause

Acredito que 90% ou mais dos tutoriais que você ver na internet de como fazer um pause, vai mostrar isso e acabou. Seu personagem não se move, está ótimo. Clica no voltar, ele volta a se mover, tudo certinho, tudo perfeito. Porem já tentou mover seu personagem? Sem ele estar na animação do ataque? Não? Bora ver o que acontece:

06 - Tutorial Pause

“Está parado, mas se eu apertar para o lado?”

07 - Tutorial Pause

Opa, ele mudou para a animação de parado para andando mesmo que a animação fique parada no primeiro frame.
“E se eu apertar para outro lado?”

08 - Tutorial Pause

“Eita. Espera… Isso significa que… Se eu apertar o botão da habilidade…”

09 - Tutorial Pause

Sim, isso também significa que você vai usar a Habilidade. Complicada assim não é mesmo? Afinal mesmo o Time parando, o Update ainda é executado. Então o melhor é nos métodos Update onde ocorrem isso, nós verificarmos se o jogo está pausado ou não.

Uma forma bem simples de resolver isso é no método Update do script Jogador, a gente adicionar um If (Time.timeScale > 0):

Script: Jogador.cs

    void Update() {
        if (Time.timeScale > 0) { 
            if (desabilitarComandos) 
                GetComponent().isKinematic = true;    
            else {
                GetComponent().isKinematic = false;
                if (!atacando)
                    mover();
                if (estaNoChao)
                    atacar();
            }
        }
    }

Isso já resolve, ou seja, ele só vai executar os comandos abaixo, caso o timeScale seja maior que zero. Agora sim nosso script estaria 100% pronto e já poderíamos terminar por aqui esse post. Mas que tal deixar esse código um pouco mais bonito?

E se a gente ao invés de verificar o Time.timeScale, verificássemos uma variável booleana para ver se o jogo esta ou não pausado? Tem absolutamente o mesmo efeito, porém mais bonito né?

Bom, isso é bem simples na realidade. Só precisamos criar uma variável do tipo estática (Ou seja, que mantem o eu valor em todas as classes do tipo) privada e um método público estático também (Que pode ser acessado por outros objetos, sem precisar instanciar, afinal o valor é método) que retorne esse valor.

Script: GCPause.cs

    private static bool pausado = false;

    public static bool getPausado() {
        return pausado;
    }

Está é a forma padrão que você vai encontrar na maioria das linguagens e é o que a gente vem trabalhando até agora, correto? Mas o C# tem uma forma bem mais bonita de se fazer a meu ver, porém é um pouco mais complicado, mas quem quiser saber é só falar que eu mostro e ai vocês vão entender como que em alguns atributos podemos recuperar os seus valores, mas não setar informações como é o caso do Color.a do Sprite ^^.

Prontinho, agora no script atual, basta a gente informar quando está ou não pausado (igual ao que fizemos com o Time.timeScale):

Script: GCPause.cs

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class GCPause : MonoBehaviour {

    public GameObject menu;
    private static bool pausado = false;

    public static bool getPausado()   {
        return pausado;
    }

    void Update() {
        if (Input.GetButtonDown("Cancel")) {
            menu.SetActive(true);
            Time.timeScale = 0f;
            pausado = true;
        }  
    }

    public void botaoVoltar() {
        Time.timeScale = 1f;
        pausado = false;
        menu.SetActive(false);

    }

    public void botaoMenuFases() {
        Time.timeScale = 1f;
        pausado = false;
        SceneManager.LoadScene("MenuFases");
    }

    public void botaoMenuPrincipal() {
        Time.timeScale = 1f;
        pausado = false;
        SceneManager.LoadScene("Main");
    }
}

Depois é bem simples, basta ir lá no método Update do script Jogador e trocar o if (Time.timeScale > 0f) por if (GCPause.getPausado()):

Script: Jogador.cs

    void Update() {
        if (Time.timeScale > 0) { 
            if (desabilitarComandos) 
                GetComponent().isKinematic = true;    
            else {
                GetComponent().isKinematic = false;
                if (!atacando)
                    mover();
                if (estaNoChao)
                    atacar();
            }
        }
    }

Como o método getPausado é static ele pode ser acessado sem precisar de ser inicializado em uma variável.
“Pow, então por que não sempre utilizamos static, para tudo?”

Por que a ideia é que cada objeto tenha sua própria característica. Se tudo for static, todos os scripts serão iguais, e isso não faria tanto sentido né? Já imaginou ai quantas vezes usamos o script Button e todos eles terem o mesmo efeito para todos os botões? Todos eles com o mesmo sprite, mesmo interactable e por ai vai, alterando em um, alteraria em todos. Entendeu agora?

Para finalizar esse post, é só transformar o objeto Pause em um Prefab:

10 - Tutorial Pause

Bom, com isso terminamos esse micro tutorial de como pausar o seu jogo de forma correta. A partir do próximo post, iremos entrar na reta final do tutorial (Mas relaxem, ainda tem uns 12 posts ou mais), onde cada fase do jogo terá 3 posts sendo dividido em:

Cenário
Inimigo
Boss

E após completar as 4 fases, respeitando esse padrão ai, chegaremos ao final de mais um looongo e trabalhoso tutorial (Esse está sendo osso fazer, é o dobro de posts do anterior, mas promessa é divida, prometi que teria e está tendo!).

E como sempre, qualquer dúvida deixa ai nos comentários 😉

Criador do Jogos Indie, amante de jogos, terror, música, anime e programação. Estudante de mestrado com foco em jogos na educação. Louco por Resident Evil e... sei lá, acho que é isso O.o

5 comments

  1. quando fiz esse tutorial tive um problema. O jogo começava pausado e o personagem se movia. se desabilitar o painel do pause ele não funciona a tecla ESC. então coloquei no método start da classe GCPause o comando para desabilitar o painel.

  2. Larissa disse:

    No scropt do personagem deu problema dizendo que não existe “desabilitarComandos”, pode me ajudar? aonde ela aparece tirando no if?

  3. Larissa disse:

    script*

  4. Samuel disse:

    Olá, Carlos. Seus tutoriais são ótimos, estão me ajudando muito. Só queria dizer isso mesmo. Valeu.

Deixe uma resposta

Parceiros

Steam Brasil LoboLimão Centro RPG Lab Indie
Mundo Gamer PodTerror

Anunciantes

Aglomerando - Agregador de conteúdo
Uêba - Os Melhores Links GeraLinks - Agregador de links Piadas Idiotas - São idiotas mas o faz rir Tedioso: Os melhores links LinkLog MeusLinks.com - Informação e conteúdo todos os dias para você! Agregador de Links - Madruga Links 4Blogs - Agregador de conteúdo Está no seu momento de descanso né? Entao clique aqui!