1、准备条件
1.1、设计师应该注意的地方
移动端最大的问题在于多种设备,多种平台,多种尺寸,当我们在做手机端H5网页设计稿时(当然包含微信端的H5网页设计),如果没有做过类似的移动端的设计,UI设计师和前端工程师肯定会纠结的。那么多手机屏幕尺寸,设计稿应该按照哪一个尺寸作为标准尺寸。现在已经有很多2K分辨率的手机屏幕了,设计稿是不是也要把宽高跟着最大分辨率来设计。显然不是。先看一下市面上主流的手机尺寸:
我们在H5开发初期的时候,进行了各种尺寸的设计稿尝试,比如1倍的(320X480)、2倍的(640X1136)、3倍的(1242X2280)像素。最终得出的试验结果是。H5的设计稿一般设计为640X1136即可。即iphone 5s的物理像素(也即是5、5c以及将要发布的5se的物理像素,这一系列手机在iphone的占有率中是最高的), 既满足了retina用户的显示需求,又能降低2G、3G用户加载图片需要的带宽。不过,你若有更高质量的追求,750*1334像素的设计稿也是一个不错的选择。
1.2、开发者应该注意的地方
不管在手机浏览器还是在微信客户端或者腾讯新闻客户端开发,内容大都不能全屏显示的。在底部或者顶部多多少少会有一个状态栏的占位,并不能展示手机的全部尺寸。一些手机浏览器底部会有导航,也有些会在顶部和底部都有占位,比如导航栏、状态栏。顶部的占位会把内容往下挤,底部的占位会把内容遮盖住。所以,我们在进行H5页面内容规划布局设计的时候,不能把重要内容放在太偏下或者太偏上的位置,否则前端布局时可能出现内容显示不全的情况。如果有滑动的交互操作,用户很有可能触发浏览器页面的滑动,导致较差的用户体验。
下图为腾讯新闻客户端和微信内置浏览器的占位高度,在640×1136(iphone5s)上他们的高度是一样的。如果你的页面高度超过1008px,页面就会出现滚动功能。
除去顶部大概130px的像素,底部大概150左右的像素,内容的安全高度大概有850左右,怎么布局页面,具体要看你的项目主要在什么环境上运行。
2、开始动手
2.1、页面流程
当我们在玩一个简单的H5的时候,其流程通常会包含以下步骤:
1、 出现一个载入进度条,载入一些必须的图片、音频、字体等文件;
2、 显示主菜单,提示用户开始游戏;
3、 进入游戏主逻辑。在游戏过程中,当用户胜利或者失败,或是触发了某个按钮或者按键时,游戏会退出,显示结果页面。
4、用户分享游戏或者关闭游戏。
也就是说一个完整的H5游戏,至少有3个页面不可或缺,就是加载页、游戏页、结果页。由此也可以延伸出多个页面,比如开始页,分享页等。
2.2、资源的加载
区别于普通的网页的开发,H5游戏需要大量的视觉听觉素材,并且用户的网络的带宽有限。当你使用了很多的图片、声音、视频以及媒体文件的时候,用户会花费一些时间等待浏览器从服务器下载。 如果在编写游戏时, 你不把它放在心上,不提前加载而直接使用, 等你开发完游戏到真实的用户场景上运行时,你就会碰到问题多多,因为图片和声音文件是异步加载的,你的JavaScript代码会在资源全部加载完成前执行。这常常导致一个红叉的图片在上蹿下跳,声音效果在需要时不播放或者延迟很久冒出来一个声音. 好的开发习惯是创建一个预加载器,延后脚本代码的执行,直到所有的资源都下载完毕为止,这个时候才放出游戏的开始按钮,让用户参与游戏。
我们经常会看到,一些站点在首次进入的时候会先显示一个进度条,等资源加载完毕后再呈现页面,进度条大概像这样:
以图片的加载为例,大致的代码应该是这样:
至于预加载的技术原理,其实也相当简单,就是维护一个资源列表,挨个去加载列表中的资源,然后在每个资源加载完成的回调函数中更新进度即可。
当前加载完的资源个数/pic总数*100,就是加载进度的百分比了。
当然,我们没必要手动写自己的加载器,很多优秀的游戏框架已经帮我们做到了,比如phaser,下面是phaser实现预加载的代码,具体的示例点我,点我
在上述的例子中,我们先创建一个游戏对象,然后往这个游戏对象中添加了两个方法,boot方法执行的时候准备了一张进度条图片,loaderState方法执行的时候,加载游戏所需的图片,并在页面上显示当前的进度。在多关卡的游戏中,加载的设置尤为重要。
3、理解游戏
3.1、认识phaser
对于一款游戏来说,框架就是它的基石。好的框架能是开发者利器,能够帮助开发者做出强有力的,跨浏览器的游戏,能给广大玩家带来更精致的作品。Phaser是一款专门用于移动及桌面的HTML5 2D游戏开发的开源免费框架,内置游戏物理引擎,它也就是传说中100行代码之内搞定Flappy Bird的神器。通过这个框架我们可以很容易地开发桌面和移动的小游戏。接下来我会以这个框架为基础,了解游戏的开发知识。
你可以点击这里获取phaser源码。点我,点我!
Phaser是一个单独的js文件,你可以通过script的标签来使用它。
3.2、游戏开发的世界观
游戏的界面分三个层次,世界、舞台和摄像机。如果把游戏看做通过手机观看的一部话剧,话剧都是在舞台上进行表演的,舞台的背后是世界。我们看到的画面都是通过现场的摄像机提供给我们的。摄像机有一个视角,这个视角到哪里,我们就能看到哪里的画面,游戏中所有看的见的东西,都是在舞台中的。可以把舞台看成游戏中所有对象最顶层的一个容器,然而舞台下面就是世界了,可以把它看成仅次于舞台的一个顶层容器,世界与舞台不同的地方在于,舞台的大小是你可视元素(对象)的大小,是固定大小的,但是世界确实是可以改变大小的,甚至是无限大的,而且可以随时设置成我们想要的大小,世界默认的大小是舞台的大小,我们看到的画面都是通过摄像机对象得到的,摄像机对象有个视角范围,这个范围跟舞台的大小范围是一样的,如果世界的范围是大于舞台的,那么摄像机就可以在世界中任意移动了,移动到不同的位置,我们就能看到不同的东西。
所有展示的东西,都在舞台上,世界有多大,摄像机就可以走多远,改变世界的大小,摄像机才可以在舞台上移动。世界限制你的范围,舞台给你准备素材,摄像机展示多彩的界面。理解了世界、舞台、摄像机的概念,面向对象的游戏编程就好理解多了。
游戏对象:game
可以通过以下代码,创建一个宽为640,高为1136的canvas标签,canvas的父标签是id=“gamezone”的div,当创建完毕后,生成一个game对象,然后会直接执行state对象中的方法。
var game = new Phaser.Game(
640,1136,Phaser.CANVAS,’gamezone’,state
);
舞台:game.stage
世界:game.world
摄像机:game.camera
通过代码,我们可以更好的理解游戏的世界,具体的示例,点我,点我!使用前后左右键可以移动摄像机的视角,点击屏幕可以把视野聚焦到火鸡身上。
3.3、游戏场景的生命周期
场景:game.state
场景指的是游戏中不同的界面或内容,比如游戏菜单界面为一个场景,真正玩游戏的界面为一个场景,不同的关卡又是不同的场景等等。场景能把一个复杂的游戏分成许多小块,各个场景可以独立出来,从而简化游戏的开发。游戏中的场景概念更加广泛,例如一个只是执行某些准备工作的但是没有实质的画面显示出来的state(状态),我们也把它叫做一个场景。一个游戏正是由众多场景所组成的。当我们创建一个游戏对象后,但这只是一个空的游戏,里面什么东西都没有,接下来往游戏里添加场景,并在不同的条件下切换场景,这样,一个个场景就构成了不同的游戏。
第一段代码示例中的
就是添加场景和启动场景。
场景的添加可以随意的,不按顺序,场景的启动也是,满足条件后触发即可,有些场景用户在结束游戏后都看不到也用不到,比如游戏的商店的场景(场景3),但是它确确实实存在过的。
把一个场景单拿出来,查看场景的内部的代码,代码循环:
每一个场景都会拥有这一个到五个方法,preload、create、update、render至少要存在一个,其中,update和render会循环执行,直到下一个场景开始。为什么要这么设计呢?举个例子来说,网速是H5的短板,可以在在游戏启动时只加载主菜单所需的资源,以提高游戏启动的速度。然后在每进入一关时,加载这一关所必须的资源。这样能更好的改善用户体验。
3.4、元素
理解完世界和场景这两大块,算是理解游戏开发的70%了,剩下的就是些细微的东西了,让我们先对它有一些认识,等使用的时候可以再查手册。
元素就是游戏的显示对象,顾名思义就是能够在舞台上显示的对象,也就是我们在游戏中所能看到的东西,我们只有了解了这些显示对象,才能做出一个好游戏。
文字(Text):
我们可以通过文本对象,显示浏览器默认的字体和你通过css加载的字体,它是对canvas文本的的一个包装。
图形(Graphics):
图形对象是对canvas绘图的一个包装,简便快捷的绘制出多边形。
图像(Image):
图像是一个轻量级对象,你可以使用它来显示任何不需要物理引擎或者动画的任务东西。它可以旋转、缩放、剪切,并接收输入事件。它可以完美的用于标识、背景、简单的按钮和其他非精灵类图形。
精灵(Sprite):
精灵是游戏的生命体,几乎可用于所有的可视化物体。基本上,精灵是有一套坐标和渲染在画布上的纹理所组成。精灵也包括了一些额外的属性,例如物理移动、输入处理、事件、动画等等。
瓦片(TileSprite):瓦片精灵是个有着重复纹理的精灵。纹理可以被滚动、缩放,并且自动包裹边缘。请注意,TileSprites 和普通的精灵默认没有输入处理方法和物理引擎刚体,两者都必须要启用后才会具有这些特性。
组:(Group)
组是一个用于显示各种对象(包括 Sprites 和 Images)的容器。我们可以把许多对象放进一个组里,然后就可以使用组提供的方法对这些对象进行一个批量或是整体的操作。比如要使组里的对象同意进行一个位移,只需要对组进行位移就可以了,又比如要对组里的所有对象都进行碰撞检测,那么就只需要对这个组对象进行碰撞检测就行了。
接下来以瓦片精灵为例,讲述各个元素的使用。瓦片精灵类似于css中的背景平铺,具体事例点我,点我,这里所有大背景图,都是有一张小小的瓦片拼接出来的,按上下左右可以移动视角。
3.5、物理引擎
若要使一个游戏更逼真,那一定离不开物理引擎,物理引擎是通过为游戏中的物体赋予真实的物理属性,计算运动、旋转和碰撞之后的效果。就是把现实世界的牛顿定律,应用到虚拟世界当中去。物理引擎是独立于游戏引擎存在的一个库。物理引擎的种类很多,例如box2d,cocos,three等,各有优劣,各有擅长。Phaser就内置了三种物理引擎arcade、ninja、P2(pixi 2d)。P2在这里要单独提一下,P2作为一个JS的2D渲染器,它的目标是提供一个快速的、轻量级而且是兼任所有设备的2D库。对于支持webgl的浏览器,P2将使用webgl绘图,不支持webgl的浏览器就降级至canvas,Pixi渲染器可以使开发者享受到硬件加速,但并不需要了解WebGL。进当然不限于这些引擎,你可以另外添加自己需要的物理引擎。下面是物理引擎的一个实例。
事例中对厨师和火鸡进行碰撞检测,类似于超级玛丽的踩怪物,厨师踩到火鸡是,由于火鸡是刚体,然后就会厨师就会反弹。当关闭火鸡的刚体属性后,厨师就直接从火鸡中穿过去了,与他碰撞的是世界的边界了。具体的示例,点我,点我!
3.6、动画
动画能够使游戏的画面更流畅。动画分两种,一种是补间动画,一种是逐帧动画。
在做动画时,我们只需要在动画的开头和结尾设定好状态,在中间只需要做一些过渡,就能实现图画的运动;插入中间的过渡是由计算机自动运算而得到的。这种动画叫做补间动画。在phaser中,Tween对象就是专门用来实现补间动画的。通过game.add的tween方法得到一个Tween对象,这个方法的参数是需要进行补间动画的物体。然后我们可以使用Tween对象的to方法来实现补间动画。
在例子中,我们设定了一个图片,让它在两个点之间来回走动,具体事例,点我,点我。
如果想实现更复杂一点的动画,那就需要逐帧动画了。
不同于补间动画,逐帧动画的每一帧都需要单独制定,而不像补间动画那样只需要制定开始和结束的那两个关键帧,同时逐帧动画是通过图片来实现的,我们可以给它的每一帧都指定一张图片,然后这些帧连续起来播放,就形成了一个动画。
下图准备了一张含有4帧图片的图片,把这4张图连起来一起循环播放,就成了一个动画。
我们把篮球的序列图加载成一个sprite对象,它有个animations属性,该对象有一个add方法,用来添加动画,还有一个play方法,用来播放动画。这样,一个循环变动的篮球就实现了。具体示例,点我,点我!
4、小技巧
4.1、用ps切完设计图后,原图对于移动端来说偏大,可以使用tinypng(tinypng.com)进行压缩,这里的图片压缩还是相当好用,可以节省用户不少带宽。也可以使用腾讯智图(zhitu.tencent.com)来进行压缩,区别于tinypng,它能为你提供高大上WebP格式的图片。
4.2、在进行页面布局的时候,脱离设备,按照640×1136像素进行布局,然后在页面的meta里加入
进行0.5倍缩放。这时候屏幕能适应320×568宽度的手机屏,对于比较宽的手机,会有些黑边。你也可以通过phaser进行缩放。
scaleMode会更改canvas的大小达到适配的目的。
4.3、如果你想学习phaser,这里有650+的例子和文档,你也可去百度搜一篇Flappy Bird开发的教程,这样的学习会更高效。
5、结尾
当试着用百度搜索了一些“H5游戏开发”之后,发现网上教程很多,什么“45分钟学会H5游戏开发”,“100行代码做个H5游戏”比比皆是,于是就改了主意,从另一角度来阐释游戏开发。H5游戏开发的思路大都是来自于Flash,Flash有一套现成的开发流程,把它的思想理解之后,对于H5游戏开发好处多多。再次把焦点回到市场上来,“今年将是H5游戏的元年!”,这个口号一直喊了5年,市场渐渐疲软。直到2016年第一款千万级别的产品出世,让游戏行业重新认识到原来H5游戏也是可以赚钱的。以现在的眼光来看待H5游戏行业,无论从技术层面还是用户层面来讲,H5游戏的市场都呈现越来越广阔的状态。