Это последний этап нашего проекта.
Я попытался сделать схему, чтобы проиллюстрировать рабочий процесс MVC в Unity.

В приложении Unity объекты MonoBehaviour находятся в сцене, поэтому вы можете видеть их иерархию. Но эти объекты не могут общаться друг с другом напрямую. Шаблон MVC в Unity — решение этой проблемы.
Если говорить проще: пользовательский ввод приходит в контроллер, который создает представление для модели, а представление отображает данные модели на экране.
Сначала мы ждем ввода от пользователя, например нажатия кнопки. Затем контроллер создает представление и выбирает модель, необходимую для отображения в этом представлении. Теперь представление готово, оно содержит ссылки на объекты пользовательского интерфейса и передает данные в эти ссылки для отображения.
Давайте продолжим проект с того, на чем мы остановились в прошлой статье. Поработаем над представлением. Я создам панель, которая будет содержать UI-объекты.

У нас есть панель, объект Image для иконки предмета и три текстовых объекта для отображения имени, типа и силы атаки. Чтобы управлять этими объектами, создадим класс в проекте с именем InfoView и добавим его в сцену.

Добавим ссылки на элементы интерфейса.
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; }
Затем создадим метод Init, чтобы настроить эти элементы согласно входным данным.
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; } } }
Теперь назначим поля в редакторе.

Мы готовы сделать префаб из этого представления. Я создал папку с именем Resources. Это особая папка, которая позволяет Unity загружать файлы из нее через специальный API. Поместим наши префабы в папку Resources.

Поскольку я буду использовать префабы, то удалю InfoView из сцены.

Время открыть контроллер.
Я добавлю открытую переменную Transform, чтобы знать, какой объект будет родительским для этого представления, и закрытую переменную, чтобы сохранить ссылку на InfoView при старте.
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"); } }
Напишем метод для создания экземпляров представления в сцене.
private void CreateInfoView(ItemData data) { var infoGO = GameObject.Instantiate(infoViewPrefab, infoViewParent); infoGO.GetComponent<InfoView>().Init(data); }
Я передам этот метод ItemView в InitItem, используя события в C#. Чтобы этого добиться, изменим немного 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) ); } }
Я добавил параметр, чтобы передать метод. И теперь можно подключить контроллер.
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); } }
В методе Start я заполняю инвентарь предметами, и когда вы кликнете по одному из них, будет вызван метод CreateInfoView. Но перед тем как мы начнем тестировать это, я укажу вам на одну проблему. Контроллер не знает, создавали ли мы InfoView ранее. Давайте исправим это.
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); } }
Мы сделали переменную infoView и проверяем ее перед созданием нового экземпляра InfoView в сцене.
Давайте протестируем.

Кажется, мы это сделали!
Проект на GitHub.
Это только основы реализации MVC в Unity с использованием Scriptable Objects. Но я верю, что подобный подход можно реализовать в любом проекте. Например, при работе с REST-вызовами этот шаблон может сэкономить вам много времени и сохранить код расширяемым. В целом в Unity достаточно сложно передать объекты сцены в код и работать с ними. Кто-то может возразить и сказать, что для этих целей можно использовать шаблон Singleton. Да, метод, который я описал, не единственный, но он весьма неплох.
Думаю, мы можем вообще не использовать шаблоны, но тогда мы ничем не будем отличаться от средневековья. 🙂
В любом случае, поскольку эта серия статей завершена, я предлагаю вам почитать другие мои тексты, в которых также рассказывается о шаблоне MVC и Scriptable Objects: Making a REST service using Node and Express to use with Unity.
На этом все. Удачного кодинга!
ссылка на оригинал статьи https://habr.com/ru/company/plarium/blog/479550/

Добавить комментарий