共计 2672 个字符,预计需要花费 7 分钟才能阅读完成。
前段时间为了推广一个新的公众号,开发了一款名为「投篮达人」(已下线)的小游戏,公布上线之后失去了不错的成果,胜利为公众号吸引了很多粉丝。上面就来跟大家分享下开发这款游戏的历程。
需要剖析
游戏自身其实很简略,只是一个投篮游戏,实现篮球的投射,篮筐静止,篮球与篮筐撞击,游戏完结后的排行榜记录以及公众号的辨认。但因为游戏是 2D 游戏,却有一个仿 3D 成果(篮球投出后离咱们越来越远以及穿透篮网),同时要让篮球与篮筐进行碰撞检测且模仿一个晦涩天然的反弹成果,所以须要一直填坑。
技术选型
思考到开发速度,找一个成熟且文档齐全的 HTML5 游戏开发引擎就非常重要了,在国内大多数人用的都是 Cocos2d-x-js 或 Egret,phaser 或 Hilo 这些不足比拟棘手的开发工具就跳过了,Cocos 在网页上的性能不太现实,所以最初抉择了 Egret 2D
至于物理引擎方面,Egret 是举荐应用 P2 引擎的,因为其性能相较于 Box 2D 或者 Matter.js 都好,不过毛病是不足中文文档。
实现思路
-
伪 3D 静止
- 近大远小的显示
以篮球初始地位(或底部)为原点确立一个视觉焦点,在篮球运动的过程中依据篮球在 Y 轴上的地位计算其缩放比例,计算公式如下:``scale = (curY - startY) / (endY - startY);``
另外,在物理世界中,任何刚体都是形态和大小都放弃不变的物理模型,也就意味着,咱们能让篮球的贴图的缩放,但无奈让篮球的刚体进行缩放。为了让篮球和篮筐撞击时,篮球的大小是精确的,咱们能够依据上图的缩放比例公式,计算篮球到达篮筐(篮筐地位确定,比例必然是固定的)时的比例,在初始地位让篮球的贴图和刚体大小放弃这一比例,当篮球运动到篮筐时大小就正好是其刚体的理论大小。
篮球与篮筐的交互
因为篮球上升时,在 2D 的物理世界中,篮球和篮筐实际上是同一立体,球和篮筐的刚体默认会产生碰撞,同时,篮球的纵深须要在上升时大于篮筐而着落时小于篮筐;
为了解决第一个问题,能够利用 P2 提供的碰撞分组来防止碰撞。
在 P2 中,刚体须要一个或多个 Shape 决定刚体的形状,而 Shape 又具备 collisionGroup 和 collisionMask 两个属性,前者决定了 Shape 的碰撞分组,后者决定了 Shape 会与哪些碰撞分组产生碰撞。须要留神的是,collisionGroup 的取值是 Math.pow(2,0) 到 Math.pow(2,32)。// 创立篮球刚体的形态 ballShape = new p2.Circle({radius: GlobalData.ballRadius / factor}); // 设置篮球的碰撞分组 ballShape.collisionGroup = this.FLYBALL; // 这样设置 collisionMask 篮球就能与篮筐交互,留神多个分组分隔的是 | 不是 || ballShape.collisionMask = this.BASKET | this.GROUND;
- 因而,在篮球上升时,设置其碰撞分组为 FLYBALL,其 collisionMask 为高空,此时篮球只会和高空碰撞,不与篮筐碰撞,当下落时,将其分组设置为 DROPBALL,collisionMask 为高空和篮筐,此时篮球就会和篮筐产生碰撞了。
为了解决第二个问题,思路相似,上升时将篮球的回升设置最高,着落时与篮筐替换纵深值即可;
- 二维码辨认
在微信网页中,常常须要提供长按二维码辨认性能,但二维码须要是一张理论的图片,内嵌于 Canvas 的二维码是不反对长按辨认的,为了让微信可能辨认到图片,只须要在 Canvas 下面笼罩一张图片即可。示意图如下:
在设置图片时,大小尺寸须要依据浏览器尺寸和 Canvas 的理论尺寸进行计算缩放,能力让图片看起来像是和 Canvas 一起的;
-
文字复制
游戏需要中,须要用户点击按钮复制一段文字发送给公众号,但因为浏览器对文字复制的权限不一样,市面上的解决方案是应用 ZeroClipBoard,但开发时没思考到,应用的是 document.execCommand(‘copy’),而因为兼容性,进行了 fallback,当浏览器不反对时提醒用户长按抉择文字进行复制,这时也因为 Canvas 不反对文字抉择,须要将文字跟二维码一样解决,搁置于 Canvas 之上;
性能优化
-
渲染优化
Egret 每刷新一帧的时候,会执行四步操作。在制作游戏的时候应该清晰的记住四步操作都在干什么。
- 咱们执行了一次 EnterFrame,此时,引擎会执行游戏中的逻辑。并且抛 EnterFrame 事件。
- 执行一个 clear。将上一帧的画面全副擦除。
- Egret 内核会遍历你游戏场景中的所有 DisplayObject,并从新计算所有显示对象的 transform
- 如果你接触过 canvas,那么你理解,这一步会将所有的图像全副 draw 到画布中。
理解了 Egret 的渲染机制之后,咱们就晓得该从哪里下手了。
首先,因为每次都要遍历 DisplayObject,对于不可见的对象都要进行革除,而创建对象也须要破费性能开销,所以咱们能够创立回收池对不可见的对象进行回收,这样就能够减小一部分开销;
其次,Canvas 检测触摸点的形式是遍历所有点来检测点击的是哪个点,咱们设置 Touch 层的时候,尽可能的往上挪,而不是设置在对象上,这样就能够缩小遍历所产生的开销。
另外在游戏开发过程中我手头只有 iOS 设施,而测试过程时发现在安卓机上存在掉帧重大的景象;在将画布尺寸从 640 1136 放大至 480 800 后,卡顿情况明显好转,猜想是因为画布太多会造成渲染的开销也变大,所以能够将画布在可承受范畴内设置小一些,由浏览器缩放画布,从而缩小渲染开销。
- 脏矩形渲染
对于简单 UI 界面的状况,全屏刷新算法会每秒 60 次不停地刷新所有 UI 对象,脏矩形渲染可能检测扭转的对象,只渲染扭转的对象。在有脏矩形渲染的状况下,哪扭转绘制哪,极其状况间接跳过绘制,在简单 UI 界面的状况非常容易达到满帧。
Egret 默认开启了脏矩形渲染,但当所有显示对象都在不停的动,那这种状况下性能反而不好。此时咱们须要通过敞开脏矩形渲染
this.stage.dirtyRegionPolicy = "off";
WebGL 渲染
WebGL 通过减少 OpenGL ES 2.0 的一个 JavaScript 绑定,能够为 HTML5 Canvas 提供硬件 3D 减速渲染。Egret Engine2D 提供了 WebGL 渲染模式。只需开启 WebGL 渲染,就能取得硬件加速。
Egret 在开启 WebGL 渲染模式下,如果浏览器不反对将主动切换到 Canvas 渲染模式下。
图片起源:页游