Unity中GUI的设计
发表于2016-06-16
作者:paladin career
没少听人诟病Unity的GUI系统,焦点主要集中在对它immediate风格API的吐槽。我也曾对这种风格的GUI接口感到不适。
游戏因平台不同移植后最容易让人觉得没有原版舒服的是GUI和操作方式两大系统。针对不同平台的键鼠、手柄、触摸屏等不同操作设备及不同分辨率想完全用一套方案解决所有问题是不可能的。比如对于大屏幕电脑可以把GUI元素做的非常细小而不会让玩家看不清,并且可以通过快捷键或鼠标精确点击准确执行操作,但蚊子腿大小的GUI显然不适合放到巴掌大的手机触摸屏上。
游戏的渲染、动画、物理、粒子、后期特效等均已成熟多年,不同平台间程序部分差异不大,区别只是针对不同平台机能做资源上的限制,而GUI和目标平台屏幕尺寸,操作方式及游戏设计大为相关,比如一些建造类SLG玩家主要精力就集中在GUI上,而ACT游戏中的GUI只是简单的提供必要信息。将通用的部分形成模式,不通用的留有灵活底层接口允许用户自行定制,这应该是Unity这种通用引擎的设计原则。因此Unity中其它部分看上去都很有条理浑然一体,而GUI显得过于“原始”就不奇怪了。在Unity中,GUI系统是必不可少但很可能是吃力不讨好的模块,不知其开发团队是打算今后再做适当包装还是全权把问题留给第三方插件解决。
幸运的是在Unity中自行扩展GUI系统是很容易的,我发现immediate风格GUI做数据驱动很方便,详情可参阅最后参考引文。那么对GUI的定制就可分三部分来设计:配置文件格式,运行时数据结构,运行时数据结构与底层GUI API的关联,这么一划分貌似又跑到MVC的老生常谈上了。
如我曾说,为了实现这套GUI我先得需要一套符合我对其功能和语法要求的脚本系统,便是L#,它衍生出的DSL便可做为配置文件。格式形如:
它表示一个如下布局:
每个GUI元素以如下格式呈现:(类型 属性列表 [事件回调] 子元素),某些类型不含有事件回调。每个元素都可含有N个子元素,整个布局是一个树形结构。
对于运行时数据结构和其与底层GUI API的关联并没什么特别需要讲的,只是典型的composite模式在OO中的应用。也许值得一提的是利用C#的分布类将可复用的运行时数据结构和关联部分分离开,平台/渲染底层相关API分到方便移植的单独文件中。GUI事件的回调即可以用L#提供的语法和布局写在一起,也可单独在C#代码中做处理。Unity文档中说GUI很耗效率尽量不要大量使用,以我对它的理解,效率更多的是耗在像素填充率上,或者说GUI覆盖的面积越大帧数掉的越凶,针对这点最好从游戏设计角度平衡,主场景3D元素较多时尽量精简GUI,一些物品、属性之类要显示大量数据的大窗口出现时,最好让它们覆盖整个屏幕不再渲染主场景,在移动平台上尤其重要。
这种方式损失了一点加载时的效率和运行时空间,不过考量GUI的规模不会太大以及灵活性的必要性,这点代价是值得的。L#脚本可放在独立文件夹中,也可放到资源包中,可通过如下代码尝试着加载:
依C#和L#的表达能力,想做GUI动画的话,配置也不麻烦。.NET的反射系统非常出色,包含绝大部分常用功能的编辑器可在500行C#代码内搞定。
参考: