Unity中的MVC框架

基本概念

MVC全名是Model View Controller
是模型(model)-视图(view)-控制器(controller)的缩写
是一种软件设计规范,用一种业务逻辑、数据、界面显示 分离的方法组织代码
将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

MVC在游戏开发中不是必备的,它主要用于开发游戏UI系统逻辑

前期准备

接下来要实现一个小的UI面板,分别实现不使用MVC框架和使用MVC框架的代码,以此作为对比。

Canvas设置

非MVC框架实现

主面板逻辑

MainPanel.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainPanel : MonoBehaviour
{
    //1.获得控件
    public Text txtName;
    public Text txtLev;
    public Text txtMoney;
    public Text txtGem;
    public Text txtPower;
    public Button btnRole;

    private static MainPanel panel;
    //2.添加事件
    //3.更新信息
    //4.动态显隐
    //使用静态方法,让NormalMain能够调用
    public static void ShowMe(){
        if(panel == null){
            //实例化面板对象
        GameObject res = Resources.Load<GameObject>("UI/MainPanel");
        GameObject obj = Instantiate(res);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        panel = obj.GetComponent<MainPanel>();
        }
        //如果隐藏形式是setacive,则显示也要set
        panel.gameObject.SetActive(true);
        //显示完面板 更新
        panel.UpdateInfo();
        
    }
    public static void HideMe(){
        if(panel != null){
            //一. 直接删
            // Destroy(panel.gameObject);
            // panel = null;
            //二. 隐藏
            panel.gameObject.SetActive(false);
        }
    }
    // Start is called before the first frame update 
    void Start()
    {
        //2.添加事件
        btnRole.onClick.AddListener(ClickBtnRole);

    }

   private void ClickBtnRole(){
    //打开角色面板的逻辑
    Debug.Log("按钮点击");
   }

   //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();
   }
}

NormalMain.cs

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.M)){
            //显示主面板
            MainPanel.ShowMe();
        }
        else if(Input.GetKeyDown(KeyCode.N)){
            //隐藏主面板
            MainPanel.HideMe();
        }
    }

角色面板逻辑

RolePanel.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class RolePanel : MonoBehaviour
{
   //1.获得控件
    public Text txtLev;
    public Text txtHp;
    public Text txtAtk;
    public Text txtDef;
    public Text txtCrit;
    public Text txtMiss;
    public Text txtLuck;
    public Button btnClose;
    public Button btnLevUp;

    private static RolePanel panel;
    //2.添加事件
    //3.更新信息
    //4.动态显隐
    // Start is called before the first frame update 

    public static void ShowMe(){
        if(panel == null){
            //实例化面板对象
        GameObject res = Resources.Load<GameObject>("UI/RolePanel");
        GameObject obj = Instantiate(res);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        panel = obj.GetComponent<RolePanel>();
        }
        //如果隐藏形式是setacive,则显示也要set
        panel.gameObject.SetActive(true);
        //显示完面板 更新
        panel.UpdateInfo();
        
    }
    public static void HideMe(){
        if(panel != null){
            //一. 直接删
            // Destroy(panel.gameObject);
            // panel = null;
            //二. 隐藏
            panel.gameObject.SetActive(false);
        }
    }

    void Start()
    {
        btnClose.onClick.AddListener(()=>{
            HideMe();
        });

        btnLevUp.onClick.AddListener(()=>{
            //升级就是数据更新
            //这里就是获取本地数据
            int lev = PlayerPrefs.GetInt("PlayerLev",1);
            int hp= PlayerPrefs.GetInt("PlayerHp",100);; 
            int def= PlayerPrefs.GetInt("PlayerDef",10);
            int atk= PlayerPrefs.GetInt("PlayerAtk",20);
            int crit= PlayerPrefs.GetInt("PlayerCrit",20);
            int miss= PlayerPrefs.GetInt("PlayerMiss",10);
            int luck= PlayerPrefs.GetInt("PlayerLuck",40);
            //然后根据升级规则去改变他
            lev += 1;
            hp += lev;
            atk += lev;
            def += lev;
            crit += lev;
            miss += lev;
            luck += lev;
            //存起来
            PlayerPrefs.SetInt("PlayerLev",lev);
            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();
            //更新主面板的数据
            MainPanel.Panel.UpdateInfo();
        });
    }

    //更新信息
    public void UpdateInfo(){
        txtLev.text = "LV." + PlayerPrefs.GetInt("PlayerLev",1).ToString();

        txtHp.text = PlayerPrefs.GetInt("PlayerHp",100).ToString();
        txtAtk.text = PlayerPrefs.GetInt("PlayerAtk",20).ToString();
        txtDef.text = PlayerPrefs.GetInt("PlayerDef",10).ToString();
        txtCrit.text = PlayerPrefs.GetInt("PlayerCrit",20).ToString();
        txtMiss.text = PlayerPrefs.GetInt("PlayerMiss",10).ToString();
        txtLuck.text = PlayerPrefs.GetInt("PlayerLuck",40).ToString();
       
    }
}

MainPanel更新

    public static MainPanel Panel{
        get{
            return panel;
        }
    } 

    private void ClickBtnRole(){
    //打开角色面板的逻辑
        RolePanel.ShowMe();
   }

MVC框架实现

Model数据脚本

using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
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 event UnityAction<PlayerModel> updateEvent;

    //在外部第一次获取这个数据 如何获取
    //通过单例模式 来达到数据的唯一性 和数据获取
    private static PlayerModel data = null;

    public static PlayerModel Data{
        get{
            if(data == null){
                data = new PlayerModel();
                data.Init();
            }
            return data;
        }

    }


    //数据相关的操作
    //   初始化
    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);; 
        def= PlayerPrefs.GetInt("PlayerDef",10);
        atk= PlayerPrefs.GetInt("PlayerAtk",20);
        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);
        }
    }
}

View界面脚本

MainView.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainView : MonoBehaviour
{
    //1.找控件
    public Text txtName;
    public Text txtLev;
    public Text txtMoney;
    public Text txtGem;
    public Text txtPower;
    public Button btnRole;
    public Button btnSkill;

    //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();
    }
}

RoleView.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class RoleView : MonoBehaviour
{
    //1.找控件
    
    public Text txtLev;
    public Text txtHp;
    public Text txtAtk;
    public Text txtDef;
    public Text txtCrit;
    public Text txtMiss;
    public Text txtLuck;
    public Button btnClose;
    public Button btnLevUp;

    //2.提供面板更新的相关方法给外部
    public void UpdateInfo(PlayerModel data){
        txtLev.text = "LV." + data.Lev;
        txtHp.text = data.Hp.ToString();
        txtAtk.text = data.Atk.ToString();
        txtDef.text = data.Def.ToString();
        txtCrit.text = data.Crit.ToString();
        txtMiss.text = data.Miss.ToString();
        txtLuck.text = data.Luck.ToString();
    }
}

Controller业务逻辑

MainController

using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;

/// <summary>
/// Controller要处理的东西 就是业务逻辑
/// </summary>
public class MainController : MonoBehaviour
{
    //能够在Controller中得到界面才行
    private MainView mainView;
    //面板之间的交互都是通过Controller来实现,我们不想让mainView也变成静态被其它访问,
    //因此可以设置个静态的 Controller,因为Controller也要被外部访问
    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);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        controller = obj.GetComponent<MainController>();
        }
        //如果隐藏形式是setacive,则显示也要set
        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(mainView.UpdateInfo);
        PlayerModel.Data.AddEventListener(UpdateInfo);
    }
    
    private void ClickRoleBtn(){
        RoleController.ShowMe();
    }
    //3. 界面的更新
    private void UpdateInfo(PlayerModel data)
    {
        if(mainView != null){
            mainView.UpdateInfo(data);
        }    
    }

    private void OnDestroy() {
        PlayerModel.Data.RemoveEventListener(UpdateInfo);
    }
}


RoleController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Timeline;

public class RoleController : MonoBehaviour
{
    private RoleView roleView;

    private  static RoleController controller = null;
    public static RoleController Controller{
        get{
            return controller;
        }
    }

     public static void ShowMe(){
        if(controller == null){
            //实例化面板对象
        GameObject res = Resources.Load<GameObject>("UI/RolePanel");
        GameObject obj = Instantiate(res);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        controller = obj.GetComponent<RoleController>();
        }
        //如果隐藏形式是setacive,则显示也要set
        controller.gameObject.SetActive(true);

        
    }
    public static void HideMe(){
        if(controller != null){
            controller.gameObject.SetActive(false);
        }
    }
    void Start()
    {
        roleView = this.GetComponent<RoleView>();
        //第一次更新面板
        roleView.UpdateInfo(PlayerModel.Data);

        roleView.btnClose.onClick.AddListener(ClickCloseBtn);
        roleView.btnLevUp.onClick.AddListener(ClickLevUpBtn);
        //PlayerModel.Data.AddEventListener(roleView.UpdateInfo);
        PlayerModel.Data.AddEventListener(UpdateInfo);
    }

    private void ClickCloseBtn(){
        HideMe();
    }

    private void ClickLevUpBtn(){
        //通过数据模块 进行升级 达到数据改变
        PlayerModel.Data.LevUp();
        
    }
    // Update is called once per frame
    private void UpdateInfo(PlayerModel data)
    {
        if(roleView != null){
            roleView.UpdateInfo(data);
        }    
    }

    private void OnDestroy() {
        PlayerModel.Data.RemoveEventListener(UpdateInfo);
    }
}

对比与总结

好处

1.各司其职,互不干涉 --编程思路更清晰
2.有利开发中的分工 -- 多人协同开发时,同步并行
3.有利于组件重用  -- 项目换皮时,功能变化小时,提高开发效率

坏处

1.增加了程序文件的体量  -- 脚本由一变三
2.增加了结构的复杂性  --对于不清楚MVC原理的人不友好
3.效率相对较低     -- 对象之间的相互跳转,始终伴随着一定开销

扩展

MVC的美中不足

M和V之间存在着联系,也就是数据和界面之间存在着耦合性,当数据结构改变时会牵扯界面逻辑随之改动。
在MVC中当需求变化时,需要维护的对象数量会增加

如这一段

改变了PlayerModel中的变量的话,则MainView里的这个函数可能也要调整。

MVX

数据和界面是必备的内容
我们可以通过改变X元素来优化原本的MVC
也就是改变联系和处理M(数据)和V(界面)的方式

MVP:切断View和Model的耦合,让Presenter处理一切
MVVM:MVP的升级版,让ViewModel和V进行双向数据绑定,更新VM等同于更新V,反之同理
MVE:用EventCenter事件中心来分发消息

学习MVX的目的
不要拘泥于框架结构和设计模式要找到一个适合自己项目
一个稳定的,有序的,能满足项目需求的实现方式

MVP

全称为模型(Model)-视图(View)一主持人(Presenter)

Model提供数据,View负责界面,Presenter负责逻辑的处理

它是MVC的一种变式,是针对MVC中M和V存在耦合的优化

与MVC的区别:

在MVC中View会直接从Model中读取数据而不是通过 Controller
而在MVP中View并不直接使用Model,它们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部。

同样是上面的项目

MVP_MainView.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MVP_MainView : MonoBehaviour
{
     //1.找控件
    public Text txtName;
    public Text txtLev;
    public Text txtMoney;
    public Text txtGem;
    public Text txtPower;
    public Button btnRole;
    public Button btnSkill;

    // //2.提供面板更新的方法给外部
    // public void UpdateInfo(string name, int lev, int money, int gem, int power){
    //     txtName.text = name;
    //     txtLev.text = "LV." + lev;
    //     txtMoney.text = money.ToString();
    //     txtGem.text = gem.ToString();
    //     txtPower.text = power.ToString();
    // }
}

MVP_RoleView.cs

public class MVP_RoleView : MonoBehaviour
{
 //1.找控件
    
    public Text txtLev;
    public Text txtHp;
    public Text txtAtk;
    public Text txtDef;
    public Text txtCrit;
    public Text txtMiss;
    public Text txtLuck;
    public Button btnClose;
    public Button btnLevUp;

    //2.提供面板更新的相关方法给外部
    //方法可选 到时候可以直接在P里面通过访问控件 去修改

}

MainPresenter.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MainPresenter : MonoBehaviour
{
 //能够在Presenter中得到界面才行
    private MVP_MainView mainView;
    //面板之间的交互都是通过Controller来实现,我们不想让mainView也变成静态被其它访问,
    //因此可以设置个静态的 Controller,因为Controller也要被外部访问
    private static MainPresenter presenter = null;
    public static MainPresenter Presenter{
        get{
            return presenter;
        }
    }
    //1.界面的显隐
     public static void ShowMe(){
        if(presenter == null){
            //实例化面板对象
        GameObject res = Resources.Load<GameObject>("UI/MainPanel");
        GameObject obj = Instantiate(res);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        presenter = obj.GetComponent<MainPresenter>();
        }
        //如果隐藏形式是setacive,则显示也要set
        presenter.gameObject.SetActive(true);

        
    }
    public static void HideMe(){
        if(presenter != null){

            presenter.gameObject.SetActive(false);
        }
    }

    private void Start(){
        //获取同样挂载在一个对象上的 view脚本
        mainView = this.GetComponent<MVP_MainView>();
        //第一次更新
        //mainView.UpdateInfo(PlayerModel.Data);
        //通过P自己的更新方法来更新
        UpdateInfo(PlayerModel.Data);
        //2.界面 事件的监听 来处理对应的业务逻辑
        mainView.btnRole.onClick.AddListener(ClickRoleBtn);

        //PlayerModel.Data.AddEventListener(mainView.UpdateInfo);
        PlayerModel.Data.AddEventListener(UpdateInfo);
    }
    
    private void ClickRoleBtn(){
        //RoleController.ShowMe();
        RolePresenter.ShowMe();
    }
    //3. 界面的更新
    private void UpdateInfo(PlayerModel data)
    {
        if(mainView != null){
            //mainView.UpdateInfo(data);
            //以前是把数据M传到V中去更新,现在全部由P来做
            mainView.txtName.text = data.PlayerName;
            mainView.txtLev.text = "LV." + data.Lev;
            mainView.txtMoney.text = data.Money.ToString();
            mainView.txtGem.text = data.Gem.ToString();
            mainView.txtPower.text = data.Power.ToString();
        }    
    }

    private void OnDestroy() {
        PlayerModel.Data.RemoveEventListener(UpdateInfo);
    }
}

RolePresenter.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RolePresenter : MonoBehaviour
{
    private MVP_RoleView roleView;

    private  static RolePresenter presenter = null;
    public static RolePresenter Presenter{
        get{
            return presenter;
        }
    }

     public static void ShowMe(){
        if(presenter == null){
            //实例化面板对象
        GameObject res = Resources.Load<GameObject>("UI/RolePanel");
        GameObject obj = Instantiate(res);
        //设置父对象
        obj.transform.SetParent(GameObject.Find("Canvas").transform,false);

        presenter = obj.GetComponent<RolePresenter> ();
        }
        //如果隐藏形式是setacive,则显示也要set
        presenter.gameObject.SetActive(true);

        
    }
    public static void HideMe(){
        if(presenter != null){
            presenter.gameObject.SetActive(false);
        }
    }
    void Start()
    {
        roleView = this.GetComponent<MVP_RoleView>();
        //第一次更新面板
        UpdateInfo(PlayerModel.Data);

        roleView.btnClose.onClick.AddListener(ClickCloseBtn);
        roleView.btnLevUp.onClick.AddListener(ClickLevUpBtn);
        //PlayerModel.Data.AddEventListener(roleView.UpdateInfo);
        PlayerModel.Data.AddEventListener(UpdateInfo);
    }

    private void ClickCloseBtn(){
        HideMe();
    }

    private void ClickLevUpBtn(){
        //通过数据模块 进行升级 达到数据改变
        PlayerModel.Data.LevUp();
        
    }
    // Update is called once per frame
    private void UpdateInfo(PlayerModel data)
    {
        if(roleView != null){
            //直接在p中得到V界面的控件,断开M和V的联系
            roleView.txtLev.text = "LV." + data.Lev;
            roleView.txtHp.text = data.Hp.ToString();
            roleView.txtAtk.text = data.Atk.ToString();
            roleView.txtDef.text = data.Def.ToString();
            roleView.txtCrit.text = data.Crit.ToString();
            roleView.txtMiss.text = data.Miss.ToString();
            roleView.txtLuck.text = data.Luck.ToString();
        }    
    }

    private void OnDestroy() {
        PlayerModel.Data.RemoveEventListener(UpdateInfo);
    }
}

MVP同样由缺点,Presenter中的逻辑很多。

但是之后逻辑修改也只用在Presenter中。

MVVM

全称为模型(Model)-视图(View)-视图模型(ViewModel)
Model提供数据,View负责界面,ViewModel负责逻辑的处理
MVVM的由来是MVP(Model-View-Presenter)模式与WPF结合应用时发展演变过来的一种新型框架

数据绑定

将一个用户界面元素(控件)的属性 绑定到 一个类型(对象)实例上的某个属性的方法。

如果开发者有一个MainViewMode类型的实例,那么他就可以把MainViewMode的“Lev”属性绑定到一个Ul中Text的“Text”属性上。“绑定”了这2个属性之后,对Text的Text属性的更改“传播”MainViewMode的Lev属性,而对MainViewMode的Lev属性的更改同样会“传播”到Text的Text属性

MVVM在Unity中水土不服

因为View对象始终由我们来书写,没有UI配置文件(如WPF中的XAML),要想实现传播需要事件/委托,很麻烦。

硬要在Unity中实现MVVM,需要写三模块,并且还要对V和VM进行数据绑定,工作量大,好处也不够明显

Unity的第三方MVVM框架
Loxodon Framework
https://github.com/vovgou/loxodon-framework
uMVVM
https://github.com/MEyes/uMVVM

MVE

全称为模型(Model)-视图(View)-事件中心(EventCenter)
Model提供数据,View负责界面,EventCenter负责数据传递

好处:

利用事件中心的观察者模式
让M和V层的之间的关系更加灵活多变
减少了目前数据层的负载
将数据层事件全部交由事件中心处理

总结

铁打的M和V,流水的X
数据和界面是必备的内容
我们可以通过改变X元素来优化原本的MVC
也就是改变联系和处理M(数据)和V(界面)的方式

不要拘泥于框架结构和设计模式要找到一个适合自己项目的
一个稳定的,有序的,能满足项目需求的实现方式

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Unity游戏MVC框架可以帮助我们更好地管理UI。MVC是一种将代码的功能进行划分的设计框架,主要原理是将软件用户界面和业务逻辑分离,提高代码的可扩展性、可复用性、可维护性和灵活性。 在Unity,我们可以将MVC框架应用到游戏的UI设计。举个例子来说,当游戏要发布节日活动,并且需要相应地更改游戏UI时,使用MVC框架可以将UI的功能分开,达到低耦合的效果。这样,当替换UI时,其他功能不会受到影响,提高游戏的质量。 在Unity开发过程,许多公司都使用了MVC的逻辑模式,即数据模型-视图-控制器。数据模型负责存储和管理游戏数据,视图负责显示用户界面,而控制器负责处理用户输入和更新数据模型。通过将这些功能分离,我们可以更好地组织和管理UI代码,提高开发效率。 所以,通过应用MVC框架,我们可以更好地管理Unity游戏的UI,提高代码的可维护性和可扩展性,同时也能提高游戏的质量和用户体验。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【Unity3D日常开发】Unity3d使用MVC框架](https://blog.csdn.net/q764424567/article/details/83788696)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Unity框架——MVC框架](https://blog.csdn.net/Htlas/article/details/79076201)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值