Unity中使用MVC模式

前言

MVC模式是视图层控制层模型层代码进行分层开发,视图层只关心UI的变化,控制层获取模型对象,并在数据变化时更新视图,启到统一作用,模型层是获取和更新数据模型的,这样就不必将所有逻辑代码集中一起,看着比较混乱。

1.Unity开发时使用MVC

正常情况每个UI界面对应一个脚本,把逻辑全部写在一起,这样的话太过臃肿,在Unity开发时使用MVC模式去实现游戏功能模块的开发,这样的话每个脚本负责的逻辑就比较清楚了,代码也不会过于臃肿。现在我们就开始模拟一下登陆界面脚本如何使用MVC模式开发,LoginFormCtrl 的代码如下:

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

public sealed class LoginFormCtrl : GameComponent
{
    new LoginFormView iFormView;
    new LoginFormModel iFormModel;

    protected override void Awake()
    {
        base.Awake();
        iFormView = (LoginFormView)base.iFormView;
        iFormModel = (LoginFormModel)base.iFormModel;
    }
    protected override void Start()
    {
        base.Start();
    }

    protected override void Update()
    {
        base.Update();
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
    }
}

LoginFormView的代码如下:

public class LoginFormView: IMVController
{
    public override void Ready()
    {
        
    }

    public override void Renew()
    {
        
    }

    public override void ShutDown()
    {
        
    }

}

LoginFormModel的代码如下:

public class LoginFormModel:IMVController
{
    public override void Ready()
    {
        //注册消息监听
    }

    public override void Renew()
    {
        
    }

    public override void ShutDown()
    {
        //取消消息监听
    }

    private void ReceiveLoginSuccess()
    {
        //TODO 登陆成功消息
    }

    private void ReceiveLoginFailed()
    {
        //TODO 登陆失败消息
    }
}

IMVController的代码如下:

using UnityEngine;
public abstract class IMVController
{
    protected Transform transform;
    protected GameObject gameObject;

    public void Init(Transform transform, GameObject gameObject)
    {
        this.transform = transform;
        this.gameObject = gameObject;
    }

     public abstract void Ready();
     public abstract void Renew();
     public abstract void ShutDown();
}

GameComponent的代码如下:

using System;
using UnityEngine;

public abstract class GameComponent : MonoBehaviour
{
    protected IMVController iFormModel, iFormView;

    protected virtual void Awake()
    {
        string formName = this.GetType().FullName;
        formName = formName.Substring(0, formName.Length - 4);
        iFormView = (IMVController)Activator.CreateInstance(Type.GetType(formName + "View"));
        iFormModel = (IMVController)Activator.CreateInstance(Type.GetType(formName + "Model"));
        iFormView.Init(transform,gameObject);
        iFormModel.Init(transform, gameObject);
    }

    protected virtual void Start()
    {
        iFormView?.Ready();
        iFormModel?.Ready();
    }

    protected virtual void Update()
    {
        iFormView?.Renew();
        iFormModel?.Renew();
    }

    protected virtual void OnDestroy()
    {
        iFormView?.ShutDown();
        iFormModel?.ShutDown();
    }
}

这里就很好诠释Unity如何去使用MVC模式去开发,LoginFormCtrl拥有LoginFormModel和LoginFormView对象,并且会把自身的transform和gameObject共享给Model和View,然后把LoginFormCtrl挂载到实际界面上即可正常使用,具体如图所示:

但是有点难受的事情是LoginFormModel、LoginFormView、LoginFormCtrl都要自己创建,导致浪费了没有必要的时间,所以这里写一个工具去自动生成这三个脚本。

2.自动创建MVC三个脚本

这里可以在Unity上面扩展出一个界面,界面需要生成脚本名和创建脚本路径的文本框,然后点击生成按钮自动创建出MVC三个脚本,具体代码如下:

using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;

public class AutoMvcBuilder : EditorWindow
{
    [MenuItem("Game Framework/AutoMvcBuilder Tool", false, 41)]
    private static void Open()
    {
        Rect area = new Rect(0, 0, 300, 120);
        AutoMvcBuilder window = GetWindowWithRect<AutoMvcBuilder>(area, true, "MVC脚本生成器");
        window.Show();
    }

    static string savePath = string.Empty;
    static string saveFileName = string.Empty;
    static string commonContent =
    "public class {0}{1}:IMVController\r\n" +
    "{2}\r\n" +
    "     public override void Ready()\r\n" +
    "     {3}\r\n\r\n" +
    "     {4}\r\n\r\n" +
    "     public override void Renew()\r\n" +
    "     {5}\r\n\r\n" +
    "     {6}\r\n\r\n" +
    "     public override void ShutDown()\r\n" +
    "     {7}\r\n\r\n" +
    "     {8}\r\n" +
    "{9}";
    static string ctrlContent =
    "public sealed class {0}Ctrl : GameComponent\r\n" +
    "{1}\r\n" +
    "     new {2}View iFormView;\r\n" +
    "     new {3}Model iFormModel;\r\n\r\n" +
    "     protected override void Awake()\r\n" +
    "    {4}\r\n" +
    "        base.Awake();\r\n" +
    "        iFormView = ({5}View)base.iFormView;\r\n" +
    "        iFormModel = ({6}Model)base.iFormModel;\r\n" +
    "    {7}\r\n\r\n" +
    "    protected override void Start()\r\n" +
    "    {8}\r\n" +
    "        base.Start();\r\n" +
    "    {9}\r\n\r\n" +
    "    protected override void Update()\r\n" +
    "    {10}\r\n" +
    "       base.Update();\r\n" +
    "    {11}\r\n\r\n" +
    "    protected override void OnDestroy()\r\n" +
    "    {12}\r\n" +
    "       base.OnDestroy();\r\n" +
    "    {13}\r\n" +
    "{14}";
    private void OnGUI()
    {
        //输入框控件
        GUIStyle buttonStyle = new GUIStyle();
        buttonStyle.alignment = TextAnchor.MiddleCenter;
        buttonStyle.fontSize = 15;
        buttonStyle.fixedWidth = 15;
        buttonStyle.normal.textColor = Color.white;
        buttonStyle.normal.background = null;

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("MVC脚本名:", GUILayout.Width(80));
        saveFileName = EditorGUILayout.TextField(string.Empty,saveFileName, GUILayout.Width(100));
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.Space();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("脚本生成路径:", GUILayout.Width(80));
        savePath = EditorGUILayout.TextField(string.Empty,savePath, GUILayout.Width(190));
        if (GUILayout.Button("⊙", buttonStyle))
            savePath = OpenFolder();
        EditorGUILayout.EndHorizontal();

        GUIStyle tmpStyle = new GUIStyle();
        tmpStyle.alignment = TextAnchor.MiddleCenter;

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("生成"))
        {
            if (!Directory.Exists(savePath))
            {
                this.ShowNotification(new GUIContent("路径不存在!!!"));
                return;
            }              

            File.WriteAllText(savePath + saveFileName + "Model.cs", 
                    string.Format(commonContent,saveFileName,"Model",'{', '{', '}','{', '}','{', '}', '}'), Encoding.UTF8);
            File.WriteAllText(savePath + saveFileName + "View.cs",
                    string.Format(commonContent, saveFileName, "View", '{', '{', '}', '{', '}', '{', '}', '}'), Encoding.UTF8);
            File.WriteAllText(savePath + saveFileName + "Ctrl.cs", string.Format(ctrlContent,
                   saveFileName,'{', saveFileName, saveFileName,'{', saveFileName, saveFileName,'}', '{', '}', '{', '}', '{', '}', '}'), Encoding.UTF8);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            this.ShowNotification(new GUIContent("保存成功!!!"));
        }
        EditorGUILayout.EndHorizontal();
    }

    private string OpenFolder()
    {
        string tmpPath = string.Empty;
        tmpPath = EditorUtility.OpenFolderPanel("Resource Folder", "Assets", string.Empty);
        if (!string.IsNullOrEmpty(tmpPath))
        {
            var gamePath = System.IO.Path.GetFullPath(".");//TODO - FileUtil.GetProjectRelativePath??
            gamePath = gamePath.Replace("\\", "/");
            if (tmpPath.Length > gamePath.Length && tmpPath.StartsWith(gamePath))
                tmpPath = tmpPath.Remove(0, gamePath.Length + 1);
        }
        return tmpPath + '/';
    }
}

具体的运行效果图如下:

具体工程链接如下:

https://download.csdn.net/download/m0_37920739/12199626 

总结

1.MVC的优缺点

优点:1、耦合性低,视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码。2、可维护性高,便于开发和维护。

缺点:1、不适合小型,中等规模的应用程序。2、增加了系统结构和实现的复杂性

2.MVC使用场景

1.Unity、AndroidStudio这些著名开发工具的设计。

2.大型工程开发时经常用到的框架。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值