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.mzph.cn/diannao/15651.shtml

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

相关文章

【golang】内存对齐

什么是内存对齐 在访问特定类型变量的时候通常在特定的内存地址访问&#xff0c;这就需要对这些数据在内存中存放的位置有限制&#xff0c;各种类型数据按照一定的规则在空间上排列&#xff0c;而不是顺序的一个接一个的排放&#xff0c;这就是对齐。 内存对齐是编译器的管辖…

机器视觉-硬件

机器视觉-硬件 镜头焦距凸透镜焦点不止一个相机镜头由多个镜片组成对焦和变焦 镜头光圈光圈的位置光圈系数F 镜头的景深景深在光路中的几何意义 远心镜头远心镜头的种类远心镜头特性应用场景 镜头的分辨率镜头反差镜头的MTF曲线镜头的靶面尺寸镜头的几何相差相机镜头接口螺纹接…

个人手里有一批宽带资源,想跑PCDN 如何做?

网友问我手里有一批宽带资源&#xff0c;想要跑PCDN该如何做&#xff0c;可以按照以下步骤操作&#xff1a; 了解PCDN的基本原理和市场需求。PCDN&#xff08;Peer-to-Content Delivery Network&#xff09;是一种基于P2P技术的内容分发网络&#xff0c;通过将用户设备上的空闲…

javas-core VS java-object-diff

对照工具选择 javas-core 和 java-object-diff ,对比demo https://github.com/kofgame/objectdiff-vs-javers&#xff0c;都为同源对比&#xff0c;都支持嵌套对象。 使用JMH测试方法进行性能测试&#xff0c;使用题库的QuestionResponseVO对象来进行对照对比&#xff0c;进行…

【Python搞定车载自动化测试】——Python基于Pytest框架实现UDS诊断自动化(含Python源码)

系列文章目录 【Python搞定车载自动化测试】系列文章目录汇总 文章目录 系列文章目录&#x1f4af;&#x1f4af;&#x1f4af; 前言&#x1f4af;&#x1f4af;&#x1f4af;一、环境搭建1.软件环境2.硬件环境 二、目录结构三、源码展示1.诊断基础函数方法2.诊断业务函数方法…

深入探索Python基础:两个至关重要的函数

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、初学者的基石&#xff1a;print与input函数 二、类型转换&#xff1a;从字符串到浮点数…

【完整解析】2024电工杯数学建模A题论文与代码

园区微电网风光储协调优化配置 1 论文2 代码分享2.1 第三题第一问 3 数据与代码 1 论文 2 代码分享 2.1 第三题第一问 function anssq3w1ObjFun(ttt,id); %ttttt(1); tt[750,0,0,1000,600,500]; limttt(1)*200; limmttt(2)*500*0.9-ttt(2)*500*0.1; t1ttt(3)*1000;t2ttt(4)*1…

ASP+ACCESS多功能论坛程序设计

摘 要 随着计算机的广泛应用&#xff0c;人们已经对网络不再感到陌生。在科技飞速发展的今天&#xff0c;电脑信息技术与各行各业进行了有效的结合。人们在网上可以进行网上购物&#xff0c;网上交友&#xff0c;电子商务&#xff0c;网络营效等等。面对强大的网络功能&#x…

通过Kafka-Logger插件收集流量进行漏洞扫描

通过Kafka-Logger插件收集流量进行漏洞扫描 方案 可以通过APISIX kafka-logger 插件将日志作为 JSON 对象推送到 Apache Kafka 集群中&#xff0c;消费Kafka里的数据格式化后添加到MySQL。 方案详情 1、登录APISIX&#xff0c;启用内置的kafka-logger 插件&#xff1a; 2…

从 0 实现一个文件搜索工具 (Java 项目)

背景 各文件系统下, 都有提供文件查找的功能, 但是一般而言搜索速度很慢 本项目仿照 everything 工具, 实现本地文件的快速搜索 实现功能 选择指定本地目录, 根据输入的信息, 进行搜索, 显示指定目录下的匹配文件信息文件夹包含中文时, 支持汉语拼音搜索 (全拼 / 首字母匹配…

DiffMap:首个利用LDM来增强高精地图构建的网络

论文标题&#xff1a; DiffMap: Enhancing Map Segmentation with Map Prior Using Diffusion Model 论文作者&#xff1a; Peijin Jia, Tuopu Wen, Ziang Luo, Mengmeng Yang, Kun Jiang, Zhiquan Lei, Xuewei Tang, Ziyuan Liu, Le Cui, Kehua Sheng, Bo Zhang, Diange Ya…

解决go install 网络问题

rootiZbp1hiqzlhh6w05gloffgZ:~# go install mvdan.cc/garblelatest go: mvdan.cc/garblelatest: module mvdan.cc/garble: Get "https://proxy.golang.org/mvdan.cc/garble/v/list": dial tcp 172.217.160.81:443: i/o timeout解决方法 更换阿里代理 rootiZbp1hiq…

浅论未来 IT 和财务结合的趋势

前言 会计核算企业各类业务单据&#xff0c;所有业务部门的数据都会汇流到财务部来&#xff0c;所以会计其实是企业的数据中心&#xff1b;而 IT 技术正是处理数据的利器&#xff0c;可以将重复的流程自动化&#xff0c;还能将财务数据可视化&#xff1b;因此&#xff0c;两者…

SPI通信(STM32)

一、SPI通信 &#xff11;、SPI&#xff08;Serial Peripheral Interface&#xff09;是由Motorola公司开发的一种通用数据总线 &#xff12;、四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff09;、MOSI&#xff08;Master Output Slave Input&#xff09;、MIS…

esp32-idf 开发踩坑记录

现象 直接使用原始命令编译idf.py build 但是提示idf 版本错误 卸载旧版本 编译出错build 问题 然后删除编译文件后&#xff0c;重新编译&#xff0c;还是出错 解决方法1 最后发现是因为项目所在文件夹有中文目录&#xff0c;把项目迁移到英文目录后&#xff0c;重新编译&a…

打破传统相亲模式,这几款靠谱的相亲软件助你脱单

相亲软件在当今社会已经变得越来越普遍&#xff0c;市面上有众多相亲软件可供选择&#xff0c;但哪些相亲软件好用呢&#xff1f;下面介绍几款备受好评的相亲软件&#xff0c;帮助你在茫茫人海中找到那个对的人&#xff01; 1、一伴婚恋 这个APP它最大的优点就是信息真实靠谱…

Filter和Interceptor

会话 cookie 服务器自动将cookie响应给浏览器 浏览器接收响应回来的数据 自动将cookie存储在本地&#xff0c; 后续请求当中浏览器将cookie携带到服务器 cookie不能跨域&#xff0c;存储在客户端 session 存储在服务器 token------>JWT 存储在客户端&#xff0c; 服务…

【C++ QT项目实战-03】---- C++ QT系统实现读取JSON文件数据的自动化模式

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a;C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &#…

Flink 窗口

窗口&#xff08;Window&#xff09; 窗口是处理无限流的核心。 窗口将流分割成有限大小的“桶”&#xff0c;我们可以计算窗口中的数据。 窗口程序一般有键控流&#xff08;keyed streams&#xff09;的窗口程序 和 非键控流&#xff08;non-keyed streams&#xff09;的窗口…

Rabbitmq 搭建使用案例 [附源码]

Rabbitmq 搭建使用案例 文章目录 RabbitMQ搭建docker 代码golang生产者消费者 可视化消费进度 RabbitMQ搭建 docker docker run -d --hostname rabbitmq --name rabbitmq -e RABBITMQ_DEFAULT_USERadmin -e RABBITMQ_DEFAULT_PASSadmin -e RABBITMQ_DEFAULT_VHOSTmy_vhost -e…