Menu
CoddyTech

Manter entre Cenas

Parte da seção Criando Jogos de Verdade do Journey de Unity da Coddy. Lição 20 de 60.

Carregar uma cena destrói todos os objetos da cena anterior, mas algumas coisas precisam durar o jogo inteiro, como as moedas que um jogador leva de um nível para outro. DontDestroyOnLoad(gameObject) move um objeto da cena dele para uma cena própria, chamada DontDestroyOnLoad na Hierarchy ao clicar em “Jogar”, que nunca é afetada pelos carregamentos. Isso funciona apenas em um objeto raiz: em um objeto filho, o Unity registra um aviso e não mantém nada. Os filhos do objeto mantido vêm junto, mas os objetos para os quais ele apenas aponta, não: depois do carregamento, um campo que apontava para um objeto da cena anterior contém um objeto destruído, que é igual a null.

public class GameSession : MonoBehaviour
{
    public static GameSession Instance;
    public int coins;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

Este GameSession fica na cena Menu. Ao clicar em “Jogar”, o jogo vai de Menu para Level1 e, depois, volta para Menu, que cria todos os seus objetos novamente, incluindo um novo GameSession, enquanto o objeto mantido continua lá. Sem a verificação em Awake, haveria dois, e o recém-criado assumiria Instance com 0 moedas. Com ela, o recém-criado encontra Instance já definido, destrói a si mesmo e para, e a sessão que passou pelos níveis permanece.

O return é importante porque Destroy aguarda até o fim do quadro. Sem ele, o restante de Awake ainda seria executado para o recém-criado: Instance = this; faria com que todos os scripts apontassem para um objeto prestes a ser destruído.

challenge icon

Desafio

Fácil

Mantenha um único relógio da partida funcionando durante o carregamento de cada cena.

  1. Em Awake(), se Instance != null, chame Destroy(gameObject); e return;. Caso contrário, defina Instance e chame DontDestroyOnLoad(gameObject);.
  2. O carregamento destrói o texto do nível anterior, então, em Update(), antes da linha do texto, quando clockText == null, defina clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.

Pressione “Jogar”, vá para Level2 e volte: um único relógio continua contando. Depois, pressione “Verificar”.

Experimente você mesmo

using UnityEngine;
using TMPro;

public class RunClock : MonoBehaviour
{
    public static RunClock Instance;
    public TMP_Text clockText;
    private float seconds;

    void Awake()
    {
        Instance = this;
    }

    void Update()
    {
        seconds += Time.deltaTime;
        clockText.text = "Time: " + seconds.ToString("0.0");
    }

    public void Split()
    {
        Debug.Log("Split: " + seconds.ToString("0.0"));
    }
}

Todas as lições de Criando Jogos de Verdade

Pratique por conta própria: Playground de Unity