游戏 UI 模块的选择
在游戏(包括引擎)开发的过程中,谈及 UI 模块,通常所指有二:
- 开发工具所用到的 UI 。
- 游戏本身所用到的 UI 。
这两者很多时候都是共用的一个模块,比如之前的 Unity 就直接把引擎开发用的 UI 模块扔给开发者开发游戏使用。但很快,开发者就发现,适合工具开发的 UI 模块,在做游戏时就不那么顺手了。所以就有了第三方 UI 插件的流行,以至于最后又倒逼 Unity 官方重新制作游戏 UI 模块。
开发工具面临的需求和游戏场景面临的需求很不一样:
开发工具需要的时候更好的将内部数据以可视化方式呈现出来,供用户浏览和修改,以适应数据驱动的开发。UI 的呈现需要的一致性,风格统一有利于减少学习成本,同时需要清晰的表达复杂的数据结构。有时还需要将内部数据的变化过程同步的动态呈现,给开发者更直观的感受。
游戏 UI 是游戏过程的情感体验的一部分,外观和交互需要根据游戏设计专门化。它往往并不需要表达游戏内部复杂的数据结构,而是将那些数据以额外面对玩家的形式展现出来。玩家通过界面下达的指令也并非直接对数据的修改,而是以指令流的形式传递过去。另外,HUD 也是很大的一个部分,和 UI 对话框在设计上也有很大的不同。
他们两者之间在技术上的共性其实很小,针对这些共性的技术实现可能也只有几百到上千行代码的规模,远少于差异部分需要的代码量。我比较倾向于把这两个东西分开实现。
关于工具所用的 UI 模块的选择,我的开发生涯中早期使用过 MFC ,.net ,wxwidgets,Qt 。近两年做引擎开发时先选择的 iup ,后来转向 dear imgui 。这里面的选择无非是 Retained mode 和 Immediate mode 之争。在这个问题上,我目前比较赞成 im mode ,认同这篇 blog 的观点 。另外加一句,我觉得 stateless 模式可以减少 bug 。
在这个问题上,今天不想展开谈,这次主要说说游戏 ui 。
为游戏写 UI 模块,我自己动手干过两次,都是十多年前的事情。最早是为大话西游写的,后来因为学习 C++ 的新语法又重写过一版,但没有用在自己开发的游戏中(送给朋友,他倒是用在游戏产品里了)。在此之后,我的开发思路改变,不再追求自己实现,而是考察成熟方案。所以如非必要,就不再新起山头了。
最近做游戏引擎开发,又重新考虑该选择一个怎样的游戏 UI 模块。
首先考虑的是对已经在用的 imgui 做一番改造。试过 Nuklear 和 Dear imgui ,改造过程都不太满意。Dear imgui 在做工具开发上已经非常成熟,但项目已经明确了,聚焦于工具开发而不会考虑游戏 UI ,我稍微动了下手,觉得不应该背道而驰。
在做手机游戏开发的初期(陌陌争霸),我也尝试过自己实现一个简单的 IM mode 的 UI 模块,勉强够用,但似乎也不太好用。对游戏开发不太友好。后来就转向 Retained mode 的库。
前些年 CEGUI 非常流行,这两年似乎不那么活跃了。最近两年也涌现过几个类似的项目,看了一下感觉还是太复杂。这些复杂的项目似乎都奔着工具开发的领域去做,其实我是用不着的,犯不着为了不需要的需求增加项目的复杂度。
UI 模块本质上,实现需要解决的仅仅是一组矩形如何布局的问题。这个问题并不复杂,而且布局问题也有非常简洁的开源实现,不需要从头动手。实现了布局后,把控件顺次绘制出来即可。至于优化,可以探讨的方面很多,但可以列为单独任务。
而从设计角度,就是如何去描述这些控件,可以方便的翻译成布局信息。
最近一段时间最打动我的是 Paradox 的游戏引擎。虽然是闭源的,但因为给群星做汉化 Mod 的缘故,我仔细研究了它。它的 UI 系统是完全可以 Mod 的,全部是文本呈现。给了我许多启发。
首先是 UI 的结构和呈现分离。在这个引擎中,区分了 .gui 和 .gfx 两类文件(其实文件格式是统一的,仅仅是后缀不同)。.gui 描述的是 UI 的结构,可以看成是把 UI 看作是树状层级的一个个矩形区域,描述出每个区域的功能。而这些矩形区域到底如何呈现,是用静态图片,还是有动画效果,又或者直接用线条绘制。以及一些和逻辑无关的表现行为,例如鼠标悬浮时需要有一些特别效果,等等。都单另放在一个 .gfx 文件中描述。这就有点像 html 和 css 的分离,但更简洁一些。
我想找找有没有类似设计的开源 UI 库,没有找到。其实自己实现也不算复杂,核心仅在于如何设计这个数据表达的形式,而这个从 Paradox 的游戏文件中已经可以找到完整的参考了。我前段时间自己设计了一版。但在设计的同时,也在继续寻找潜在可用的开源方案。
除了这些从头设计的开源 UI 库以外,这些年还流行另一种解决方案。那就是借用成熟的 UI 表达形式,为游戏环境重新实现。这些成熟的 UI 方案无非两种:flash 或 HTML/CSS 。这类方案的最大优势就是,开发 UI 的工具成熟,开发者不需要学习新概念。而对于 UI 怎样描述这方面,成熟的文件格式可以少踩很多坑。而另起山头自己设计的格式,虽然更简洁,或许能贴近需求,但难免在需求迭代之后,发现之前的失误。
这其中最为有名的是 Scaleform ,是对 Flash 的重新实现。星际 2 就用了它。不过这是个商业中间件,且已经停止开发。开源的类似品也有一些,不太成熟。考虑到 Flash 本身已经日薄西山,我也不想考虑这个系列。
HTML/CSS 方案最近几年非常流行。最有名的是基于开源 webkit 的各种改造。例如吃鸡就是用的这样的方案。但 webkit 还是过于复杂了,这种复杂性最终的反应就是用于游戏后,性能有问题,且不太好优化。吃鸡的团队就做了大量的改造,可以在某些特定场景下,提升一两个数量级的性能。可见 webkit 直接用于游戏引擎复杂度造成的潜在问题。
另外,Valve2 的 Source 2 引擎中提供的 UI 模块 Panorama UI 也是基于 HTML/CSS 的。这是一个商业闭源产品,但可以找到开源的类似品。很多年前,我关注过一个叫 LibRocket 的库,那个时候还不太完善,后来就停止维护了。最近我发现有人在它的基础上 fork 出来一个叫 RmlUI 的项目,我十分喜欢。裁剪掉了许多不必要的功能,代码做了整理以及一定的优化。明显其设计目的就是嵌入到其它游戏引擎中使用。
昨天我阅读了文档,玩了一下。发现一些 mingw 编译的小问题,顺手提了 PR 。这个项目非常活跃,直到昨天还有新的提交。我选择开源项目的首要考察因素就是维护者的活跃程度。所以暂时会把这个作为重点备选项目,尝试往我们正在开发的引擎中集成。
关于集成,一般的 UI 库都会提供一个抽象层让你对接渲染和系统输入消息。而渲染部分最难的是两个问题,一是如何保证性能,二是字体的管理。
由于大多数成熟的开源项目都是西方人领头的,对汉字这种字符量巨大的字符集没有过多的考虑。把动态烘培字模,限制使用贴图数量的方案优先级都排的比较低。如果不下一番功夫,一般就用巨大的贴图,烘培上所有的汉字了事。例如 imgui 就是这么干的,动态的字体贴图管理这个特性已经在 todo list 里停留了很久了,好像也看不到时间表。
如果游戏只使用一两种字体倒无所谓,想让字体丰富一些,这不是个办法。所以我前段时间静下心好好设计并实现了字体渲染中贴图管理的模块。改天我再写一篇 blog 记录一下。
Comments
Posted by: great90 | (16) March 25, 2021 11:16 AM
Posted by: 海的味道 | (15) July 23, 2020 02:37 PM
Posted by: kenshin | (14) July 23, 2020 05:05 AM
Posted by: operali | (13) July 15, 2020 02:58 AM
Posted by: foxerzhou | (12) July 13, 2020 01:55 PM
Posted by: Cloud | (11) July 13, 2020 11:34 AM
Posted by: foxerzhou | (10) July 12, 2020 05:16 PM
Posted by: foxerzhou | (9) July 12, 2020 03:31 PM
Posted by: 老九 | (8) July 12, 2020 12:27 PM
Posted by: 淘花 | (7) July 11, 2020 06:29 PM
Posted by: 谷主 | (6) July 11, 2020 09:44 AM
Posted by: 锣鼓熏天 | (5) July 10, 2020 09:47 AM
Posted by: yongxinchang | (4) July 10, 2020 08:33 AM
Posted by: 听星 | (3) July 9, 2020 08:26 PM
Posted by: pig09 | (2) July 9, 2020 06:18 PM
Posted by: Zwinger | (1) July 9, 2020 05:57 PM