Roll It 是一项 Chrome 实验,让您只需使用手机和电脑上的浏览器,即可重温经典的木板路游戏。您可以通过手机上的浏览器轻轻一弹手腕来瞄准和滚动球,而计算机上的浏览器则会使用 WebGL 和 Canvas 渲染“Roll It”巷的实时图形。这两部设备通过 Websocket 进行通信。没有应用。无需下载。没有令牌。您只需一个现代浏览器即可。
在 Google Creative Lab 的指导下,Legwork 开发了用户体验、界面和游戏环境,然后与开发合作伙伴 Mode Set 合作打造了 Roll It。在整个项目期间,我们遇到了许多独特的挑战。本文将介绍我们在将“滚动吧”游戏付诸实施的过程中所用的一些技巧、发现的一些诀窍以及学到的一些经验教训。
3D 工作流程
一开始,我们遇到的一个难题是,如何将软件中的 3D 模型转换为适合 Web 的文件格式。在 Cinema 4D 中创建资源后,我们对模型进行了简化,并将其转换为低多边形网格。每个网格都被赋予了特定的多边形选择标记,以区分对象的各个部分,以便进行着色和纹理处理。然后,我们能够将其导出为 Collada 1.5 (.dae) 文件,并导入到开源 3D 程序 Blender,以便为 three.js 创建兼容的文件。确保模型正确导入后,我们将网格导出为 JSON 文件,并使用代码应用了照明。下面详细介绍了我们采取的步骤:
编写代码
Roll It 是使用开源库开发的,可在现代浏览器中原生运行。借助 WebGL 和 WebSocket 等技术,Web 正在逐渐接近主机级游戏和多媒体体验。随着越来越多的现代工具可用于 HTML 开发,开发者可以更轻松、更自如地打造这些体验。
开发环境
Roll It 的原始代码大部分是使用 CoffeeScript 编写的,这是一种简洁明了的语言,可转编译为格式正确且经过 lint 检查的 JavaScript。CoffeeScript 具有出色的继承模型和更清晰的范围处理,非常适合 OOP 开发。CSS 是使用 SASS 框架编写的,该框架为开发者提供了许多强大的工具来增强和管理项目的样式表。将这些系统添加到构建流程需要一些时间来进行设置,但绝对值得,尤其是对于像 Roll It 这样的大型项目。我们设置了一个 Ruby on Rails 服务器,以便在开发期间自动编译资源,这样所有这些编译步骤都变得透明。
除了打造简洁舒适的编码环境之外,我们还手动优化了资源,以尽可能减少请求,从而加快网站加载速度。我们将每张图片都通过了两个压缩程序(ImageOptim 和 ImageAlpha)的压缩。每款程序都以自己的方式优化图片,分别采用无损和有损压缩。通过正确组合设置,可以显著缩减图片的文件大小。这不仅在加载外部图片时节省了带宽,而且经过优化后,您的图片会转换为更小的 base64 编码字符串,以便在 HTML、CSS 和 JavaScript 中内嵌。说到 base64 编码,我们还使用此技术将 Open Sans WOFF 和 SVG 字体文件直接嵌入到 CSS 中,从而进一步减少了总请求次数。
启用了物理特性的 3D 场景
THREE.js 是适用于 Web 的通用 3D JavaScript 库。它封装了低级 3D 数学和基于硬件的 WebGL 优化,让普通用户无需编写自定义着色器或手动执行矩阵转换,即可轻松创建光线充足且美观的互动式 3D 场景。Physijs 是针对已转换为 JavaScript 的热门 C++ 物理库的 THREE.js 专用封装容器。我们利用此库在 3D 空间中模拟了球滚动、跳跃和弹跳到目的地的过程。
从一开始,我们就不仅致力于让滚球的物理体验感觉逼真,还要确保游戏中的物体感觉真实。这需要反复调整 Physijs 场景的整体重力、球在玩家投掷后滚动的速度、赛道的跳跃斜度,以及球和赛道材质的摩擦和弹性恢复(弹性)属性。更强的引力和更快的速度相结合,带来了更逼真的游戏体验。
平滑处理
大多数新型浏览器和显卡组合都应在 WebGL 环境中利用基于原生硬件的抗锯齿功能,但有些组合无法正常运行。如果抗锯齿功能无法原生运行,THREE.js 场景中的任何硬边和对比度边缘都会锯齿状且难看(至少在我们挑剔的眼睛看来是这样)。
幸运的是,我们可以通过一段代码来检测平台是否原生支持抗锯齿。如果可以,那就太棒了。如果不行,THREE.js 附带了一系列后处理着色器,可以帮助我们解决问题。即 FXAA 抗锯齿滤镜。通过使用此着色器在每一帧中重新绘制渲染的场景,我们通常可以获得更加平滑的线条和边缘。请参阅下面的演示:
// Check for native platform antialias support via the THREE renderer
// from: http://codeflow.org/entries/2013/feb/22/how-to-write-portable-webgl/#antialiasing
var nativeAntialiasSupport = (renderer.context.getParameter(renderer.context.SAMPLES) == 0) ? false : true;
基于加速度计的游戏控制
“Roll It”的大部分魔力来自玩家使用手机执行的滚球手势。移动设备已经能够在浏览器中使用加速度计一段时间了,但作为一个行业,我们才刚刚开始探索在 Web 上基于动作的手势识别。我们在一定程度上受到手机加速度计提供的数据的限制,但只要稍加发挥创意,我们就能设计出一些出色的新体验。
检测滚动 其主要的“滚动”手势首先会跟踪来自窗口 deviceorientation
事件的 10 个最新加速度计更新。通过将当前倾斜度值减去上一个倾斜度值,我们可以存储事件之间的角度差值。然后,通过不断求和最近 10 个角度差分,我们可以检测手机在空间中移动时的连续旋转。当手机超出扫描角度变化阈值时,我们会触发滚动。然后,通过查找该扫描中单次倾斜增量最大值,我们可以估算出球的速度。在 Roll It 中,系统会使用附加到每个加速度计更新的时间戳对此速度进行标准化处理。这有助于平滑地调整加速度计更新在不同设备上流式传输到浏览器的速度。
WebSocket 通信
当玩家用手机滚动球时,手机会向笔记本电脑发送一条消息,指示其发射球。此“滚动”消息通过两个机器之间的 WebSocket 连接发送,采用 JSON 数据对象的形式。JSON 数据很小,主要包括消息类型、投掷速度和瞄准方向。
{
"type": "device:ball-thrown",
"speed": 0.5,
"aim": 0.1
}
笔记本电脑和手机之间的所有通信都是通过类似这样的小型 JSON 消息进行的。每当游戏在桌面设备上更新其状态,或者用户倾斜或点按手机上的按钮时,系统都会在两台设备之间传输 WebSocket 消息。为了让这种通信简单易管理,WebSocket 消息会使用任一浏览器中的单个出口点进行广播。相反,接收浏览器上只有一个入口点,一个 WebSocket 对象处理两端的所有传入和传出消息。收到 WebSocket 消息后,系统会使用 jQuery 的 trigger()
方法在 JavaScript 应用中重新广播 JSON 数据。此时,传入数据的行为与任何其他自定义 DOM 事件一样,并且可以由应用中的任何其他对象拾取和处理。
var websocket = new WebSocket(serverIPAddress);
// rebroadcast incoming WebSocket messages with a global event via jQuery
websocket.onmessage = function(e) {
if (e.data) {
var obj = JSON.parse(e.data);
$(document).trigger(data.type, obj);
}
};
// broadcast outgoing WebSocket messages by passing in a native .js object
var broadcast = function(obj) {
websocket.send(JSON.stringify(obj));
};
当两部设备与游戏代码同步时,Roll It 的 WebSocket 服务器会动态创建。Roll It 的后端是使用 Go 在 Google Compute Engine 和 App Engine 平台上构建的。
倾斜菜单屏幕
除了游戏过程中使用的事件驱动型 WebSocket 消息之外,玩家还可以通过倾斜手机并点按按钮来确认选择,从而控制“Roll It”中的菜单。这需要从手机到笔记本电脑传输更一致的倾斜度数据流。为了减少带宽并避免发送不必要的更新,只有在设备倾斜度发生超过几度的变化时,才会发送这些消息。如果手机平放在桌面上,发送倾斜度数据流就没有意义了!传输速率也会受到节流限制 - 在“滚动”模式下,每秒发送的 WebSocket 消息不得超过 15 条,即使设备正在积极倾斜也是如此。
计算机上获取倾斜度值后,系统会使用 requestAnimationFrame
对这些值进行插值,以保持平滑的触感。最终结果是一个旋转菜单和一个滚动的球,用于帮助指示用户的选择。当手机发送倾斜度数据时,这些 DOM 元素会通过重新计算 requestAnimationFrame
循环内的 CSS 转换来实时更新。菜单的容器只是旋转,但球似乎在沿地板滚动。为了实现此效果,我们实现了一些基本三角函数,以将球的 x 坐标与其旋转相关联。简单的方程为:旋转次数 = x /(直径 * π)
小结
滚动是时代的标志。从为其开发提供支持的开源项目、桌上和口袋中的设备的处理能力,以及作为平台的 Web 状态来看,现在是通过开放 Web 建立联系的真正令人兴奋且具有变革性的时代。仅仅几年前,这些技术中的大部分仅存在于专有系统中,无法自由使用和分发。如今,我们每天都在创造和分享新的拼图碎片,因此可以通过更少的工作量和更多想象力来实现复杂的体验。还在等什么?打造出精彩的内容,并与世界各地的用户分享!