Menu
CoddyTech

Manter entre Cenas

Parte da seção Criando jogos de verdade do Journey de Unity da Coddy. Lição 20 de 56.

Carregar uma cena destrói todos os objetos da cena anterior, mas algumas coisas precisam durar o jogo todo, como as moedas que um jogador leva de um nível para outro. DontDestroyOnLoad(gameObject) move um objeto para fora da cena dele, para uma cena própria, chamada DontDestroyOnLoad na Hierarchy durante o Play, que nunca é afetada pelo carregamento. 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: após o carregamento, um campo que apontava para um objeto da cena anterior mantém um objeto destruído, que é igual a null em uma comparação.

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. O Play percorre Menu, Level1 e depois volta para Menu, e a cena Menu cria todos os seus objetos novamente, incluindo um novo GameSession, enquanto o objeto mantido ainda está 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 frame. Sem ele, o restante de Awake ainda é executado para o recém-criado: Instance = this; apontaria todos os scripts para um objeto prestes a ser destruído.

challenge icon

Desafio

Fácil

Um cronômetro de speedrun. O objeto RunClock em Level1 conta os segundos da execução inteira e registra um split sempre que um nível é concluído. O Goal dourado de Level1 carrega Level2, cujo objetivo carrega Level1 novamente, e cada objetivo chama RunClock.Instance.Split() primeiro. Cada nível tem seu próprio HUD com um ClockText; o Inspector atribui ao RunClock o que está em Level1. As setas movem o Player. Altere RunClock.cs para que:

  • o cronômetro continue funcionando durante o carregamento de todas as cenas, sem recomeçar;
  • o tempo sempre apareça no ClockText do nível que está aberto, como Time: 12.3;
  • ao voltar para Level1, que tem seu próprio RunClock, ainda haja apenas um cronômetro: aquele que está funcionando, e RunClock.Instance seja esse.

Pressione Play, vá para Level2 e volte, conclua Level1 novamente e, em seguida, clique em Check.

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"));
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Criando jogos de verdade