浅谈游戏UI架构

界面(User Interface)层在游戏中的定位就是数据与用户之间的中间层,它承载着两个基本任务,一是把游戏中的各种数据展示给用户,二是把用户的操作转化成指令调用逻辑层的功能。通常的游戏引擎都会自带UI功能,并且集成易用的编辑器,甚至有专门的UI中间键,例如ScaleForm,可以提供非常强大的UI服务。我们更多的关注是界面的设计,也就是我们常说的交互是否舒适,界面是否美观。但这篇文章要讲的并不是这方面的问题,而是讨论在程序的角度,基于Win32消息机制如何实现一个UI界面层。

首先我们通过一个简单的面板看看单独一个界面的结构:

ui01

单独的一个面板,我们称为一个Frame或者一个Panel,它是由许多子窗口(Windows)或子控件(Item)组成。上面这个简单的面板就包括一个Text控件显示“请输入捐献金额”, 两个Button子窗口“确定”“取消”, 一左一右微调数值的Button,还有一个获得用户输入的Edit框。值得注意的是,Button(子窗口)下还可以有Item(子控件),例如Button下的“确定”,“取消”Text。

对面板的结构有了一个大概的了解后,接着讨论这个面板如何的工作,也就是界面的逻辑。在魔兽世界以前,大部分界面逻辑都是C/C++层面实现的,但伴随魔兽世界崛起而崛起的Lua脚本语言改变了这一切,用脚本来写界面逻辑成为了新的趋势。这样做是有很多好处。例如脚本的实时解析特性使得频繁改动的UI界面可以快速重载观察改动的结果,而良好的交互接口控制可以保证在脚本层面的BUG只会使得这个界面工作不正常,而不会影响客户端甚至出现宕机。不过这样做也有弊端,作为网游如果向脚本层面导出许多功能性接口,做外挂的只需要攻破脚本加载处理的这一点,就能用自己的脚本完成几乎全部操作了。

对于这种结构的UI面板适合用什么格式的文件保存呢?也就是说这采用什么格式的配置文件呢?普遍的做法是采用xml格式文件,因为xml格式文件本身能够直观表示这种树结构格式,并且每个节点可以具有自己的属性。无论是查询各节点的层地关系还是节点的内容都很快捷。而且现有许多xml的开源库可以提供使用,集成到自己游戏中和UI编辑器中也很方便。另外一种做法是用lua的table格式表示,如果本身就采用lua脚本写UI逻辑的话,这样做能够在数据读取时有天然的优势,不过麻烦一点的是在编辑器中要生成lua文件格式的配置文件时要自己花一点功夫。

如果采用lua脚本写UI逻辑的话,就要考虑两个层面如何实现交互了。C/C++层面向脚本层导出界面对象后,lua可以直接操作界面对象,完成脚本到C/C++层面的交互。(具体参考文章:Lua创建使用C++对象)而C/C++层面到脚本的交互则是通过模仿Win32消息机制来实现的。例如一个鼠标左键点击事件产生,通过Win32消息机制由WndProc函数获知并查询到最终作用于哪一个窗体或控件,就调用约定好的脚本接口,并传参告诉脚本具体是哪一个窗体或控件接受这个消息。

这里引申出另外一个问题,就是如何管理游戏中的各个面板。首先在整个UI层面上存在那么多面板,他们之间应该是有区分层次关系的,例如背包,地图等面板,一旦打开总是希望在最上层的。而另外一些面板,例如技能栏,小地图等,总是希望他们在较低的层次,不要覆盖任何面板。出于这样的考虑我们首先会把所有面板分在几个不同的容器中。假设我们分层低、中、高三个容器,渲染时按照低、中、高的顺序渲染,而查询时按照高、中、低的顺序查询,就可以实现大体的分层结构了。

而在同一个容器(层次)中的面板如何实现层次结构呢?这里提供一个方案是用双向链表管理。把同一层次的面板用双向链表管理起来,每次渲染时从链表头向尾遍历并依次渲染,而每次查询时从链表尾向头遍历依次查询,这样在链表头的面板就代表在同一层次中暂时处在较低位置的面板,它总是会被链表后面的面板覆盖(如果他们之间有重叠),而且链表中较后的面板则会有限选中。在选中(激活)一个面板后通过把它移动到链表的最末端来提升它成为当前层次下最高的面板。

在UI模块中当然少不了的是各基础功能的封装,例如读各种配置表读写、声音控制、动画控制等等。值得一提的是字符串管理,在整个UI层面使用到的字符串应该有一个统一的配置文件,然后有相应的管理器可以取得并使用这些字符串。这样做有很多好处,第一就是方便字符串的查找更新,从而索引出所有使用该字符串的面板。第二个好处是方便做本地化的处理,如果游戏要出其他国家地区的版本,只要翻译字符串配置文件即可,而不用担心代码中夹杂中文字符串引起的各种问题。

最后少不了的部分就是UI编辑器了,不过UI编辑器又具有一定的复杂性,展开讲的话又是另外一篇文章了,在此掠过了。

水平有限,能力有限,文采有限,导致这篇文章写得我好纠结,暂时只能写这么多了,以后再陆续添加修改吧。

临表涕零,不知所言,囧

Bookmark the permalink.

发表评论

邮箱地址不会被公开。