Unity MVC框架1-2 实战分析

该课程资源来源于唐老狮,吃水不忘打井人,不胜感激

Unity MVC框架演示 1-1 理论分析-CSDN博客

首先你需要知道什么mvc框架,并且对三个层级有个比较清晰的认识,当然不清楚也好,下面例子中将会十分细心地让你理解,你需要有一定的阅读代码的能力和一些耐心

实例场景      

        非常简单的小例子,不涉及任何进阶的知识

         1. 有两个面板,主面板可点击角色出现的面板
         2.按下M会出现主面板,按下N会隐藏,且角色面板可以通过点击与右上角的叉隐藏
         3. 角色面板中,点击升级,角色属性会变化,主面板的人物等级也会变化

        f35ff633cc394d30ae963830dbf643a9.gif

普通的做法

以主面板为例,拆解出如下步骤

1.获得控件

//1.获得控件public Text txtName;public Text txtLev;public Text txtMoney;public Text txtGem;public Text txtPower;public Button btnRole;

2.添加事件

   void Start(){//2.添加事件//btnRole.onClick.AddListener(ClickBtnRole);btnRole.onClick.AddListener(() =>{//打开角色面板的逻辑Debug.Log("按钮点击");//显示角色面板RolePanel.ShowMe();});}private void ClickBtnRole(){//打开角色面板的逻辑//显示角色面板RolePanel.ShowMe();}

3.更新信息

  //3.更新信息public void UpdateInfo(){//获取玩家数据 更新玩家信息//获取玩家数据的方式 1.网络请求 2.json 3.xml 4.2进制 5.PlayerPrefs公共类//通过PlayerPrefs来获取本地存储的玩家信息 更新到界面上txtName.text = PlayerPrefs.GetString("PlayerName", "唐老狮");txtLev.text = "LV." + PlayerPrefs.GetInt("PlayerLev", 1).ToString();txtMoney.text = PlayerPrefs.GetInt("PlayerMoney", 999).ToString();txtGem.text = PlayerPrefs.GetInt("PlayerGem", 888).ToString();txtPower.text = PlayerPrefs.GetInt("PlayerPower", 10).ToString();}

4.动态显隐

    //4.动态显影public static void ShowMe(){if(panel == null){//实例化面板对象GameObject res = Resources.Load<GameObject>("UI/MainPanel");GameObject obj = Instantiate(res);//设置它的父对象 为Canvasobj.transform.SetParent(GameObject.Find("Canvas").transform, false);panel = obj.GetComponent<MainPanel>();}//如果是隐藏的形式hide 在这要显示panel.gameObject.SetActive(true);//显示完面板 更新该面板的信息panel.UpdateInfo();}

发现问题 

        上述代码中,会发现高度耦合,这样简单的例子还好,如果项目一大起来还到处引用那就丸辣,不但乱七八糟,而且就算写了注释过几天重新阅读的难度也会比较大,又浪费时间有不优雅

所以,就出现了MVC框架,将该脚本一分为三,分别放在三个层中
2cdb8f0250b747df90126dd1526d7d22.png

分析和解决问题

那我该如何去分层呢?

在这个例子中,我们就直接将脚本分到MVC三个文件夹里,并试图让其之间产生联系为努力吧

M层---处理数据  

using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Events;/// <summary>
/// 作为一个唯一的数据模型 一般情况 要不自己是个单例模式对象
/// 要不自己存在在一个单例模式对象中
/// </summary>
public class PlayerModel
{//数据内容private string playerName;public string PlayerName{get{return playerName;}}private int lev;public int Lev{get{return lev;}}private int money;public int Money{get{return money;}}private int gem;public int Gem{get{return gem;}}private int power;public int Power{get{return power;}}private int hp;public int HP{get{return hp;}}private int atk;public int Atk{get{return atk;}}private int def;public int Def{get{return def;}}private int crit;public int Crit{get{return crit;}}private int miss;public int Miss{get{return miss;}}private int luck;public int Luck{get{return luck;}}//在外部第一次获取这个数据 如何获取//通过单例模式 来达到数据的唯一性 和数据的获取private static PlayerModel data = null;public static PlayerModel Data{get{if( data == null ){data = new PlayerModel();data.Init();}return data;}}//通知外部更新的事件//通过它和外部建立联系 而不是直接获取外部的面板private event UnityAction<PlayerModel> updateEvent;//数据相关的操作// 初始化public void Init(){playerName = PlayerPrefs.GetString("PlayerName", "唐老狮");lev = PlayerPrefs.GetInt("PlayerLev", 1);money = PlayerPrefs.GetInt("PlayerMoney", 9999);gem = PlayerPrefs.GetInt("PlayerGem", 8888);power = PlayerPrefs.GetInt("PlayerPower", 99);hp = PlayerPrefs.GetInt("PlayerHp", 100);atk = PlayerPrefs.GetInt("PlayerAtk", 20);def = PlayerPrefs.GetInt("PlayerDef", 10);crit = PlayerPrefs.GetInt("PlayerCrit", 20);miss = PlayerPrefs.GetInt("PlayerMiss", 10);luck = PlayerPrefs.GetInt("PlayerLuck", 40);}// 更新 升级public void LevUp(){//升级 改变内容lev += 1;hp += lev;atk += lev;def += lev;crit += lev;miss += lev;luck += lev;//改变过后保存SaveData();}// 保存 public void SaveData(){//把这些数据内容 存储到本地PlayerPrefs.SetString("PlayerName", playerName);PlayerPrefs.SetInt("PlayerLev", lev);PlayerPrefs.SetInt("PlayerMoney", money);PlayerPrefs.SetInt("PlayerGem", gem);PlayerPrefs.SetInt("PlayerPower", power);PlayerPrefs.SetInt("PlayerHp", hp);PlayerPrefs.SetInt("PlayerAtk", atk);PlayerPrefs.SetInt("PlayerDef", def);PlayerPrefs.SetInt("PlayerCrit", crit);PlayerPrefs.SetInt("PlayerMiss", miss);PlayerPrefs.SetInt("PlayerLuck", luck);//保存后执行事件更新方法UpdateInfo();}public void AddEventListener(UnityAction<PlayerModel> function){updateEvent += function;}public void RemoveEventListener(UnityAction<PlayerModel> function){updateEvent -= function;}//通知外部更新数据的方法private void UpdateInfo(){//找到对应的 使用数据的脚本 去更新数据if( updateEvent != null ){updateEvent(this);//updateEvent?.();}EventCenter.GetInstance().EventTrigger<PlayerModel>("玩家数据", this);}
}

V层---负责更新来自model的数据

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class MainView : MonoBehaviour
{//1.找控件public Button btnRole;public Button btnSill;public Text txtName;public Text txtLev;public Text txtMoney;public Text txtGem;public Text txtPower;//2.提供面板更新的相关方法给外部public void UpdateInfo( PlayerModel data ){txtName.text = data.PlayerName;txtLev.text = "LV." + data.Lev;txtMoney.text = data.Money.ToString();txtGem.text = data.Gem.ToString();txtPower.text = data.Power.ToString();}}

C层---玩家控制

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// Controller要处理的东西 就是业务逻辑
/// </summary>
public class MainController : MonoBehaviour
{//能够在Controller中得到界面才行private MainView mainView;private static MainController controller = null;public static MainController Controller{get{return controller;}}//1.界面的显影public static void ShowMe(){if (controller == null){//实例化面板对象GameObject res = Resources.Load<GameObject>("UI/MainPanel");GameObject obj = Instantiate(res);//设置它的父对象 为Canvasobj.transform.SetParent(GameObject.Find("Canvas").transform, false);controller = obj.GetComponent<MainController>();}controller.gameObject.SetActive(true);}public static void HideMe(){if( controller != null ){controller.gameObject.SetActive(false);}}private void Start(){//获取同样挂载在一个对象上的 view脚本mainView = this.GetComponent<MainView>();//第一次的 界面更新mainView.UpdateInfo(PlayerModel.Data);//2.界面 事件的监听 来处理对应的业务逻辑mainView.btnRole.onClick.AddListener(ClickRoleBtn);//告知数据模块 当更新时 通知哪个函数做处理PlayerModel.Data.AddEventListener(UpdateInfo);}private void ClickRoleBtn(){Debug.Log("点击按钮显示角色面板");//通过Controller去显示 角色面板RoleController.ShowMe();}//3.界面的更新private void UpdateInfo( PlayerModel data ){if( mainView != null ){mainView.UpdateInfo(data);}}private void OnDestroy(){PlayerModel.Data.RemoveEventListener(UpdateInfo);}}

 在上述代码中,我们提取对主面板相关的内容,就有如下流程图
8b54768b162349d2a157033ada1bdf55.png

总结

这么看来代码量是增多了,但是确实层次结构清晰了,实际运用要看个人取舍 

跨模块联系中的事件中心(也叫事件的订发布-订阅-取消模式),请参考如下文章

Unity 从零开始的框架搭建1-2 事件的发布-订阅-取消的小优化及调用对象方法总结[半干货]-CSDN博客

 [干货] [非基础警告] Unity 发布-订阅模式下的事件中心设计-CSDN博客

 

        

 

 

 

 

 

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

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

相关文章

光控资本:牛市一般维持多长时间?牛市的轮涨顺序是什么?

牛市继续多长时间没有一个统一标准&#xff0c;我们是无法判断牛市什么时候到来&#xff0c;什么时候结束的。以A股牛市前史为例&#xff0c;继续时间从几十天到几年的情况都有&#xff0c;是没有规则可循的&#xff0c;现在A股继续最久的一次牛市是862天。 纵观A股前史&#…

【路径规划】创建末端执行器的路径,导入URDF模型,使用逆向运动学进行路径规划

摘要 本文通过路径规划为机器人末端执行器生成运动路径&#xff0c;采用URDF&#xff08;Unified Robot Description Format&#xff09;导入机器人模型&#xff0c;并结合逆向运动学进行路径规划和控制。使用Matlab进行建模和仿真&#xff0c;以确保执行器沿预定路径顺利运动…

API调用comfyui工作流,做一个自己的app,chatgpt给我写的前端,一键创建自己的卡通形象,附源码

前言 工具介绍 首先 comfyui你是少不了的&#xff0c;这个是工作流的后端支持&#xff0c;用这个去调试工作流和生成API可调用文件 前端我们就用很流行的gradio吧&#xff0c;什么你一时半会没有学gradio的计划&#xff0c;没事&#xff0c;笔者也没系统学过&#xff0c;我干…

Ubuntu18.04安装cuda11.1(出现c++版本问题)

一、概述 需要使用到ubuntu18.04进行cuda的配置&#xff0c;最新版本的cuda跟pytorch的版本不太适配&#xff0c;所以为了能够复现&#xff0c;我选择了一些老版本的cuda11&#xff0c;其使用的范围更加广泛。将自己 二、具体操作 &#xff08;一&#xff09;安装流程 1.官网…

[Linux#62][TCP] 首位长度:封装与分用 | 序号:可靠性原理 | 滑动窗口:流量控制

目录 一. 认识TCP协议的报头 1.TCP头部格式 2. TCP协议的特点 二. TCP如何封装与分用 TCP 报文封装与解包 如何封装解包&#xff0c;如何分用 分离有效载荷 隐含问题&#xff1a;TCP 与 UDP 报头的区别 封装和解包的逆向过程 如何分用 TCP 报文 如何通过端口号找到绑…

帝国CMS系统开启https后,无法登陆后台的原因和解决方法

今天本地配置好了帝国CMS7.5&#xff0c;传去服务器后&#xff0c;使用http访问一切正常。但是当开启了https&#xff08;SSL&#xff09;后&#xff0c;后台竟然无法登陆进去了。 输入账号密码后&#xff0c;点击登陆&#xff0c;跳转到/e/admin/ecmsadmin.php就变成页面一片…

多线程会在一个事务里面吗?

目录 多线程会在一个事务里面吗&#xff1f; 多线程、数据库事务以及数据库连接之间的关系 Spring的事务管理​​​​​​​ 声明式事务Transactional的实现原理 声明式事务Transactional的失效场景 Transactional注解的方法不是public为什么会失效 Spring AOP的代理机制…

【C++】——继承(下)

【C】——继承&#xff08;下&#xff09; 5 继承与友元6 继承与静态成员7 多继承7.1 继承模型7.2 菱形继承的问题7.3 虚继承7.4 多继承中的指针偏移问题 8 组合与继承 5 继承与友元 友元关系不能被继承。即一个函数是父类的友元函数&#xff0c;但不是子类的友元函数。也就是说…

【C++】用红黑树模拟实现set与map

目录 一、红黑树的完善&#xff1a; 1、红黑树节点模版的修改&#xff1a; 2、仿函数在模拟实现中的应用&#xff1a; 3、新增迭代器&#xff1a; 4、红黑树中的迭代器实现&#xff1a; 二、set与map的模拟实现&#xff1a; 1、insert&#xff1a; 2、map的[ ]: 三、测…

HTML的介绍

HTML HTML是一种超文本标记语言,超文本是指,除了文本之外,还可能包含图片,音频,或者评注等的 文本形式,比文本强大,通过链接和交互方式来组织和呈现信息.标记语言是指,由标签构成的语言.HTML定义了多种不同的标签,用来表示不同的内容. 标签的介绍: 1.<h3> 三级 </h3&…

如何彻底掌握 JavaScript 23种设计模式

设计模式是解决特定问题的常用解决方案&#xff0c;它们可以帮助开发者编写更清晰、可维护、可扩展的代码。在 JavaScript 中&#xff0c;常见的设计模式可以分为三大类&#xff1a;创建型模式、结构型模式 和 行为型模式。本文将全面介绍 JavaScript 中常见的设计模式&#xf…

云计算第四阶段 CLOUD2周目 01-03

国庆假期前&#xff0c;给小伙伴们更行完了云计算CLOUD第一周目的内容&#xff0c;现在为大家更行云计算CLOUD二周目内容&#xff0c;内容涉及K8S组件的添加与使用&#xff0c;K8S集群的搭建。最重要的主体还是资源文件的编写。 (*^▽^*) 环境准备&#xff1a; 主机清单 主机…

【D3.js in Action 3 精译_033】4.1.0 DIY 实战:如何通过学习 d3.autoType 函数深度参与 D3 生态建设

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

基于YOLO11/v10/v8/v5深度学习的安检X光危险品检测与识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

Microsoft Visual Studio安装gtest

1. 参考【Windows Visual Studio下安装和使用google test&#xff08;gtest&#xff09;】 https://blog.csdn.net/Bule_Zst/article/details/78420894 2. 编译gtest使用Win32模式。 3. 配置属性&#xff0c;C/C&#xff0c;常规&#xff0c;附加包含目录 …

Zilliz获Forrester报告全球第一;OB支持向量能力;Azure发布DiskANN;阿里云PG发布内置分析引擎

重要更新 1. Azure发布PostgreSQL向量索引扩展DiskANN&#xff0c;声称在构建HNSW/IVFFlat索引上&#xff0c;速度、精准度都超越pg_vector&#xff0c;并解决了pg_vector长期存在的偶发性返回错误结果的问题( [1] )。 2. 阿里云RDS PostgreSQL 发布AP加速引擎&#xff08;rds…

《Programming from the Ground Up》读后感

之所以看这本书&#xff0c;是想了解一些跟汇编相关的知识&#xff0c;打开这本书后就被作者的观点——“If you don’t understand something the first time, reread it. If you still don’t understand it, it is sometimes best to take it by faith and come back to it …

qemu启动busybox虚拟机网络连接配置

一、busybox文件系统网络问题 由于根文件是用busybox构建&#xff0c;所以很多配置文件是没有的&#xff0c;包括部分网络的默认设置。启动虚拟机后只能使用ip命令和ifconfig命令查看网络状态。 二、开启qemu网络支持 想要使虚拟机上网&#xff0c;最简单的方式可以使用 -netde…

Opencv中的直方图(3)直方图比较函数compareHist()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 比较两个直方图。 函数 cv::compareHist 使用指定的方法比较两个密集或两个稀疏直方图。 该函数返回 d ( H 1 , H 2 ) d(H_1, H_2) d(H1​,H2​…

南科大分享|大数据技术如何赋能大模型训练及开发

嘉宾介绍 张松昕&#xff0c;南方科技大学统计与数据科学系研究学者&#xff0c;UCloud 顾问资深算法专家&#xff0c;曾任粤港澳大湾区数字经济研究院访问学者&#xff0c;主导大模型高效分布式训练框架的开发&#xff0c;设计了 SUS-Chat-34B 的微调流程&#xff0c;登顶 Ope…