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层

cs 复制代码
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进行更新View
    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);
    }
}

2.View层

cs 复制代码
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。

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
    //controller控制view
    private 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框架测试

cs 复制代码
using UnityEngine;

public class TestMVC : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Controller.Show();
        }
        if (Input.GetMouseButtonDown(1))
        {
            Controller.Hide();
        }
    }
}

五、知识补充

cs 复制代码
    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#中,事件的使用是一种很好的设计模式,它允许对象通知其他对象发生了某些事情,而不需要知道这些对象是谁或者它们要做什么。这有助于保持代码的解耦和灵活性。

相关推荐
杨半仙儿还未成仙儿16 小时前
Spring框架:Spring Core、Spring AOP、Spring MVC、Spring Boot、Spring Cloud等组件的基本原理及使用
spring boot·spring·mvc
Artistation Game1 天前
九、怪物行为逻辑
游戏·unity·游戏引擎
百里香酚兰1 天前
【AI学习笔记】基于Unity+DeepSeek开发的一些BUG记录&解决方案
人工智能·学习·unity·大模型·deepseek
无理 Java1 天前
【技术详解】SpringMVC框架全面解析:从入门到精通(SpringMVC)
java·后端·spring·面试·mvc·框架·springmvc
dangoxiba1 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十三集:制作小骑士的接触地刺复活机制以及完善地图的可交互对象
游戏·unity·visualstudio·c#·游戏引擎
椰椰椰耶1 天前
【Spring】@RequestMapping、@RestController和Postman
java·后端·spring·mvc
先生沉默先2 天前
使用Materialize制作unity的贴图,Materialize的简单教程,Materialize学习日志
学习·unity·贴图
十画_8242 天前
Visual Studio 小技巧记录
unity·visual studio
red_redemption2 天前
cpp,git,unity学习
git·unity·游戏引擎
tealcwu2 天前
【Unity踩坑】Unity更新Google Play结算库
unity·游戏引擎