Unity MVC框架1-2 实战分析

news2024/10/12 5:26:32

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

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);
            //设置它的父对象 为Canvas
            obj.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);
            //设置它的父对象 为Canvas
            obj.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.coloradmin.cn/o/2207077.html

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

相关文章

“CFD+水务”,积鼎通用流体仿真软件VirtualFlow助力水处理能力提升

在快速发展的现代社会中&#xff0c;水务行业作为城市基础设施的重要组成部分&#xff0c;其高效、安全、可持续的运营直接关系到民众的生活质量与城市的健康发展。随着科技的进步&#xff0c;CFD技术正逐步渗透到水务行业的各个角落&#xff0c;以其独特的模拟预测能力&#x…

软件测试学习笔记丨质量门禁 - SonarQube

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32486 一&#xff0c;质量门禁概念 质量门禁是为了控制达标率的检查任务设置质量门禁的好处 通过检查达标状态来评估产品质量&#xff0c;控制产品发布利用自动化任务来控制产品的代码质量&a…

构建高效互通的数字桥梁:香港服务器托管指南

在当今全球化日益加深的商业环境中&#xff0c;出海企业面临着前所未有的机遇与挑战。为了确保国内外业务的顺畅运行&#xff0c;特别是在实现国内外数据高效互通、低延迟访问方面&#xff0c;选择一家合适的香港服务器机房进行托管成为了许多企业的关键决策之一。香港&#xf…

科研绘图系列:R语言蝴蝶图(Butterfly Chart)

文章目录 介绍加载R包数据函数画图系统信息介绍 蝴蝶图(Butterfly Chart),也被称为龙卷风图(Tornado Chart)或双轴图(Dual-Axis Chart),是一种用于展示两组对比数据的图表。这种图表通过在中心轴两侧分别展示两组数据的条形图,形似蝴蝶的翅膀,因此得名。蝴蝶图的特点…

ORM 框架 查询相关函数

1、Ubuntu 实时查看 Mysql 数据库日志 sudo tail -f /var/log/mysql/mysql.log2、Django 的 ORM 3、查询相关函数 4、get filter exclude 方法可以增加条件 &#xff08;1&#xff09;条件格式&#xff1a; 模型类属性名__条件值值 &#xff08;2&#xff09;示例代码 # 在…

Spark优化-缓存和checkpoint

目录 缓存使用 checkpoint使用 两者的区别 如下图,如果不适用缓存,rdd3的数据需要经过两次计算,而每次计算也是在内存中计算,很消耗内存,而使用了缓存,可以直接从缓存中直接获取数据,不需要每次对rdd2进行计算 缓存和checkpoint也叫作rdd的持久化&#xff0c;将rdd的数据存储…

快速总结ACmix

ACMix&#xff1a;On the Integration of Self-Attention and Convolution 卷积和自注意力模块通常遵循不同的设计范式&#xff1a; 传统卷积根据卷积滤波器权重利用局部感受野上的聚合函数&#xff0c;这些权重在整个特征图中共享。 内在特性对图像处理施加了至关重要的归纳…

Linux入门:进程状态与优先级

文章目录 一. OS进程状态1.1 一般分类1.2 运行状态1.3 阻塞状态1.4 挂起状态1.5 并行与并发 二. Linux进程状态2.1 分类2.1.1 R状态2.1.2 S状态2.1.3 D状态2.1.4 T状态与t状态2.1.6 X状态 2.2 僵尸状态&#xff08;Z&#xff09;2.2.1 概念2.2.2 查看状态 三. 进程的优先级3.1 …

6N137S1取反电路图

文章目录 一、前言二、6N137S1性能介绍三、应用电路图 一、前言 在硬件电路设计中需要用到隔离电路&#xff0c;但此引脚输出为WS2812的信号&#xff0c;频率有840khz&#xff0c;所以需要使用逻辑光耦&#xff0c;选用6N137S1光耦&#xff0c;速率能达到10Mhz&#xff0c;能满…

Python+Flask接口判断身份证省份、生日、性别、有效性验证+docker部署+Nginx代理运行

这里写目录标题 一、接口样式二、部署流程2.1 镜像打包2.1.1 准备工作2.1.2 build打包2.1.3 dokcer部署运行2.1.4 Nginx代理 三、代码及文件3.1 index.py3.2 areaCodes.json3.3 Dockerfile 一、接口样式 https://blog.henryplus.cn/idcardApi/idCard/query?idcard{idcard} 二、…

anatraf网络性能监控与故障排除

目录 网络性能监控的必要性 1. 提前预警问题 2. 快速响应与故障排除 网络故障排除的常见场景 1. 带宽不足导致的网络卡顿 2. IP冲突引发的网络中断 3. 网络设备故障 结语 随着现代企业对网络依赖性的日益增强&#xff0c;网络性能监控&#xff08;Network Performance …

进口磁力仪G882SX和原装G882究竟有什么区别?

Geometrics公司的铯光泵磁力仪G882有两个型号&#xff1a;一个是出口型号G882SX&#xff0c;另一个是原装型号G882&#xff0c;出口型号的噪声水平比原装型号高一个量级。国内搞磁力仪的专业人士认为进口型号故意加了噪声。 ​ 在之前的博文《如何利用matlab对G882数据进行频谱…

SpringCloud Alibaba-01 入门简介

1.Spring Cloud Alibaba 是由阿里巴巴结合自身丰富的微服务实践而推出的微服务开发的一站式解决方案。它是 Spring Cloud 生态中的第二代实现&#xff0c;提供了包括服务注册与发现、分布式配置管理、服务限流降级、消息驱动能力、阿里云对象存储、分布式任务调度等在内的多种功…

打开cad自动新建一个图纸

命令栏输入&#xff1a;startmode,改为0 即为自动打开cad新建一个图纸。 改为2&#xff0c;即不会新建图纸。

高效录制 PPT 秘籍:四款卓越录屏软件深度解析

一、引言 在现代工作、学习与知识传播的多元场景中&#xff0c;PPT 已然成为不可或缺的信息载体。将 PPT 内容录制下来&#xff0c;其用途广泛&#xff0c;从教师精心打造线上教学课件&#xff0c;到职场精英分享项目方案&#xff0c;再到培训师筹备培训素材等。而获取优质的 P…

来电无通话界面问题分析

1、问题描述 场测反馈&#xff0c;无法接到电话&#xff0c;被叫失败。 2、Log分析 从Modem log看&#xff0c;空口确实有上报到有相关通话信息 排查AT相关Log&#xff0c;确实有上报AT< EAIC相关命令 查看相关AT指令 /* * EAIC: <call_id>,<number>,<type…

Centos 7.9NFS搭建

原创作者&#xff1a;运维工程师 谢晋 Centos 7.9NFS搭建 NFS服务端安装客户机访问共享配置 NFS服务端安装 SSH连接系统登录到服务端安装nfs服务 # yum -y install nfs-utils2. 安装完成后&#xff0c;查看需要共享的目录&#xff0c;这边共享的是/home目录&#xff0c;如…

C#里在使用DataGridView的过程中,当需要让某行数据进行居中显示

在使用DataGridView的过程中,当需要让某行数据进行居中显示,又需要怎么样来实现的呢? 由于DataGridView显示的过程,最上面一行显示的内容取决于FirstDisplayedCell属性, 因此只要设置这个属性,那么这一行就会显示到列表最顶端上。 要让指定的行显示在中间位置,那么还需要…

ICT产业新征程:深度融合与高质量发展

在信息时代的浪潮中&#xff0c;每一场关于技术革新与产业融合的盛会都闪耀着智慧的光芒&#xff0c;引领着未来的方向。9月25日&#xff0c;北京国家会议中心内&#xff0c;一场聚焦全球信息通信业的顶级盛事——第32届“国际信息通信展”&#xff08;PT展&#xff09;隆重拉开…

基于SSM的教材管理系统(含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的教材管理系统1拥有两种角色&#xff1a; 管理员&#xff1a;学生管理、学院管理、出版社管理、教材管理、入库、分配、订购分类 学生&#xff1a;查看出版社和教材 1.1 背景描…