更新: 我们对这个开源 Doom 的移植是否尊重其使用条款存疑。在做出明智和最终决定之前,我们决定从网站上移除它。
这是一篇由 Alon Zakai 撰写的客座文章。Alon 是 Firefox Mobile 开发人员之一,在空闲时间,他喜欢用 JavaScript 和新 web 技术进行实验。其中一项实验是 Emscripten,一个 LLVM 到 JavaScript 的编译器,以下是 Alon 对它如何使用类型化数组运行经典的第一人称射击游戏 网络上的 Doom 的解释。
作为一名长期第一人称射击游戏爱好者,我一直想把它们带到 web 上。从头开始编写一个非常困难,所以,我采用了最初的 Doom,它是开源的,并使用 Emscripten 将其从 C 编译到 JavaScript。结果就是,Doom 的一个版本可以用 在 web 上玩,使用标准的 web 技术。
Doom 通过将像素数据写入内存,然后在转换颜色等之后将这些像素数据复制到屏幕上进行渲染。对于此演示,编译后的代码具有用大型 JavaScript 数组模拟的内存(因此该数组中的元素 N 代表正常原生代码中内存地址 N 的内容)。这意味着渲染、颜色转换和复制到屏幕上的所有操作都在该大型 JavaScript 数组上完成。基本上,该代码包含大型循环,这些循环复制或修改该数组的元素。为了使它尽可能快,演示可以选择使用 JavaScript 类型化数组,它们看起来像普通的 JavaScript 数组,但保证是特定数据类型的扁平数组。
// Create an array which contains only 32-bit Integers var buffer = new Int32Array(1000); for ( var i = 0 ; i < 1000 ; i++ ) { buffer[i] = i; }
当使用类型化数组时,与普通 JavaScript 数组的主要区别在于数组的元素都具有您设置的类型。这意味着在该数组上工作可能比在普通数组上快得多,因为它与普通低级 C 或 C++ 数组非常接近。相比之下,普通的 JavaScript 数组也可以是稀疏的,这意味着它不是单个连续的内存区域。在这种情况下,每次访问数组都会产生一个成本,即计算正确的内存地址。使用类型化数组,查找内存地址要快得多,因为它很简单直接。因此,在 Doom 演示中,使用类型化数组的帧速率几乎是未使用类型化数组的两倍。
类型化数组在 WebGL 和 音频数据 API 以及 Canvas 元素(从 getImageData()
收到的像素数据实际上是一个类型化数组)中非常重要。但是,如果您正在处理大量类似数组的数据,也可以独立使用类型化数组,这正是 Doom 演示的情况。只需注意,如果用户的浏览器不支持类型化数组,您的代码也能正常工作。这样做相当容易,因为类型化数组在大多数情况下看起来和行为像普通数组一样——您使用方括号访问它们的元素等等。主要的潜在陷阱是
- 类型化数组没有
slice()
。相反,它们有subarray()
,它不会创建数组的副本——相反,它只是对相同数据的视图。 - 不要忘记类型化数组的类型是静默强制的。如果您将 5.25 写入整数类型数组的元素,然后读回完全相同的元素,则会得到 5,而不是 5.25。
关于 louisremi
开发者关系团队,长期 jQuery 贡献者和开放 Web 爱好者。 @louis_remi
14 条评论