@rogeryi
2018-02-12T15:22:23.000000Z
字数 2602
阅读 5021
Blog
WebGL
WeiXin
这是个人关于微信小游戏系列文章的第一篇,在这系列文章里会描述 ——
为了做性能对比,一共移植了四个 Demo,这些 Demo 常用于浏览器自身的 Canvas/WebGL 性能测试,包括 GUIMark3 和 WebGL Aquarium。
移植的代码已经上传到 GitHub,读者可以自行下载运行测试。
上图从左至右分别是:
总的来说移植并不算太困难,WebGL Aquarium 本身包含了大量的 DOM 元素和利用 DOM 来加载脚本和图片,所以花的时间比较长,其它页面只有很少 DOM 元素和 DOM 操作的,移植起来还是很简单,当然这里只包括主体内容的渲染部分,其它如 HUD,输入事件处理,音频播放等并没有包括在内,如果原来的页面是使用 DOM 做 HUD 的,可能会比较麻烦。另外,如果先开发小游戏再移植到浏览器上运行,理论上应该会更简单。
移植过程中自己写了一些方便双端运行的适配代码(wxhelper.js),示例如下。
let WX_GAME_ENV = typeof wx !== 'undefined';
let WX_GAME_DEVTOOLS = false;
let SystemInfo = null;
if (WX_GAME_ENV) {
SystemInfo = wx.getSystemInfoSync();
if (SystemInfo.platform == "devtools")
WX_GAME_DEVTOOLS = true;
}
function Now() {
if (WX_GAME_ENV) {
if (WX_GAME_DEVTOOLS)
return wx.getPerformance().now();
else
return wx.getPerformance().now() / 1000;
} else {
return performance.now();
}
}
注意规范里面的 performance.now() 是返回微秒精度,但是以毫秒为单位的浮点数值,而小游戏的 API 定义是返回微秒为单位,并且实机环境跟 DevTools 环境还不一样,DevTools 环境估计就是调用浏览器本身的 API,返回的是毫秒为单位的值,这算是踩到的第一个坑,上面的适配代码统一返回毫秒单位。
function CreateImage() {
if (WX_GAME_ENV) {
return wx.createImage();
} else {
return new Image();
}
}
let MainCanvas = null;
function GetMainCanvas(domId) {
function GetMainCanvasImpl(domId) {
if (WX_GAME_ENV) {
if (window != null && window.canvas != null)
return window.canvas;
else
return wx.createCanvas();
} else {
return document.getElementById(domId);
}
}
if (MainCanvas != null)
return MainCanvas;
MainCanvas = GetMainCanvasImpl(domId);
return MainCanvas;
}
在小游戏环境中,只允许有一个占据全屏幕的主 Canvas,如果使用微信提供的 Adapter,这个 Canvas 会事先创建并通过 window.canvas 引用。
在浏览器环境里面,window 是全局对象,而在小游戏环境里面 GameObject 才是全局对象,下面的代码演示了如何在小游戏环境里面模拟 window 全局对象,我们可以在 GameGlobal 下创建一个 window 属性并让它引用自身。
if (typeof window !== 'undefined') {
window.wxhelper = wxhelper;
} else if (typeof GameGlobal !== 'undefined') {
GameGlobal.wxhelper = wxhelper;
GameGlobal.window = GameGlobal;
window.top = GameGlobal.parent = window;
} else {
console.log("Cannot find any global object!");
}
因为在小游戏环境里面,每个 JavaScript 文件都是一个模块,里面包含的方法和变量不会自动包括在全局对象下面,如果我们需要跟浏览器保存一致的行为,就需要将对外的 API 显式地导出到全局变量。比如:
// Vector3D.js
window.Vector3D = function Vector3D(x, y, z){
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
}
// Boid.js
Boid.ZERO = new Vector3D(0, 0, 0);
上面的示例代码可以把 Vector3D 在浏览器和小游戏环境都导出到全局对象下面,虽然在浏览器环境下是多余的。当浏览器对 ES6 Module 的支持完善后,理论上我们可以使用统一的模块管理方式来处理浏览器和小游戏环境的模块 API 的导出/导入的问题。