Unity | 框架MVC

目录

一、MVC介绍

二、搭建UI界面

三、代码实现

1.Model层

2.View层

3.Controller层

四、MVC框架测试

五、知识补充


一、MVC介绍

  1. model:数据层。界面展示的数据(需要进行初始化、更新、保存、事件通知等操作),单例模式,不必继承MonoBehaviour。
  2. view:界面层。寻找UI,提供更新UI控件的方法,供controller调用。要挂在预制体上。
    (1)MVC是对M和V层进行了解耦,但没有完全解耦,从而诞生了MVP:对M和V层完全解耦。
    (2)MVC里view还是具备直接得到model的权限的,MVP框架是完全把视图跟模型分离了。
  3. controller:处理业务逻辑。控制View的显隐及更新,事件监听及取消。要挂在预制体上。
    (1)注意:物体隐藏时,OnDestroy不会被调用。
    (2)一个view对应一个controller。

二、搭建UI界面

        搭建如下的UI界面,并制作成预制体,并放于Resources\Prefabs目录。

三、代码实现

        创建三个脚本:Model.cs、View.cs、Controller.cs。并将View.cs、Controller.cs挂于预制体上。

1.Model层

using System;
using UnityEngine;public class Model
{// 单例private static Model instance;public static Model Instance{get{if (instance == null){instance = new Model();instance.Init();}return instance;}}// 数据private int coinCount;public int CoinCount  {get { return coinCount; }}// 数据操作:初始化、更新、保存private void Init(){coinCount = PlayerPrefs.GetInt("CoinCount", 0);}public void UpdateCoinCount(){++coinCount;Save();}private void Save(){PlayerPrefs.SetInt("CoinCount", coinCount);CallEvent();}// 事件:用于通知Controller进行更新Viewprivate event Action<Model> ModelEvent;public void AddEventListener(Action<Model> function){ModelEvent += function;}public void RemoveEventListener(Action<Model> function){ModelEvent -= function;}private void CallEvent(){ModelEvent?.Invoke(this);}
}

2.View层

using UnityEngine;
using UnityEngine.UI;public class View : MonoBehaviour
{//提供UI控件public Text coinText;public Button addCoinButton;//提供更新UI控件的方法public void UpdateCoin(Model model){coinText.text = model.CoinCount.ToString();}
}

3.Controller层

        一个UI预制体对应一个View、一个Controller。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Controller : MonoBehaviour
{//controller控制viewprivate View view;private static Controller controller;public static Controller Instance{get{return controller;}}//1.面板显示隐藏public static void Show(){if (controller == null){var temp = Resources.Load<GameObject>("Prefabs/UIPanel");var go = Instantiate(temp);go.transform.parent = GameObject.Find("Canvas").transform;go.transform.localPosition = Vector3.zero;go.transform.localScale = Vector3.one;controller = go.GetComponent<Controller>();}controller.gameObject.SetActive(true);}public static void Hide(){if (controller != null){controller.gameObject.SetActive(false);}}void Start(){view = GetComponent<View>();//2.首次更新面板数据view.UpdateCoin(Model.Instance);//3.事件监听,更新数据view.addCoinButton.onClick.AddListener(() =>{Model.Instance.UpdateCoinCount();});Model.Instance.AddEventListener(UpdateCoin);}private void UpdateCoin(Model model){//2.更新面板数据view.UpdateCoin(model);}private void OnDestroy(){Model.Instance.RemoveEventListener(UpdateCoin);}
}

四、MVC框架测试

using UnityEngine;public class TestMVC : MonoBehaviour
{void Update(){if (Input.GetMouseButtonDown(0)){Controller.Show();}if (Input.GetMouseButtonDown(1)){Controller.Hide();}}
}

五、知识补充

    private event Action<Model> ModelEvent;public void AddEventListener(Action<Model> function){ModelEvent += function;}public void RemoveEventListener(Action<Model> function){ModelEvent -= function;}private void CallEvent(){ModelEvent?.Invoke(this);}

        在C#中,event关键字用于声明一个事件,它本质上是一种特殊的多播委托。`ModelEvent`在这里是一个事件,当你对其使用`+=`操作符时,你实际上是将一个回调方法添加到委托的调用列表中。如果你注册了多个回调,那么这些回调方法就会被添加到`ModelEvent`的调用链中。

        当调用`ModelEvent?.Invoke(this);`时,以下是在底层发生的事情:

  1. 空值检查:`?.`是C# 6.0中引入的空条件运算符。它在尝试调用方法或访问成员之前会检查左侧的对象是否为`null`。如果`ModelEvent`不为`null`,那么调用继续;如果为`null`,那么调用就不会执行,整个表达式的结果也是`null`。
  2. Invoke方法:`Invoke`是`MulticastDelegate`类的一个方法,它负责同步地调用委托链中的每个回调方法。`this`关键字是传递给每个回调方法的参数,表示事件的发起者。
  3. 多播委托的调用链:`ModelEvent`作为一个多播委托,可以持有对多个方法的引用。当你调用`Invoke`时,它按照注册的顺序调用这些方法。如果调用链中的任何一个方法抛出异常,那么后续的方法调用将不会执行,除非你捕获并处理了这个异常。
  4. 线程安全性:虽然`?.`操作符提供了对`null`的检查,但这并不保证线程安全性。如果在检查`ModelEvent`之后和调用`Invoke`之前,另一个线程将`ModelEvent`设置为`null`,那么仍然会抛出`NullReferenceException`。在多线程环境中,通常需要额外的同步机制来确保线程安全。
  5. 事件的触发:如果`ModelEvent`不为空,`Invoke`会触发事件,即调用所有注册的回调方法。这些方法将按照它们被添加到委托中的顺序被调用。

        在C#中,事件的使用是一种很好的设计模式,它允许对象通知其他对象发生了某些事情,而不需要知道这些对象是谁或者它们要做什么。这有助于保持代码的解耦和灵活性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/332177.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React中显示数据

SX 会让你把标签放到 JavaScript 中。而大括号会让你 “回到” JavaScript 中&#xff0c;这样你就可以从你的代码中嵌入一些变量并展示给用户。例如&#xff0c;这将显示 user.name&#xff1a; return (<h1>{user.name}</h1> ); 你还可以将 JSX 属性 “转义到 …

宁夏银川、山东济南、中国最厉害的改名大师的老师颜廷利教授的前沿思想观点

在当代社会&#xff0c;一个响亮的声音穿越了传统的迷雾&#xff0c;它来自东方哲学的殿堂&#xff0c;由一位现代学者颜廷利教授所发出。他的话语&#xff0c;如同一股清泉&#xff0c;在混沌的世界里激荡着思考的波澜&#xff1a;"有‘智’不在年高&#xff0c;无‘智’…

嵌入式之音频基础知识

声音特性 1、响度&#xff1a;人主观上感觉声音的大小&#xff08;俗称音量&#xff09;&#xff0c;由“振幅”和人离声源的距离决定&#xff0c;振幅越大响度越大&#xff0c;人和声源的距离越小&#xff0c;响度越大&#xff1b; 2、音调&#xff1a;声音的高低&#xff0…

无人机反制:光电干扰一体设备技术详解

一、光电干扰技术原理 光电干扰技术是一种利用光学和电子技术手段对无人机实施干扰和控制的先进技术。该技术通过向无人机发射特定频率和强度的光信号或电磁信号&#xff0c;干扰无人机的视觉系统、控制系统或通信链路&#xff0c;进而达到反制无人机的目的。光电干扰技术具有…

world machine学习笔记(4)

选择设备&#xff1a; select acpect&#xff1a; heading&#xff1a;太阳的方向 elevation&#xff1a;太阳的高度 select colour&#xff1a;选择颜色 select convexity&#xff1a;选择突起&#xff08;曲率&#xff09; select height&#xff1a;选择高度 falloff&a…

neo4j开放远程连接

注&#xff1a;本博客所用neo4j版本为社区5.12版 第一步&#xff1a;修改neo4j配置文件 首先找到neo4j的安装位置&#xff0c;点击进入conf文件夹&#xff0c;随后点击neo4j.conf文件&#xff0c;在“Network connector configuration”下面的单元中找到server.default_liste…

7款好用到离谱的神级App推荐!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 转眼间&#xff0c;2024年已经是下个月。最近有很多小伙伴的咨询&#xff0c;我也赶紧整理了7款好用的软件&#xff0c;希望对大家有所帮助。 …

Elasticsearch 分析器(内置分析器,自定义分析器,IK分析器)

Elasticsearch 分析器&#xff08;内置分析器&#xff0c;自定义分析器&#xff0c;IK分析器&#xff09; 内置分析器使用分析器自定义分析器中文分析器&#xff08;IK分析器&#xff09;安装使用添加词典 内置分析器 官网&#xff1a;https://www.elastic.co/guide/en/elasti…

03_前端三大件CSS

文章目录 CSS用于页面元素美化1.CSS引入1.1style方式1.2写入head中&#xff0c;通过写style然后进行标签选择器加载样式1.3外部样式表 2.CSS样式选择器2.1 元素选择器2.2 id选择器2.3 class选择器 3.CSS布局相关3.1 CSS浮动背景&#xff1a;先设计一些盒子因此&#xff0c;引出…

【qt】QTreeWidget 树形组件

QTreeWidget 树形组件 一.什么是树形组件二.界面设计树形组件三.代码实现1.清空2.设置列数3.设置头标签4.添加根目录①QTreeWidgetitem②设置文本③设置图标④添加为顶层目录 5.添加子目录①初始化为父目录②子目录添加到父目录③获取到子目录 四.插入目录1.获取当前选中目录项…

python数据类型之元组、集合和字典

目录 0.三者主要作用 1.元组 元组特点 创建元组 元组解包 可变和不可变元素元组 2.集合 集合特点 创建集合 集合元素要求 集合方法 访问与修改 子集和超集 相等性判断 集合运算 不可变集合 3.字典 字典特点 字典创建和常见操作 字典内置方法 pprin模块 0.…

Vxe UI 表单设计器、零代码平台

vxe-pc-ui Vxe UI 表单设计器、零代码表单设计器 安装 Vxe UI PC端组件库 官方文档 查看 github、gitee // ...import VxeUI from vxe-pc-uiimport vxe-pc-ui/lib/style.css// ...// ...createApp(App).use(VxeUI).mount(#app)// ...使用 vxe-form-design 设计器组件 vxe-fo…

分享活动规划

前两天去参加菁英学院的一些辅导&#xff0c;是关于苏州久富农业机械的发展&#xff0c;看了他们企业的故事&#xff0c;我觉得我们农机很有前景和发展空间&#xff0c;我希望重新经过一次分享活动来分享我的感触&#xff0c;希望能够再次把我学到的内容传输到其他班的同学们 请…

word 全文中 英文字体 和 样式的字体 莫名奇妙地 被改成 “等线”

word全文中英文字体和样式的字体莫名奇妙地被改成“等线” sm word又抽风了&#xff0c;改完论文保存后打开突然发现全文字体都不对劲&#xff0c;吓得冷汗直冒&#xff1a;虽然我用git管理了论文版本&#xff0c;但是只有比较大的修改我才上传了&#xff0c;刚刚修了几个小时…

Redis篇 redis基本命令和定时器原理

基本命令和定时器原理 一. exists命令二. del命令三. Expire命令四. ttl命令五. redis的过期策略六. 定时器的两种设计方式七. type命令 一. exists命令 用来判断key的值是否存在 返回值是key的个数 这样写的话&#xff0c;有没有什么区别呢&#xff1f; 效率变低&#xff0c;消…

猫抓(cat-catch)插件的常规用法

目录 1.1、前言1.2、抓取图片资源1.3、抓取音频资源1.4、抓取视频资源 1.1、前言 本文将介绍利用猫抓&#xff08;cat-catch&#xff09;插件如下抓取网页上的图片、音频、视频等资源&#xff0c;猫抓&#xff08;cat-catch&#xff09;插件的安装及设置请参考推荐一款媒体影音…

ionic关于@angular版本报错解决方案(有效)

最近学校要求使用ionicangular学习&#xff0c;但是出现下面问题&#xff0c;这里我就分享一个我亲测有效的解决方案&#xff0c;提供学习&#xff08;在VScode中&#xff09; npm error code ERESOLVE npm error ERESOLVE could not resolve npm error npm error While resol…

数据迁移测试经验分享

以下为作者观点&#xff1a; 数据迁移&#xff0c;是在保证新旧系统业务连续性的前提下&#xff0c;将数据从旧数据库迁移到新数据库的过程&#xff0c;测试前通过迁移策略和方案了解新旧系统数据如何重构与关联&#xff0c;测试过程需确保数据迁移的正确性&#xff0c;主要体…

vs2013使用qt Linguist以及tr不生效问题

一、qt Linguist&#xff08;语言家&#xff09;步骤流程 1、创建翻译文件,在qt选项中 2.选择对应所需的语言&#xff0c;得到.ts后缀的翻译文件 3.创建.pro文件&#xff0c;并将.ts配置在.pro文件中 3.使用qt Linguist 打开创建好的以.ts为后缀的翻译文件&#xff0c;按图所示…