本文要点
尽管 WebAssemly 还在积极开发当中,并且仍然比较小众,但这项技术本身已经足够成熟,足以用来将诸如桌面平台游戏编辑器之类的复杂应用程序移植到 Web 上。
将桌面平台软件移植到 WebAssembly 的好处包括:移植的软件可以跨平台交付,可能会吸引更多的目标受众等。
与原生桌面应用程序相比,前端框架和工具可简化 UI 开发并缩短反馈周期。
Web 还带来了新的可能性,例如深层链接以及丰富的 UI 生态系统的帮助,这些可能会极大改善用户体验。
开发人员必须特别注意内存管理、测试和键盘操作,以减少移植过程中出现的问题。
谷歌软件工程师和GDevelop游戏编辑器的创建者Florian Rival,最近在布拉格举办的ReactiveConf 2019 大会上发表了演讲。他在演讲中讨论了将一款原生桌面平台游戏编辑器通过WebAssembly移植到浏览器中的经验教训。
InfoQ 采访了 Rival,询问了他在这一过程中所遇到的技术挑战、从移植中获得的收益,以及开发人员在考虑使用 WebAssembly 移植桌面应用程序时可以参考的技巧。
InfoQ:首先介绍一下GDevelop吧。它的目标受众是哪些?GDevelop 对于自身受众的价值主张是什么?它为游戏创作者解决了哪些痛点?
Florian Rival:GDevelop 的理念是让初学者到经验丰富的游戏开发人员都可以创作游戏。GDevelop 允许你使用视觉事件(由条件和动作组成)来创建游戏逻辑。你还可以通过组合预定义和可自定义的行为来构建游戏对象。
这样以来就消除了学习编程语言语法和习语这一入门门槛。对于非开发人员来说,这是一种通过直观界面快速上手并开始创作的方法。很多人喜欢沙盒游戏。GDevelop 是一个沙盒——但是你用它可以做的事情是无限的。
对于经验丰富的游戏开发人员来说,你将获得一个集成的开发环境,可以使游戏的创建工作非常快速且高效(事件被转换为“真实”代码),并且可扩展。
最后,对于团队而言,这是一种使所有人(开发人员、艺术家、项目经理、游戏设计师……)围绕一个共同界面协作,并培养所有人创造力的一种方法。
当然,与游戏创作相关的培训和讲习班使用 GDevelop 与学生互动也是好处多多的。只需几秒钟时间,你就可以开始探索游戏底层,通过事件来教学编程概念,甚至可以进一步创建扩展。
InfoQ:是什么促使你将游戏编辑器移植到 WebAssembly 的?移植到 Web 会给你带来哪些在桌面平台无法或很难获得的好处?
Rival:这款编辑器以前是原生 C++桌面应用程序。它正常工作的时候还可以,不好不坏。但它在某些方面开始出了问题:对 macOS 和 Linux 的支持很难正确实现(UI 工具包中频繁出现崩溃),并且在 UI 上的工作进展相当缓慢(因为“做一项更改>编译>运行>重复”这套循环流程太费时间了),还只能使用过时的 UI 组件。这些也会给新的贡献者提高门槛。
在工作中使用 React 相当长一段时间(以及使用 React Native 等框架制作移动应用程序)之后,我知道了组件范式(和“UI 作为状态的函数”)是制作接口时的一种非常强大且可扩展的方法。
当时我很怀念这种开发速度及其在原生侧实现的出色架构!
总而言之,我开始思考 Web 技术是否能用来帮助开发出更好的应用程序。
至此,我开始转向 WebAssembly(使用Emscripten),这是将现有的大型 C++代码库移植到浏览器(以及像 Node.js 这样的 JS 引擎)的便捷方法。
我的想法是将 WebAssembly 用作核心,将 JavaScript + React(或另一个前端框架)用作接口,之后我就会拥有一个可移植到几乎所有现有平台上的应用程序,可在各种设备上一致地工作。我还可以解锁一些做梦都想不到的新东西,比如说你可以在几秒钟内启动应用并开始尝试它,或者在手机和平板电脑上运行一模一样的应用。
InfoQ:在谈到移植这个话题时,你在演讲中提到了以下架构:
对于一款游戏编辑器来说,我知道有两个关键模块,一个是丰富的交互式 UI,用于处理编辑这部分工作;另一个是与规则引擎和游戏代码生成相关的,更具事务性的算法部分。移植到 WebAssembly 时这些模块如何转换为新的架构?
Rival:移植到 WebAssembly 的过程中,首先是在原始 C++代码库中明确区分应用程序的核心(“业务逻辑”,在我的情况下指的是描述游戏结构的各种类,以及操作这些结构的各种类,还有游戏代码生成部分)与 UI 部分。编译到 WebAssembly 的就是这一“核心”部分——除了围绕文件系统的一些抽象外,编译后的内容几乎没有任何变化。
这一代码库能够跑在浏览器中之后,下一步是编写绑定来将部分代码暴露给 JavaScript。(所使用的工具取决于你的语言。我这里针对的是 C++和 Emscripten,选择用WebIDL来编写绑定)。
然后我终于可以用 React 编写一个新接口来使用这些代码了——就像写了一个新库一样。
InfoQ:你遇到的主要挑战有哪些?对于寻求通过 WebAssembly,将现有桌面软件用类似的方式移植到 Web 上的开发人员,你有什么建议?
Rival:熟悉现有代码库当然是一个巨大的优势。最好看看现有的原生代码是怎样工作的,如果要移植的是库,那就看看它是怎样被使用的。
内存管理是一项很大的挑战。虽然 JavaScript 对象是可以垃圾回收的,但你在“ WebAssembly 世界”中创建的对象却并非如此。因此如果你调用一个函数来创建存储在 WebAssembly 内存中的对象,然后在 JavaScript 中删除对该对象的引用,则只会导致内存泄漏。一定要删除你创建的内容——直到 Emscripten/wasm 有了一些垃圾回收器为止。
另一项挑战是正确使用 WebAssembly 编译库。如果你传递了错误类型的参数,或尝试从 JavaScript 调用一个对象的方法,可是这个对象已经在 C++代码里从内存中删除了,那么你就会身处未定义行为的未知领域(在 C++中),并且很可能在 wasm 模块内遇到“崩溃”。而且你不太可能从中恢复过来(不过 JavaScript 可能会更宽容一些,并且如果应用程序的非关键部分未捕获到异常,你也有机会让应用继续工作下去)。
JavaScript 中的类型(使用 Flow 和 Typescript)可能会有所帮助——不幸的是,我还没找到一种将 C++类型自动转换为 Flow 或 Typescript 类型的方法。
调试也可能会更困难。我建议为你的 wasm 库准备一个全面的测试集,仔细检查一切是否正常运行。如果你要将实现转移到另一种语言上,这会很有用途,并且也会是一份有关如何正确使用库的实用文档。
InfoQ:你最后是如何打包/分发 Web 应用程序的,为什么这样做?
Rival:因为这款应用的一项重要特性就是可以访问文件系统,并且人们希望能够脱机处理游戏,因此我将整个应用程序打包为可以在 Windows/macOS/Linux 上运行的 Electron 应用。它在所有平台上都运行得很好。尽管 Electron 的打包尺寸可能有点偏大,但我觉得还可以接受,因为用户下载的是一款完整的游戏编辑器。
话虽如此,但制作一款可独立运行的 Web 应用也是很必要的,这样以来应用就可以在线试用和使用了。相比我正在逐渐放弃的桌面版应用,Web 平台提供了一些等效的 API,或者需要重新寻找一些替代方案,也存在一些局限。
InfoQ:要做出一个最小可行的移植版编辑器(在 UI 和性能方面)要花多长时间?这个过程的难度如何?
Rival:这样做的时候肯定会有起伏。在完成可以在浏览器内部运行的核心版本后,我和几个朋友就开始为这款应用程序开发新的基于 Web 的 UI。我们只花了几周的时间就完成了工作。后来我们又从头重新开始整个过程——但是我们的原型证明了浏览器可以支持这款应用,并能正确运行它。
我确实得在某些时候重新设计绑定,并且升级到 Emscripten 的较新版本并不总是那么容易。现在我还没更新到最新版本上:)(但这部分工作需要的只是一些时间)。
当然这并不容易,但是这项工作一开始粗糙的样子正在逐渐改观(以前 Emscripten 的编译时间非常久,现在就不再是问题了)。
InfoQ:我注意到你提到了移植到 Web 的应用程序比原来的原生应用表现更好,这让我很感兴趣。能否详细介绍一下 Web 应用程序带来的改进细节?
Rival:有趣的是,移植版的启动时间有所缩短,我认为还有提升的空间。
我最满意的是建立这种链接的可能性。
点一下那里,然后在几秒钟内(具体取决于你的联网速度和设备性能),你就有了一款正常工作的游戏编辑器;你可以用它修改游戏、运行预览并开始探究底层细节。在过去想要做到这一点根本就是不可思议的。
从开发体验来看,应用的 C++部分处理起来和之前几乎没区别,但是 UI 的开发确实更快。诸如Storybook之类的工具可以用来独立地开发应用程序的各个组件——开发时甚至无需运行应用程序本身。开发 UI 时,我们的反馈循环从几分钟缩短到了几秒钟。Storybook 还可以可视化应用程序组件的异常状态(例如错误状态),并在更改后使你能确信一切正常。我认为它们是非自动化的,但仍然是非常有用的测试用例。
不同 Web 浏览器的各种怪癖是不可避免的,但是与我在 C++中尝试过的较老的跨平台 UI 工具包相比,总体而言在 Web 端实现多平台支持要容易得多。
虽然应用界面不是由原生小部件组成的,但我们仍然可以使用其中一些部件(特别是如果你使用的是 Electron,它可以让你利用原生上下文菜单和原生菜单栏等功能)。
使用 React 带来的干净的、面向组件的架构在模块化和保持代码库整洁方面有着巨大的优势——这进一步提升了开发效率。最后这将转化为更好的界面——因为你的整洁架构将转化为精心设计的,具备一致性的组件。例如,组件的响应更容易保持一致。很难想象使用旧界面该如何创建响应式 UI。
InfoQ:就编辑器的未来功能而言,你有哪些展望?
Rival:内容数都数不过来!社区总是在提议新的事物:)界面总是在不断改进,以在直观性和完整性之间取得适当的平衡。我想围绕软件创建一个更完整的生态系统和社区——我又想出了很多主意,可以让几乎任何人都能更轻松,更迅速地制作游戏。可以在 WebAssembly 中重做一些影响性能的关键组件,或者开发一些带来新功能的扩展,从而改进游戏引擎!
GDevelop 是一款开源的,跨平台的游戏引擎,可通过其GitHub存储库获取。
ReactiveConf 是面向开发人员的大会,每年举办一次,其主题涉及软件开发的最新技术和趋势。ReactiveConf 2019 大会于 10 月 30 日至 11 月 1 日举办,是 ReactiveConf 的第五届会议。
受访者介绍
Florian Rival 是谷歌的软件工程师。他是 GDevelop(基于 WebAssembly 和 JavaScript 的开源游戏制作软件)的作者。他还制作了 Lil BUB 的《Hello Earth》(一款由网红猫为主角的 8 位游戏),支持台式机和移动设备,并 100%使用 GDevelop 制作。总的来说,他喜欢用创新方法来突破我们在应用程序、移动应用和游戏中可做事情的极限。
原文链接:
Porting a Desktop Game Editor to the Browser With WebAssembly
评论