迪斯尼《Find Your Way to OZ》这个贴近地气的游戏我在最新一期《程序员》杂志的《从HTML5移动应用现状谈发展趋势》这篇文章里有所提及,它借用了近期上映的《魔境仙踪》电影的设定(设定来自于经典故事《绿野仙踪》,看过这个电影的同学们会深有感触),构建了一个等同的宏大游戏世界。同时迪斯尼又和谷歌合作,把它作为Chrome浏览器性能和HTML5技术的一个show case。对于这样一个使用了WebGL 3D、摄像头、3D音效等多种先进技术、支持桌面和移动端、品质出色的HTML5游戏,了解它背后的实现原理和技巧必然对于我们来说有着非常巨大的参考意义。
这篇文章我早就想翻译出来,帮助大家更好的了解HTML5在游戏开发里的应用和国外的应用情况,但是这篇文章实在太长,所以只能分次刊载,以飨读者。
此教程在我近期HTML5介绍的文章中难度可称高级,适合有一定经验的开发者阅读和学习。
介绍
“寻找奥兹之路”是迪斯尼为谷歌Chrome带来的全新体验。它让你在互动的旅程中穿越堪萨斯马戏团,然后通过一个巨大的风暴到达奥兹王国。
我们的目标是结合浏览器的技术能力,以创建一种充满乐趣、身临其境的体验,用户可以与电影之间形成一个强大的联系。
这个游戏的工作实在是太庞大,所以我们只能列出一些章节,把我们认为有趣的技术故事写出来。教程的难度随着进度会逐渐增加。
我们有很多人努力工作来创建更好的体验,但是太多无法一一列举。请访问该网站,体验整个页面下的完整故事。
预览
在PC端《寻找奥兹之路》是一个丰富的身临其境的世界。我们把3D和传统的电影制作灵感结合起来,创造一个好几层的接近现实的场景效果。其中最突出的技术是用Three.js引入WebGL,使用CSS3特性来定制着色器和DOM动画元素。除此之外,getUserMedia API(WebRTC)增强了互动体验,允许用户直接从摄像头添加自己的形象,以及WebAudio带来了3D音效。
但是这种技术体验的神奇之处在于它们是如何融合为一体的。这也是面临的主要挑战之一:如何把视觉效果和互动元素融合在一起来创建一个一致的场景?这种视觉的复杂性非常难以管理:很难说清楚我们在任何一个时间需要开发什么场景。
为了解决视觉效果和优化这一问题,我们大量使用了一个控制面板,用于捕获我们正在检查的那个时间点的所有相关设置。在浏览器中可以实时修正场景中的一切,例如亮度,纵向深度,伽玛线等等。任何人都可以在体验中尝试调整重要参数的值,参与并发现什么效果最好。
在分享我们的秘密之前,我要提醒你,它可能会导致崩溃。确保你没有正在浏览什么重要的东西,并且在访问该网站的网址时添加?debug=on。等待网站加载,一旦你进入后按Ctrl+I键,会看到右手边出现一个下拉菜单。如果取消选中“退出相机路径”选项,你可以使用A、W、S、D键和鼠标在空间中自由的移动。
我们不会详述这里的所有设置,但是我们鼓励你试验:按键显示不同的场景中不同的设置。在最后的风暴场景中有一组额外的按键:Ctrl+A,可以切换播放的动画。在这个场景中,如果你按Esc(退出鼠标锁定功能),再次按下Ctrl+I键可以进入风暴场景的特殊设置。看看四周,并且截取一些像下面这样的漂亮明信片。
要做到这一点以确保其对我们的需求具有足够的灵活性,我们采用了一个很棒的名为dat.gui的框架(可以在这里看看过去关于如何使用它的教程)。它允许我们能够迅速改变暴露给游客的设置。
有点像绘景
许多经典的迪士尼电影和动画创建场景意味着合并不同的层。有外景层、单元动画层,以及物理设置层和通过玻璃绘画获得的顶层:这种技术称为绘景。
在许多方面我们创造的体验的结构是相似的,即使有些“层”远远超过了静态的视觉效果。事实上,它们根据更为复杂的计算影响事物看起来的方式。然而,至少在大画面的水平,我们处理视图,将一个合成到另外一个之上合。在顶部,你看到一个UI层,其下是3D场景:它由不同的场景组件组成。
顶部接口层使用DOM和CSS 3创建。事件通信使用Backbone路由器+ onHashChange HTML5事件来控制哪块区域响应动画。(项目源代码:/develop/coffee/router/Router.coffee)。
教程:Sprite表和视网膜支持
我们依赖一种有趣的优化技术,把多个接口层图像合并为一张单独的PNG来减少服务器请求。在这个项目中,接口由多于70 张的图像组成(不包括3D纹理),并且全部预加载以减少网站延迟。你可以在这里看到最新的Sprite表:
正常显示
Retina显示屏
下面是我们如何发挥Sprite表优势的一些技巧,在视网膜设备上如何使用它们,以及如何将接口尽可能设置的简洁而整齐。
创建Sprite表
我们使用TexturePacker来创建任何你需要的Sprite表格式。在这种情况下,我们采用EaselJS,它非常整洁,并且可以用于创建动画Sprite。
使用生成的Sprite表
一旦创建了Sprite表,你应该看到这样的一个JSON文件:
{ "images": ["interface_2x.png"], "frames": [ [2, 1837, 88, 130], [2, 2, 1472, 112], [1008, 774, 70, 68], [562, 1960, 86, 86], [473, 1960, 86, 86] ], "animations": { "allow_web":[0], "bottomheader":[1], "button_close":[2], "button_facebook":[3], "button_google":[4] }, }
其中:
images指向sprite表的地址
frames是每个UI元素的坐标[x, y, width, height]
animations 是每项内容的名称
请注意,我们已经使用了高清图像来创建Sprite表,然后我们只需通过调整图像尺寸为一半来创建正常版本。
融合一切
现在,我们只需要一段Javascript代码来使用它。
var SSAsset = function (asset, p) { var css, x, y, w, h; // pide the coordinates by 2 as retina devices have 2x density x = Math.round(asset.x / 2); y = Math.round(asset.y / 2); w = Math.round(asset.width / 2); h = Math.round(asset.height / 2); // Create an Object to store CSS attributes css = { width : w, height : h, 'background-image' : "url(" + asset.image_1x_url + ")", 'background-size' : "" + asset.fullSize[0] + "px " + asset.fullSize[1] + "px", 'background-position': "-" + x + "px -" + y + "px" }; // If retina devices if (window.devicePixelRatio === 2) { /* set -webkit-image-set for 1x and 2x All the calculations of X, Y, WIDTH and HEIGHT is taken care by the browser */ css['background-image'] = "-webkit-image-set(url(" + asset.image_1x_url + ") 1x,"; css['background-image'] += "url(" + asset.image_2x_url + ") 2x)"; } // Set the CSS to the p p.css(css); };
这是你如何使用它的代码:
logo = new SSAsset( { fullSize : [1024, 1024], // image 1x dimensions Array [x,y] x : 1790, // asset x coordinate on SpriteSheet y