(架构)UI开发的MVC模式

原文:http://engineering.socialpoint.es/MVC-pattern-unity3d-ui.html

动机

  和游戏开发的其他模块类似,UI一般需要通过多次迭代开发,直到用户体验近似OK。另外至关重要的是, 我们想尽快加速迭代的过程。使用MVC模式来进行设计,已经被业界证明了是可以解耦屏幕上的显示,如何控制用户的输入对显示的改变,以及如何根据应用的状态进行改变。MVC模式提供了以下好处:

  1. 可以修改UI的外观,而不用修改一行代码;
  2. 在不同的组件里面可以共享同一套逻辑代码,用来创建复杂的视图;
  3. 可以用很小的代价来改变UI的实现,比如正在使用NGUI , 但将来会切换成 UGUI。

代码示例

  这里提供了一个MVC在使用NGUI开发的例子,需要注意的是,我们不能在代码中提供NGUI库,毕竟它是收费的,所以想运行起来的话,需要自己导入NGUI库。接下来的内容都会以这个例子的代码作为基准,所以可以在阅读时可以先把代码下载下来。

总体概述

  这是一张简图,从宏观的角度描述了代码中MVC模式的不同部分。

  

Model

  传统的MVC中的Model,我们都很熟悉:

  1. 不保存任何View的数据或者View的状态;
  2. 只能被Controller或者其他Model访问;
  3. 会触发事件来通知外部系统进行处理和变更。

  这里的Model是使用Plain Old C# Objects(POCOs)来实现的,就是不依赖于任何外部库的C#代码。这是例子中对于PlayerModel的链接地址,它表示了Player的数据,包括HitPoints,XP和level,使用两个属性来进行访问。我们可以增加XP点,而Model则会raise一个XPGained事件。当获得升级的经验时,Level属性会更新,并raise一个LevelUp事件。

View

  概念上的view一般就是在屏幕上渲染的东西。View的职责包括:

  1. 处理用户绘制元素的reference,包括纹理,特效等;
  2. 播放动画;
  3. 布局;
  4. 接受用户输入。

  在代码这个特定例子中,View的实现使用了NGUI,所以它只是Unity工程中的一个Prefab。但这个实现细节需要解耦。想了解更多学术上的知识的话,还可以看下Passive View。View不知道工程中其他部分的任何事情,无论是数据还是逻辑。这样其他的代码必选显式地告诉View显式什么,播放什么动画等等。

Controller

  Controller是连接Model和View的桥梁。它会保存View的状态,并且根据外部事件来更新View的状态:

  1. 持有View所需要的应用状态;
  2. 控制View的流程;
  3. 根据状态show/hides/activates/deactivates/updates View或者View的某些部分。如controller可临时将攻击按钮Distable掉,因为此时攻击处于冷却状态,冷却状态一过,controller会re-enable这个按钮;
  4. load/Instantiate需要的assets,比如显示particles, 动态改变sprites等;
  5. 处理用户在View中触发的事件,比如用户按下了一个按钮;处理Model触发的事件,比如player获得了XP并触发了升级,所以controller就更新了View中的Level Number。

  这就是MVC模式中定义的三个基本元素。但在这个例子中,我们加入了另外一个中间层来进一步解耦NGUI的View实现,称之为:

ViewPresenter

  一个ViewPresenter位于View和Controller之间,作为一个接口存在,暴露了对于一个View来说是普适的操作集合,无论View本身是基于什么库来实现的(NGUI,UGUI等)。

  比如一个游戏中的按钮,一般来说都有以下功能集:

  1. 设置按钮label中的文字;
  2. 修改按钮的背景图;
  3. enable/disable用户输入;
  4. 当用户点击按钮时,进行Notify。

  这些都是与UI具体实现无关的操作,在任何一个UI toolkit中都能找到这些操作。ViewPresenter实现为一个MonoBehaviour被Attach到NGUI View的Prefab上,所以可以在Controller中通过GameObject.GetComponent来得到它来进行功能调用。由于ViewPresenter是游戏代码和UI代码的桥梁,所以它不能完全独立于屏幕渲染的底层实现。在这个例子中,ViewPresenter需要持有NGUI Widgets(比如UIButton,UILabel等)的引用,用来于它们进行交互。其实ViewPresenter实际上是一个适配器模式(Adapter pattern)的实现:  我们额外创建了定制的接口来对应用进行访问。这些引用必须在Inspector或者其他代码中进行设置。

  

  幸运的是,这个设置过程可以部分自动化,可以参看ViewPresenter.AutoPopulateDeclaredVidgets(),虽然ViewPresenter和某个特定的UI系统有耦合,但使用创建用于Controller的接口得到了一个好处:如果需要更换GUI库,只需要修改修改ViewPresenter的实现,而不需要修改ViewPresenter的接口以及controller的任何逻辑。

  之所以将其称之为ViewPresenter是因为它与Model-View-presenter模式中的Presenter有些类似,只不过Presenter可以访问Model,但ViewPresenter不可以。

  ViewPreseter可以持有一些player标识的状态,比如View存储了不同的颜色来提示heath point( 以健康度作为基准来提示满血,充裕,虚弱之类的),这些值可以暴露出来作为公共属性,运行在运行时通过inspector来进行实时修改。但无论如何,ViewPresenter不能持有应用程序逻辑的任何状态,而逻辑由controller管理,ViewPresenter根本不应该知道什么样的heath level是表示low。

  比如,如果扩展PlayerController来处理Hit points,可以增加一个方法来改变label的颜色,当处于low health的时候:

 1 public class PlayerController
 2 {   // ...
 3     void UpdateHitPointsUI()
 4     {
 5         if (Player.HasLowHitPoints)
 6         {
 7             HitPointsViewLabel.ShowLowHealthColor();
 8         }
 9         else
10         {
11             HitPointsViewLabel.ShowNormalHealthColor();
12         }
13     }
14
15 }

  如果你想创建一个非常特定或者复杂的UI,并在工程中进行重用的话,这个方法可能有些过度设计了。在这个Sample代码中,我们很轻松地进行了如此处理:controller只需要修改ViewPresenter中的一个UnityEngine.Color类型的属性。

Handling UI events

  NGUI提供了一个设计良好的时间系统,在任何定义了某事件hander的MonoBehaviour中都可以触发这个事件。这样就解耦了触发事件的MonoBehaviour和处理这个事件的MonoBehaviour。然后,强大的功能增加了结构混乱的机会,因为可以使用任何MonoBehaviour作为事件的handler,很随手的就把scene中的某个monoBehaviour拖放到inspector的handler上了,这样当创建一个包含了若干个控件的复杂View时,就容易得到一个难以track的依赖,这个依赖图的复杂度可以非常快速地增长。

  为了防止代码中混乱的蔓延,我们遵守了一个非常容易的原则:所有的View的UI事件只能被attatch到这个View的ViewPresenter来进行处理。ViewPresenter会捕获NGUI的事件,并Raise一个 .net的Event作为回应。其他的代码只订阅那个.net时间。这么做是因为需要将UI事件的具体实现与NGUI解耦,因为这样做我们使用代码中的事件,而不是inspector的事件。在我们的观点中,这是一个更安全的方法:可以很容易地在IDE中搜索处理这个Event的代码;而且更加类型安全:(如果你删除了一个处理这个Event的MonoBehavior,你只会发现控件在Play Mode中停止工作了), 可以允许设置Event上的各个参数。当然我们需要在View Presenter中封装NGUI的Event,但我们的使之自动化:看看这个代码ButtonViewPresenter.wireUIEvents()

创建复杂的View

  现在已经有一些模块可以支持建造了,通过组合来创建一些更复杂的View变得容易:由若干个UI prefab来组合成一个新的View, 并为这个组合出来的view创建一个新的ViewPresenter, 将子View中的ViewPresenter暴露出来,这样就可以在controller中进行访问了。

  

  

  这个组合出来的新ViewPresenter,可以在这里找到。

结语

  欢迎告知使用这种方法的感受,并欢迎告知你们在游戏UI开发中的独特方法,欢迎各种反馈。

  另外,如果不使用NGUI,而是使用Unity3D的GUI,那么实现ViewPresenter的OnGUI方法为Unity3D自带的GUI API将会是一个不错的体验。

时间: 2024-11-07 21:39:34

(架构)UI开发的MVC模式的相关文章

Unity3d中UI开发的MVC模式

原文:http://engineering.socialpoint.es/MVC-pattern-unity3d-ui.html 动机 和游戏开发的其他模块类似,UI一般需要通过多次迭代开发,直到用户体验近似OK.另外至关重要的是, 我们想尽快加速迭代的过程.使用MVC模式来进行设计,已经被业界证明了是可以解耦屏幕上的显示,如何控制用户的输入对显示的改变,以及如何根据应用的状态进行改变.MVC模式提供了以下好处: (1) 可以修改UI的外观,而不用修改一行代码 (2) 在不同的组件里面可以共享同

JDBC - 开发实例 - MVC模式

JDBC - 开发实例 - MVC模式  1. 在web.xml中配置连接数据库的信息 web.xml: <context-param> <param-name>server</param-name> //主机名 <param-value>localhost</param-value> </context-param> <context-param> <param-name>db</param-name&

简单理解前端web开发的MVC模式

随着前端Ajax兴起.前端开发工作进一步划分:js开发和ui页面制作.另外从整个前端项目的清晰明朗以可扩展性角度来看,MVC的应用也越来越必要,特别是对大的项目. 例如 需要给一个页面上的button注册一个onclick事件. 1.我们可以有如下最简洁的写法:(view和model control完全混合) <HTML> <HEAD> <TITLE> example </TITLE> </HEAD> <BODY> <input

移动开发中MVC模式和分层

MVC在界面开发中被奉为设计的典范,在移动开发中也是 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写. 它将业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑. 我刚接触ios,想通过ios的一些实例设计来理解MVC在ios中的应用. 1. IOS的view 对于工具化的图形界面设计,这个就应该是各种视图控件的设计,页面和控件

ios开发中MVC模式的理解

MVC是80年代出现的一种软件设计模式,是模型(model),视图(view)和控制(Controller)的缩写. 其中Model的主要功能包括业务逻辑的处理以及数据的访问,这是应用程序的主体部分. View的主要功能是用来跟用户进行交互,实现数据的收集和展示,视图是用户看到和直接操作的的界面,它只接受用户的操作. Controller的主要功能用来在视图和模型之间建立联系并控制数据的走向,控制器本身不输出任何内容和对数据做任何处理. 用个简单的例子来说明三者的关系 一个简单的计算器,它除了我

Swing程序最佳架构设计—以业务对象为中心的MVC模式(转)

前言: 我打算写一系列关于Swing程序开发的文章.这是由于最近我在做一个Swing产品的开发.长期做JavaEE程序,让我有些麻木了.Swing是设计模式的典范,是一件优雅的艺术品,是一件超越时代的产品! 有机会作Swing软件的开发,让我非常有感觉! 呵呵,希望有机会能够用Java3D编写软件,那种感觉一定更棒! Java和Swing都是杰作.我这个人对别人一向很挑剔的,能够得到我由衷地赞誉,可想而知它们有多优秀了.奇怪的是,它们居然一直都无法占领桌面市场.有人说这是技术的原因.我认为这应该

iOS里面MVC模式详解

MVC是IOS里面也是很多程序设计里面的一种设计模式,M是model,V是view,C是controller.MVC模式在ios开发里面可谓是用得淋漓尽致. 以下是对斯坦福大学ios开发里面MVC模式的一段话的翻译 主要的宗旨是把所有的对象分为3个阵营,model阵营,view阵营,或者是controller阵营 model(APP的目的) 举个例子,你要做一个打飞机的游戏,那么这个就是太空中这辆飞船的位置,什么机型,每个飞船有多少机枪,护甲有多少等等.这就是model所做的事,而飞机在屏幕上的

《从零开始学Swift》学习笔记(Day67)——Cocoa Touch设计模式及应用之MVC模式

原创文章,欢迎转载.转载请注明:关东升的博客 MVC(Model-View-Controller,模型-视图-控制器)模式是相当古老的设计模式之一,它最早出现在Smalltalk语言中.现在,很多计算机语言和架构都采用了MVC模式. MVC模式概述 MVC模式是一种复合设计模式,由"观察者"(Observer)模式."策略"(Strategy)模式和"合成"(Composite)模式等组成.MVC模式由3个部分组成,如图所示,这3个部分的作用如下

[转载]WIKI MVC模式

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). MVC模式最早由Trygve Reenskaug在1978年提出[1] ,是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件设计模式.MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能.除此之外,此