Concluindo uma série de artigos de
Cem Ugur Karacam sobre a implementação do MVC no Unity usando Objetos Script. Você pode ler as partes anteriores
aqui e
aqui .

Esta é a última etapa do nosso projeto.
Tentei fazer um diagrama para ilustrar o fluxo de trabalho do MVC no Unity.

No aplicativo Unity, os objetos MonoBehaviour estão em cena, para que você possa ver sua hierarquia. Mas esses objetos não podem se comunicar diretamente. O padrão MVC do Unity é a solução para esse problema.
Simplificando: a entrada do usuário chega ao controlador, que cria uma visualização para o modelo, e a visualização exibe os dados do modelo na tela.
Primeiro, estamos aguardando a entrada do usuário, por exemplo, clicando em um botão. O controlador cria a vista e seleciona o modelo necessário para ser exibido nessa vista. Agora a visualização está pronta, contém links para objetos da interface do usuário e passa dados para esses links para exibição.
Vamos continuar o projeto com o que decidimos no último artigo. Vamos trabalhar na apresentação. Vou criar um painel que conterá objetos da interface do usuário.

Temos um painel, um objeto de imagem para o ícone do item e três objetos de texto para exibir o nome, o tipo e a força do ataque. Para gerenciar esses objetos, crie uma classe no projeto chamada
InfoView
e adicione-a à cena.

Adicione links aos elementos da interface.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class InfoView : MonoBehaviour { public Image icon; public Text nameText; public Text typeText; public Text attackText; }
Em seguida, crie o método Init para configurar esses elementos de acordo com a entrada.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class InfoView : MonoBehaviour { public Image icon; public Text nameText; public Text typeText; public Text attackText; public void Init(ItemData data) { icon.sprite = data.icon; nameText.text = data.name; attackText.text = "Attack Power: " + data.attack; switch (data.type) { case ItemType.Axe: typeText.text = "Type: Axe"; break; case ItemType.Dagger: typeText.text = "Type: Dagger"; break; case ItemType.Hammer: typeText.text = "Type: Hammer"; break; case ItemType.Potion: typeText.text = "Type: Potion"; break; } } }
Agora atribua os campos no editor.

Estamos prontos para fazer uma pré-fabricação a partir dessa visualização. Eu criei uma pasta chamada
Resources
. Essa é uma pasta especial que permite ao Unity baixar arquivos dele por meio de uma API especial. Coloque nossos prefabs na pasta
Resources
.

Como usarei prefabs, removerei o
InfoView
da cena.

Hora de abrir o controlador.
Vou adicionar uma variável pública
Transform
para saber qual objeto será o pai dessa exibição e uma variável privada para manter o link para o
InfoView
na inicialização.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ItemViewController : MonoBehaviour { public Inventory inventoryHolder; public Transform inventoryViewParent; public Transform infoViewParent; private GameObject infoViewPrefab; private GameObject itemViewPrefab; private void Start() { itemViewPrefab = (GameObject)Resources.Load("Item"); infoViewPrefab = (GameObject)Resources.Load("InfoView"); } }
Vamos escrever um método para criar instâncias de uma exibição em uma cena.
private void CreateInfoView(ItemData data) { var infoGO = GameObject.Instantiate(infoViewPrefab, infoViewParent); infoGO.GetComponent<InfoView>().Init(data); }
Vou passar esse método
InitItem
para
InitItem
usando eventos em C #. Para conseguir isso, altere um pouco o
ItemView
.
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ItemView : MonoBehaviour { public Button button; public Image itemIcon; private ItemData itemData; public void InitItem(ItemData item, Action<ItemData> callback) { this.itemData = item; itemIcon.sprite = itemData.icon; button.onClick.AddListener(() => callback(itemData) ); } }
Eu adicionei um parâmetro para passar o método. E agora você pode conectar o controlador.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ItemViewController : MonoBehaviour { public Inventory inventoryHolder; public Transform inventoryViewParent; public Transform infoViewParent; private GameObject infoViewPrefab; private GameObject itemViewPrefab; private void Start() { itemViewPrefab = (GameObject)Resources.Load("Item"); infoViewPrefab = (GameObject)Resources.Load("InfoView"); foreach (var item in inventoryHolder.inventory) { var itemGO = GameObject.Instantiate(itemViewPrefab, inventoryViewParent); itemGO.GetComponent<ItemView>().InitItem(item, CreateInfoView); } } private void CreateInfoView(ItemData data) { var infoGO = GameObject.Instantiate(infoViewPrefab, infoViewParent); infoGO.GetComponent<InfoView>().Init(data); } }
No método Start, preencho o inventário com itens e, quando você clica em um deles, o método
CreateInfoView
será chamado. Mas antes de começarmos a testar isso, mostrarei um problema. O controlador não sabe se criamos o
InfoView
antes. Vamos consertar.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ItemViewController : MonoBehaviour { public Inventory inventoryHolder; public Transform inventoryViewParent; public Transform infoViewParent; private GameObject infoViewPrefab; private GameObject itemViewPrefab; private GameObject infoView; private void Start() { itemViewPrefab = (GameObject)Resources.Load("Item"); infoViewPrefab = (GameObject)Resources.Load("InfoView"); foreach (var item in inventoryHolder.inventory) { var itemGO = GameObject.Instantiate(itemViewPrefab, inventoryViewParent); itemGO.GetComponent<ItemView>().InitItem(item, CreateInfoView); } } private void CreateInfoView(ItemData data) { if (infoView != null) { Destroy(infoView); } infoView = GameObject.Instantiate(infoViewPrefab, infoViewParent); infoView.GetComponent<InfoView>().Init(data); } }
Criamos a variável
infoView
e testamos antes de criar uma nova instância do
InfoView
na cena.
Vamos testar.

Parece que conseguimos!
Projeto no
GitHub .
Estes são apenas os princípios básicos da implementação do MVC no Unity usando objetos Scriptable. Mas acredito que uma abordagem semelhante possa ser implementada em qualquer projeto. Por exemplo, ao trabalhar com chamadas REST, esse modelo pode economizar muito tempo e manter o código extensível. Em geral, no Unity, é bastante difícil transferir objetos de cena para codificar e trabalhar com eles. Alguém pode se opor e dizer que, para esses fins, você pode usar o modelo Singleton. Sim, o método que descrevi não é o único, mas é muito bom.
Acho que podemos não usar modelos, mas não seremos diferentes da Idade Média. :)
De qualquer forma, uma vez que esta série de artigos foi concluída, sugiro que você leia meus outros textos, que também falam sobre o padrão MVC e Objetos Scriptable:
Criando um serviço REST usando Node e Express para usar com o Unity .
Só isso. Boa codificação!