Como implementar um seletor de fases na Unity

Voltamos para a segunda parte do tutorial sobre como criar um sistema de seleção de fases. No tutorial anterior criamos a interface do nosso seletor de fase. Agora chegou a hora de implementar as funcionalidades necessárias para que tudo funcione. Durante esse tutorial vamos aprender como podemos manter informações de nossa fases, como podemos adicionar as fases dinamicamente na interface e como carregar cenas na Unity.

Antes de começar

Para este tutorial usarei a Unity 2021.3.4f1 lts. Mas desde que você esteja usando uma versão relativamente recente você está livre para usar a versão que preferir uma vez que o projeto não requer nada que seja específico dessa versão. Porém é possível que existam pequenas diferenças na UI da Unity.

Como este tutorial é continuação do post anterior não entrarei em detalhes de como a interface foi criada. Este tutorial será focado em fazer com que tudo funcione. Porém, apesar de não ser totalmente necessário, ler o tutorial anterior irá facilitar o entendimento do que estamos fazendo.

Caso você esteja interessado em apenas implementar as funcionalidades, criei um arquivo zip para que você possa começar do ponto que paramos no post anterior. Caso prefira, o projeto completo está disponível no GitHub.

Por fim, para criar os nomes das fases e as descrições usei alguns dos geradores disponíveis no site Fantasy Name Generators. Já para as imagens, usei o site Unsplash e cortei elas usando um programa de edição de imagem para os tamanhos corretos. Porém caso queira usar as mesmas imagens nos cartões das fases elas estão disponíveis aqui. 

Caso encontre algum problema ou dificuldade, sinta-se à vontade para entrar em contato comigo através dos comentários, e-mail ou redes sociais.

Onde salvar informações sobre a fase

A primeira coisa que precisamos fazer é criar alguma forma de saber quais são as fases do nosso jogo e quais as informações relevantes para aquela fase. Existem muitas formas como podemos guardar essas informações. De planilhas a banco de dados. 

Porém na Unity podemos usar ScriptableObject para criar, armazenar e editar esse tipo de informação diretamente no editor. ScriptableObjects são similares a MonoBehviours porém não podemos adicionar como componentes a GameObjects. Mas podemos criar arquivos a partir deles que serão guardados diretamente no projeto. De certa forma criando um banco de dados.

A maior vantagem é que podemos criar campos em nossas classes MonoBehaviour e arrastar esses arquivos como referência. Contudo, temos que ficar atentos a duas coisas. 

A primeira, é que enquanto estivermos trabalhando no editor, qualquer modificação nos dados do ScriptableObject serão salvos. Por exemplo, digamos que temos um ScriptableObject que guarda as opções do jogador, como o volume da música, se modificarmos essa variável enquanto estivermos no Play Mode, o novo valor será serializado pela Unity e não resetado quando sairmos do Play Mode como acontece com MonoBehaviours.

A segunda é que ao começar o jogo a Unity cria uma cópia do ScriptableObject na memória do computador e essa cópia será compartilhada com todos os objetos que fizer referência a esse ScriptableObject. Isso quer dizer que não devemos usar ScriptableObject para guardar informações que devem ser únicas a cada objeto, como por exemplo, a quantidade de vida de um inimigo, já que se um inimigo sofrer dano, todos irão. Não é o caso de nossas fases, já que queremos que a mesma informação seja compartilhada com todos os objetos que estejam interessados na informação da fase.

Como criar ScriptableObject com as informações da fase

Vamos criar uma pasta chamada Scripts para guardar nossos scripts e manter o projeto organizado. Após criar a pasta clique com o botão direito sobre ela e selecione Create > C# Script. Nomeie o arquivo como Level e abra ele no seu editor de texto.

Com o arquivo aberto, podemos apagar os métodos Start e Update e os comentários, não precisaremos deles. Além disso, nossa classe não herdará de MonoBehaviour, mas sim de ScriptableObject.

Em seguida iremos criar uma série de campos privados, todos marcados com SerializeField para que possamos editá-los diretamente no editor. 

O primeiro desses campos é chamado de sceneName, esse é provavelmente o campo mais importante dessa classe, já que ele guarda o nome da cena que queremos que seja aberta caso o jogador selecione esta fase. Precisamos usar o nome da cena porque não podemos criar referências aos arquivos das cenas de forma fácil. O maior problema aqui é que caso digitarmos o nome do arquivo errado ou o nome mudar, a Unity não conseguirá encontrar a cena.

[SerializeField]
private string sceneName;

Em seguida temos os campos levelName e levelDescription. Usaremos esses campos para guardar o nome e a descrição da fase. Como a descrição de uma fase tende a ser um texto maior, marquei o campo com o atributo TextArea para que tenhamos mais espaço no editor. Caso você queira saber mais atributos úteis, confira esse post em que fiz uma lista dos atributos que uso com mais frequência.

[SerializeField]
private string levelName;
[SerializeField]
[TextArea(10, 15)]
private string levelDescription;

O campo startUnlocked usaremos para saber se a fase deve iniciar liberada ou não, com isso poderemos impedir que o jogador selecione uma fase na interface. 

[SerializeField]
private bool startUnlocked;

Por último temos os campos levelLockedImage e levelUnlockedImage, eles guardarão referências das imagens de destaque da fase. Para esse tutorial no campo levelLockedImage a imagem em preto e branco e no campo levelUnlockedImage a imagem com cor.

[SerializeField]
private Sprite levelLockedImage;
[SerializeField]
private Sprite levelUnlockedImage;

Porém esses campos são privados, isso quer dizer que outras classes não podem acessar essas informações. Para resolver isso criaremos algumas propriedades com o acessador get, assim outras classes conseguirão acessar essas informações porém não poderão modificá-las.

public string SceneName { get { return sceneName; } }
public string LevelName { get { return levelName; } }
public string LevelDescription { get { return levelDescription; } }
public Sprite LevelLockedImage { get { return levelLockedImage; } }
public Sprite LevelUnlockedImage { get { return levelUnlockedImage; } }

Como eu disse no início, precisamos ficar atentos a alguns problemas que o ScriptableObject possui. O primeiro é que, por exemplo, se durante testes no editor liberarmos uma fase e esquecermos de resetar o status da fase, o jogador poderá ter acesso a fases que ele não deveria, já que toda alteração em um valor de um ScriptableObject é salvo automaticamente pela Unity.

Para resolver esse problema criaremos uma propriedade autoimplementada chamada IsUnlocked. Em seguida criaremos um método chamado OnEnable, esse é um método especial da Unity e é chamado automaticamente pela engine quando esse objeto é criado durante o jogo.

public bool IsUnlocked { get; set; }

private void OnEnable()
{
    IsUnlocked = startUnlocked;
}

Nesse método iremos atribuir o valor de startUnlocked a propriedade IsUnlocked. Assim, toda vez que esse ScriptableObject for criado pela Unity o valor da propriedade será inicializado com o valor que definimos no editor. Além disso, como a propriedade IsUnlocked não modifica o campo startUnlocked a Unity não irá serializar o novo valor. O que na prática quer dizer que podemos modificar a propriedade IsUnlocked  sem que o valor original seja modificado.

Porém, temos o problema oposto com a versão final do jogo. Isso é, ScriptableObject não armazena seus dados entre uma sessão e outra de jogo. Para resolver esse problema precisamos salvar a informação e carregar ela novamente quando o jogo começar. Porém isso foge do escopo deste tutorial. 

O último passo para podermos usar o ScriptableObject é marcar a classe com o atributo CreateAssetMenu. Esse atributo nos permite criar assets a partir desse ScriptableObject quando clicamos com o botão direito na janela Project.

[CreateAssetMenu(fileName = "New Level", menuName = "Level")]
public class Level : ScriptableObject

Como criar as fases

Com o ScriptableObject criado podemos começar criar as nossas fases. Se você já tiver fases no seu jogo você não vai precisar fazer isso, mas como esse projeto é apenas um exemplo criei criar algumas fases. 

Primeiro criei uma pasta chamada Levels dentro da pasta Scene. Em seguida criei 9 cenas e nomeei cada uma como Level 1, Level 2, Level 3 e assim em diante. Depois, abri cada cena e criei um GameObject Canvas e adicionei um texto com o nome de cada fase, assim quando carregar a fase saberei que abri a cena correta. Só fiz isso para testar o sistema, como disse você pode usar as fases que você já tem, ou criar quantas precisar.

Em seguida, crie uma pasta para guardar os ScriptableObject com as informações de cada fase. Para criar uma fase clique com o botão direito sobre ela e selecione Create > Level. Você pode nomear o arquivo como preferir, eu vou dar o mesmo nome do que o arquivo da cena.

Agora, selecione uma fase e preencha as informações necessárias. O mais importante é que na propriedade Scene Name você digite corretamente o nome da cena, caso contrário, a Unity não conseguirá encontrar o arquivo para abrir a cena. Não podemos nos esquecer de liberar ao menos a primeira fase marcando a propriedade Start Unlocked. Crie quantas fases você quiser ou precisar para o seu jogo.

Como adicionar as fase na interface

Agora que temos as nossas fases e suas informações podemos começar a implementar o seletor de fases.

Primeiramente, iremos criar um script chamado LevelCard na pasta Scripts. Esse script é responsável por manter e atualizar o conteúdo de cada cartão de fase. Abra o arquivo no seu editor de texto e apague os métodos Start e Update e os comentários, não precisaremos deles. Porém mantenha a herança de MonoBehaviour.

Em seguida, precisamos declarar dois using no início do arquivo. O primeiro é TMPro, ele nos permite acessar os componentes do pacote TextMeshPro, nós instalamos esse pacote no tutorial anterior e usamos ele para exibir textos na tela. O segundo é UnityEngine.UI, esse nos permite acessar os componentes de interface usados pela Unity.

using TMPro;
using UnityEngine.UI;

Depois criamos três campos privados e marcamos com o atributo SerializeField para que possamos editá-los diretamente no editor. 

[SerializeField]
private TextMeshProUGUI levelName;
[SerializeField]
private TextMeshProUGUI levelDescription;
[SerializeField]
private Image levelImage;

Os campos levelName e levelDescription irão guardar uma referência ao GameObject com o componente de texto em que será usado para exibir o nome e a descrição da fase. Já o campo levelImage irá guardar uma referência ao componente Image, em que será exibido a imagem de capa da fase. Todos esses GameObjects foram criados no tutorial anterior.

Criaremos também um método público chamado SetCardContent que irá receber as informações de uma fase, usaremos esse método para atualizar as informações exibidas no cartão.

public void SetCardContent(Level level)
{
    levelName.SetText(level.LevelName);
    levelDescription.SetText(level.LevelDescription);

    if (level.IsUnolocked)
    {
        levelImage.sprite = level.LevelUnlockedImage;
    }
    else
    {
        levelImage.sprite = level.LevelLockedImage;
    }
}

Ele é bem simples, usamos o método SetText nos campos levelName e levelDescription para atualizar o texto com o nome da fase e sua descrição. Em seguida checamos se a fase está liberada, para isso usamos a propriedade IsUnlocked do ScriptableObject da fase e caso ela esteja liberada exibimos a imagem colorida, caso contrário exibimos a imagem em preto e branco.

Depois de criar essa classe, volte para a Unity. Dê dois cliques no Prefab LevelCard para editar ele. Em seguida selecione o GameObject LevelCard e clique no botão Add Component e procure pelo script LevelCard. Agora arraste os GameObjects com os texto e a imagem para as propriedades do script que criamos.

Agora, crie mais um script chamado LevelSelect na pasta Scripts. Esse script será responsável por criar os cartões na interface, fazer a paginação e abrir a fase selecionada. Abra o arquivo no seu editor de texto e novamente apague o conteúdo da classe.

Primeiro iremos criar três campos privados e marcamos eles com a propriedade SerializeField para que possamos editá-los diretamente no editor.

O primeiro campo será chamado de levels e será um array com todas as fases que queremos que sejam exibidas na interface.

[SerializeField]
private Level[] levels;

O segundo campo será chamado de levelCardPrefab, usaremos ele para termos uma referência ao Prefab do cartão da fase, assim poderemos criar cópias dele com a informação da fase que deve ser exibida.

[SerializeField]
private GameObject levelCardPrefab;

O último campo será chamado de levelCardsContainer, irá guardar uma referência ao Rect Transform que será usado como pai dos cartões quando criarmos eles, assim podemos posicionar os cartões onde queremos.

[SerializeField]
private RectTransform levelCardsContainer;

Depois disso, criaremos um método privado chamado CreateLevelCards, este método é responsável por criar o cartão e passar as informações da fase que ele deve exibir. Para isso, iteramos sobre o array levels e usaremos o método Instantiate para criar uma cópia do levelCardPrefab e definir seu pai como levelCardsContainer. Iremos guardar uma referência ao GameObject criado em uma variável.

Em seguida, usaremos o método GetComponent nessa variável para pegar uma referência do script LevelCard. Usamos novamente uma variável para guardar uma referência a esse script.

Por último usamos o método SetCardContent para passar a informação da fase que o cartão deve exibir.

private void CreateLevelCards()
{
    foreach (Level level in levels)
    {
        GameObject levelCardGO = Instantiate(levelCardPrefab, levelCardsContainer);
        LevelCard levelCard = levelCardGO.GetComponent<LevelCard>();
        levelCard.SetCardContent(level);
    }
}

Agora criaremos o método chamado Awake, este método é especial para a Unity e será chamado quando esse script for criado durante o jogo automaticamente. Nele chame o método CreateLevelCards para que os cartões sejam criados.

private void Awake()
{
    CreateLevelCards();
}

Depois disso volte à Unity. Selecione o GameObject LevelSelectCanvas, clique no botão Add Component e procure pelo script LevelSelect. Agora precisamos preencher as propriedades.

Uma dica para quando estivermos preenchendo uma lista no editor. Clique no cadeado na janela Inpector, isso fará com que a janela fique travada no objeto selecionado, com isso podemos selecionar todas as fases e arrastar tudo de uma vez. Não se esqueça de clicar no cadeado novamente para liberar a janela depois de terminar suas edições.

Na propriedade Level Card Prefab, precisamos preencher com o Prefab LevelCard, podemos arrastar ele a partir da janela Project ou clicar na bolinha e procurar pelo nome. Já na propriedade Level Card Container precisamos do GameObject que irá conter todos os nossos cartões, neste caso é o GameObject LevelCards. Também podemos arrastar ele até a propriedade ou procurar por ele clicando na bolinha no lado da propriedade.

Clique no botão para entrar no Play Mode. Podemos ver que os cartões foram criados, mas ainda temos mais trabalho. Os botões ainda não funcionam e também podemos selecionar mais de uma fase.

Como paginar as fases

Volte ao script LevelSelect. Primeiro precisamos declarar using UnityEngine.UI no início do arquivo para que possamos acessar os componente de interface da Unity.

Em seguida vamos declarar mais três variáveis privadas e com sempre marcamos com o atributos SerializeField para que possamos editá-las diretamente no editor. 

A primeira variável será chamada de levelsPerPage e é responsável por guardar a quantidade de fases que temos por página. As outras duas serão chamadas de nextPageButton e previousPageButton e irão conter uma referência aos botões para avançar e voltar a paginação.

[SerializeField]
private int levelsPerPage;
[SerializeField]
private Button nextPageButton;
[SerializeField]
private Button previousPageButton;

Também iremos criar uma variável privada chamada currentPage, essa variável não será marcada com SerializeField e será responsável por guardar a página atual que deve ser exibida.

private int currentPage = 0;

Em seguida iremos criar um método chamado RefreshPageContent. Ele será responsável por esconder ou exibir o cartão de uma fase dependendo da página atual. 

Para isso primeiro iremos calcular qual o índice da primeira fase que deve ser exibida, isso é feito multiplicando a página atual pela quantidade de fases por página. Depois calculamos qual o índice da última fase que deve ser exibida, fazemos isso somando a quantidade de fases por página com o índice da página inicial.

Então iteramos sobre todas as fases no array levels e checamos se o índice da fase atual é maior ou igual ao índice inicial, e menor que o índice final. Em outras palavras, se a fase estiver entre os índices inicial e final podemos exibir ela, caso contrário precisamos esconder o cartão. 

Para isso usaremos o método GetChild disponível no campo levelCardsContainer, e passaremos o índice atual. Isso era retornar o componente Transform do filho naquela posição, acessamos a propriedade gameObject e usamos o método SetActive disponível neste GameObject, e passamos o valor true caso o cartão da fase deve ser exibido ou false caso contrário.

Por fim chamamos o método CheckPaginationButtons que iremos criar em seguida.

private void RefreshPageContent()
{
    int startIndex = currentPage * levelsPerPage;
    int endIndex = startIndex + levelsPerPage;

    for (int i = 0; i < levels.Length; i++)
    {
        if (i >= startIndex && i < endIndex)
        {
            levelCardsContainer.GetChild(i).gameObject.SetActive(true);
        }
        else
        {
            levelCardsContainer.GetChild(i).gameObject.SetActive(false);
        }
    }

    CheckPaginationButtons();
}

O método CheckPaginationButtons será responsável por bloquear os botões da paginação para que o jogador não possa clicar neles e quebrar a paginação. Para isso, primeiro calculamos a quantidade total de páginas, isso é feito dividindo a quantidade de fases pela quantidade de fases por página. Em seguida iremos usar uma expressão booleana para decidir se o botão deve ser bloqueado ou não.

Para o botão que irá levar para a próxima página queremos que ele seja interativo caso a página atual não seja igual à última página. E para o botão que irá levar para página anterior queremos que ele seja interativo caso a página atual não seja igual a 0, ou seja, a primeira página.

private void CheckPaginationButtons()
{
    int totalPages = levels.Length / levelsPerPage;

    nextPageButton.interactable = currentPage != totalPages;
    previousPageButton.interactable = currentPage != 0;
}

Em seguida iremos criar mais dois métodos, dessa vez eles serão públicos, e chamaremos eles quando o botão de paginação for clicado pelo jogador. 

O primeiro método será chamado de NextPage, e quando chamado irá incrementar a variável currentPage, o que basicamente quer dizer “vamos para próxima página”. Em seguida irá chamar o método RefreshPageContent para que as fases que estão sendo exibidas sejam atualizadas. 

public void NextPage()
{
    currentPage++;
    RefreshPageContent();
}

O segundo método será chamado de PreviousPage e é parecido com o método NextPage, só que ao invés de incrementar a variável currentPage iremos decrementar, o que quer dizer “vamos para página anterior” e também irá chamar o método RefreshPageContent para atualizar os cartões das fases.

public void PreviousPage()
{
    currentPage--;
    RefreshPageContent();
}

Antes de voltar a Unity chame o método RefreshPageContent no método Awake para que os cartões e os botões sejam exibidos corretamente.

private void Awake()
{
    CreateLevelCards();
    RefreshPageContent();
}

Com isso volte a Unity. Selecione o GameObject PreviousPageButton e no componente Button, clique no sinal + na lista OnClick, no campo que apareceu arraste o GameObject LevelSelectCanvas e no menu dropdown selecione LevelSelect > PreviousPage.

Faça o mesmo para o para GameObjec NextPageButton, mas selecione o método NextPage.

Com isso, esses métodos serão chamados cada vez que o botão seja clicado pelo jogador.

Em seguida selecione o GameObject LevelSelectCanvas e na propriedade Levels Per Page insira a quantidade de fase que deve aparecer em cada página, neste caso quatro. E nas propriedade Next Page Button arraste o GameObject Next Page Button e na Previous Page Button arraste os GameObject PreviousPageButton.

Entre no Play Mode e teste os botões.

Seleção de fases

Agora iremos impedir que o jogador selecione mais de uma fase ao mesmo tempo. Para isso usaremos o componente Toggle Group para agrupar todos os cartões das fases. Com os cartões agrupados esse componente não irá permitir que mais de uma fase seja selecionada. Além disso, ele poderá garantir que sempre tenha uma fase selecionada.

O componente Toggle Group pode ser adicionado a qualquer GameObject na cena, mas eu gosto de manter ele próximo do local em que será usado para ficar mais fácil de lembrar onde ele está. Por causa disso, selecione o GameObject LevelCards e clique no botão Add Compnent e procure por Toggle Group. Deixe a propriedade Allow Switch Off desmarcada, isso fará com que sempre exista uma fase selecionada.

Porém os cartões ainda não estão agrupados. Como criamos eles através de código, precisamos agrupar eles também através do código. Para isso, abra o script LevelCard.

Primeiro vamos adicionar o atributo RequireComponent acima do nome da classe com o tipo Toggle, isso evitará que esqueçamos de adicionar o componente quando adicionarmos o nosso script a um GameObject.

[RequireComponent(typeof(Toggle))]
public class LevelCard : MonoBehaviour

Em seguida iremos criar duas propriedades autoimplementadas com accesores get público e set privados, dessa forma podemos acessar a informação através de outras classes, porém apenas essa classe poderá modificar seus valores. 

A primeira propriedade será chamada de LevelInfo e ela irá guardar uma referência a informação da fase que está sendo exibida. 

A segunda propriedade será chamada de Toggle e irá guardar uma referência ao componente Toggle que o GameObject que o nosso script for adicionado terá.

public Level LevelInfo { get; private set; }
public Toggle Toggle { get; private set; }

Depois iremos criar o método Awake, como já vimos ele é chamado pela Unity quando esse objeto for criado. Nele usaremos o método GetComponent para pegar uma referência ao componente Toggle e salvar na propriedade com o mesmo nome que criamos.

private void Awake()
{
    Toggle = GetComponent<Toggle>();
}

Em seguida, iremos modificar o método SetCardContent. Primeiro iremos salvar na propriedade LevelInfo uma referência das informações da fase que o método recebeu para ser exibido.

Depois quando checamos se a fase está liberada ou não. Caso a fase não esteja liberada iremos atribuir false a variável interactable da propriedade Toggle. Isso fará com que não seja possível selecionar essa fase.

public void SetCardContent(Level level)
{
    LevelInfo = level;
    levelName.SetText(level.LevelName);
    levelDescription.SetText(level.LevelDescription);

    if (level.IsUnlocked)
    {
        levelImage.sprite = level.LevelUnlockedImage;
    }
    else
    {
        levelImage.sprite = level.LevelLockedImage;
        Toggle.interactable = false;
    }
}

Por fim iremos criar um método chamado SetToggleGroup usaremos ele para agrupar os cartões. Ele receberá uma referência a um Toggle Group e irá atribuir essa referência ao componente Toggle que salvamos na propriedade com mesmo nome. Isso termina com as modificações nesta classe.

public void SetToggleGroup(ToggleGroup toggleGroup)
{
    Toggle.group = toggleGroup;
}

Agora abra o script SelectLevel. Primeiro, abaixo do último campo marcado com SerializeField iremos criar outro campo privado chamado de levelCardToggleGroup e marcamos ele com o atributo SerializeField. Esse campo terá uma referência ao componente Toggle Group que iremos usar para agrupar os cartões.

[SerializeField]
private ToggleGroup levelCardToggleGroup;

Em seguida criaremos um campo privado chamado selectedLevel. Usaremos esse campo para saber qual fase está selecionada.

private Level selectedLevel;

Faremos algumas modificações no método CreateLevelCards. Dentro do bloco foreach, após chamarmos o método SetCardContent iremos chamar o método SetToggleGroup e iremos passar a variável levelCardToggleGroup.

Logo abaixo usaremos o método AddListener para adicionar um método ao evento onValueChanged do componente Toggle do cartão da fase. Esse evento é chamado toda vez que o campo isOn do componente é modificado, ou seja, quando ele é selecionado ou desselecionado. Para isso usaremos uma expressão lambda, e passaremos o valor de isOn e a variável levelCard para o método LevelSelected.

private void CreateLevelCards()
{
    foreach (Level level in levels)
    {
        GameObject levelCardGO = Instantiate(levelCardPrefab, levelCardsContainer);
        LevelCard levelCard = levelCardGO.GetComponent<LevelCard>();
        levelCard.SetCardContent(level);
        levelCard.SetToggleGroup(levelCardToggleGroup);
        levelCard.Toggle.onValueChanged.AddListener(isOn => LevelSelected(isOn, levelCard));
    }
}

Nesse método, primeiro iremos checar o valor de isOn, caso seja false iremos ignorar e pararemos o método aqui mesmo, pois isso significa que a fase foi desselecionada. Caso seja true iremos salvar a informação da fase selecionada no campo selectedLevel.

private void LevelSelected(bool isOn, LevelCard levelCard)
{
    if (isOn == false)
    {
        return;
    }

    selectedLevel = levelCard.LevelInfo;
}

Volte a Unity e selecione o GameObject LevelSelectCanvas e no componente Level Select arraste o GameObject que possui o Toogle Group, no meu caso é o GameObject LevelCards, até a propriedade Level Card Toggle Group. Entre no Play Mode e teste o que temos no momento.

Carregando a fase selecionada

Chegamos à última parte deste tutorial, nela iremos fazer com que seletor de fase carregue a fase selecionada. Para isso, volte ao script LevelSelect. 

Primeiro precisamos declarar using UnityEngine.SceneManagement no início do arquivo, isto irá permitir que tenhamos acesso aos sistema de gerenciamento de cenas da Unity.

Em seguida criaremos o método público StartSelectedLevel. Ele irá carregar a cena da fase selecionada. Para isso passamos o nome da cena que queremos carregar para o método LoadScene da classe estática SceneManager.

public void StartSelectedLevel()
{
    SceneManager.LoadScene(selectedLevel.SceneName);
}

Agora volte à Unity, selecione o botão StartLevelButton. No componente Button clique no sinal de mais na lista OnClick. No campo que aparecer arraste o GameObject LevelSelectCanvas e no dropdown selecione LevelSelect > StartSelectedLevel().

Mas antes de clicarmos no botão para testar, precisamos adicionar as cenas na lista de cenas que serão incluídas quando fizermos a build do jogo. Para isso clique em File > Build Settings.

Na janela que aparecerá arraste todas as cenas das fases para a lista.

Uma coisa importante aqui é que quando fizer a build do jogo a primeira cena na lista será carregada automaticamente pela Unity. Isso não afeta enquanto estivermos no editor, mas é bom ter isso em mente.

Agora entre no Play Mode. Selecione uma fase e clique no botão para carregar a fase. Você deve estar na fase agora.

Conclusão

Com isso concluímos esse tutorial de duas partes em que aprendemos a criar a interface e implementar as funcionalidades de um sistema de seleção de fases. Com as informações contidas nestes dois tutoriais acredito que possamos criar qualquer tipo de seletor de fase que quisermos. Basta usarmos nossa criatividade e adaptar o que aprendemos aqui.

Por fim, caso tenha alguma dúvida ou sugestão deixe seu comentário! Obrigado! Até a próxima!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *