修改 godot 导出的 html 页面中的 index.asm.js 的位置

godot / html

godot 是一个很适合独立游戏的开源游戏引擎,而且跨平台,你可以很方便地将自己的游戏导出到 windows、osx、甚至是网页,不过导出的网页加载时间很长,我们来看一下有没有办法缩短加载的时间

1 问题

1.1 godot 2

1.1.1 确定瓶颈

我们来观察一下,godot 导出的 html 网页:

可以看到最大的文件为 `index.asm.js`,27m 多,毫无疑问这就是我们的瓶颈。这个文件应该是 godot 引擎的 web 虚拟机,不过我们现在不会去深究这些文件分别是什么内容什么作用,那会是另一个话题。

1.1.2 index.asm.js 的引用

我们都知道网页一般以 index.html 为入口,我们打开 index.html 来寻找 index.asm.js 的加载方式,在 index.html 的尾部我们可以看到这样一段脚本:

(function() {
  var script = document.createElement('script');
  script.src = "index.asm.js";
  script.onload = function() {
    setTimeout(function() {
      (function() {
	var memoryInitializer = 'index.mem';
	if (typeof Module.locateFile === 'function') {
	  memoryInitializer = Module.locateFile(memoryInitializer);
	} else if (Module.memoryInitializerPrefixURL) {
	  memoryInitializer = Module.memoryInitializerPrefixURL + memoryInitializer;
	}
	var xhr = Module.memoryInitializerRequest = new XMLHttpRequest();
	xhr.open('GET', memoryInitializer, true);
	xhr.responseType = 'arraybuffer';
	xhr.send(null);
      })();

    var script = document.createElement('script');
    script.src = "index.js";
    document.body.appendChild(script);
    }, 1); // delaying even 1ms is enough to allow compilation memory to be reclaimed
  };
  document.body.appendChild(script);
})();

所以 index.asm.js 是在网页加载后,以脚本的形式载入的,如果玩家是首次访问我们的游戏,浏览器在开始我们的游戏之前,需要先把 27m 的虚拟机完整下载到本地。这里可以顺带一提,如果你希望把你的游戏部署到 github page,那么你可能要学会使用 git push 这些更专业的工具,因为 github 只允许浏览器上传 25m 以下的文件,所以 godot 虚拟机无法透过浏览器上传

1.2 godot 3

godot 3 的 html 标准模版的虚拟机脚本为 index.wasm,另外有一个 index.js 的外敷脚本, index.js 会去调用 index.wasm,所以如果把 index.js 和 index.wasm 部署到其他地址会有一个跨站请求的问题,这个我们放到以后讨论

2 实验

优化网页文件加载我们首先想到的就是 cdn,即把我们的文件交给 cdn 运营商,这样玩家可以就近下载文件,提高访问速度。那么我们能不能从另一个位置加载 index.asm.js 呢?我们可以试一下,我们在本地打开一个 http 服务器来作为我们网页游戏的入口,同时在另一个服务器提供 index.asm.js 文件

2.1 index.asm.js 转移

我把 index.asm.js 上传到了 tricks.one 这里(已删除),另外也传了一份到 firebase 这里,当然你也可以在本地做实验,参考下一步

2.2 本地游戏入口

在 osx 上,由于 python 是默认安装的,所以你可以进入到游戏导出目录,执行以下命令来开启我们的入口服务器,由于篇幅问题,我们也先不去讨论如何在其他平台创建一个监听本地目录的本地 web 服务器

python -m SimpleHTTPServer 8000

这样我们的游戏入口就是 localhost:8000,对于想要本地部署 index.asm.js 的朋友,你可以把它单独拷贝到另一个目录,再用本步骤的方法开启另一个 http 服务器,比如,如果你又打开了一个 8001 端口的服务器,那么你的 index.asm.js 的新地址就是 http://localhost:8001/index.asm.js

2.3 修改 index.asm.js 的地址

我们把之前脚本中的这行

script.src = "index.asm.js";

修改为 firebase 的地址

script.src = "https://firebasestorage.googleapis.com/v0/b/playeriam-00.appspot.com/o/index.asm.js?alt=media&token=4a5b63d6-c840-4558-87ec-0a1cb7cdd52a";

2.4 测试

好了,我们可以在 chrome 的开发者模式下访问 localhost:8000, 观察一下 index.asm.js 如何加载

我们可以看到,chrome 是从 firebase 下载了 index.asm.js,耗时两分多钟,接下来,我们试一下放在 tricks.one 的地址,看看会是什么结果

时间缩短到 40 秒,而且传输只有 7.2 M,这是因为 tricks.one 启用了 gzip 传输, web 服务器如何开启 gzip 传输,这里也不会详细展开

3 结论

当然这里不是在比较 firebase 和 tricks.one 的网速,孰优孰劣没有任何意义,这里只是证明,godot 的虚拟机脚本是可以通过其他地址来优化网速,而不需要部署在你的游戏服务器上,如果你的游戏瓶颈也在于加载虚拟机脚本,那么你也可以考虑把虚拟机脚本部署到用户访问更快的地址