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一起使用 。
仅此而已。 好的编码!