带有可脚本编写对象的Unity中的MVC。 第三部分

Cem Ugur Karacam完成了有关使用可脚本对象在Unity中实现MVC的一系列文章。 您可以在此处此处阅读前面的部分。



这是我们项目的最后阶段。

我试图制作一个图表来说明Unity中的MVC工作流程。



在Unity应用程序中,MonoBehaviour对象位于场景中,因此您可以查看其层次结构。 但是这些对象不能直接相互通信。 Unity的MVC模式是解决此问题的方法。

简而言之:用户输入到控制器,该控制器为模型创建视图,该视图在屏幕上显示模型数据。

首先,我们正在等待用户的输入,例如,单击按钮。 然后,控制器创建视图并选择需要在该视图中显示的模型。 现在视图已准备就绪,它包含指向用户界面对象的链接,并将数据传递到这些链接以进行显示。

让我们继续上一篇文章中介绍的项目。 我们将进行演示。 我将创建一个包含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); } 

我将使用C#中的事件将此ItemView方法传递给InitItem 。 为此,请更改一些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上的项目。

这些只是使用脚本对象在Unity中实现MVC的基础。 但是我相信任何项目都可以实施类似的方法。 例如,在使用REST调用时,此模板可以节省大量时间,并使代码可扩展。 通常,在Unity中,很难将场景对象转换为代码并使用它们。 可能有人反对说,出于这些目的,您可以使用Singleton模板。 是的,我描述的方法不是唯一的方法,但是它非常好。

我认为我们可能根本不使用模板,但是与中世纪没有什么不同。 :)

无论如何,由于本系列文章已经完成,因此建议您阅读其他文章,其中还讨论了MVC模式和可编写脚本的对象: 使用Node和Express制作REST服务以与Unity一起使用

仅此而已。 好的编码!

Source: https://habr.com/ru/post/zh-CN479550/


All Articles