Egret 游戏开发:投篮

前段时间为了推广一个新的公众号,开发了一款名为「投篮达人」(已下线)的小游戏,发布上线以后获得了不错的效果,成功为公众号吸引了不少粉丝。下面就来跟你们分享下开发这款游戏的历程。html

需求分析

游戏自己其实很简单,只是一个投篮游戏,实现篮球的投射,篮筐运动,篮球与篮筐撞击,游戏结束后的排行榜记录以及公众号的识别。但因为游戏是2D游戏,却有一个仿3D效果(篮球投出后离咱们愈来愈远以及穿透篮网),同时要让篮球与篮筐进行碰撞检测且模拟一个流畅天然的反弹效果,因此须要不断填坑。git

技术选型

考虑到开发速度,找一个成熟且文档齐全的HTML5 游戏开发引擎就十分重要了,在国内大多数人用的都是Cocos2d-x-js 或Egret,phaser 或 Hilo 这些缺少比较顺手的开发工具就跳过了,Cocos 在网页上的性能不太理想,因此最后选择了Egret 2Dgithub

至于物理引擎方面,Egret 是推荐使用P2 引擎的,由于其性能相较于Box 2D 或者Matter.js 都好,不过缺点是缺少中文文档,目前我也在进行翻译中,地址戳 👉 P2 中文文档 算法

实现思路

  • 伪3D 运动 canvas

    1. 近大远小的显示

以篮球初始位置(或底部)为原点确立一个视觉焦点,在篮球运动的过程当中根据篮球在Y轴上的位置计算其缩放比例,计算公式以下:浏览器

``scale = (curY - startY) / ( endY - startY);``复制代码

另外,在物理世界中,任何刚体都是形状和大小都保持不变的物理模型,也就意味着,咱们能让篮球的贴图的缩放,但没法让篮球的刚体进行缩放。
为了让篮球和篮筐撞击时,篮球的大小是准确的,咱们能够根据上图的缩放比例公式,计算篮球抵达篮筐(篮筐位置肯定,比例必然是固定的)时的比例,在初始位置让篮球的贴图和刚体大小保持这一比例,当篮球运动到篮筐时大小就正好是其刚体的实际大小。性能优化

  1. 篮球与篮筐的交互bash

    因为篮球上升时,在2D 的物理世界中,篮球和篮筐其实是同一平面,球和篮筐的刚体默认会产生碰撞,同时,篮球的纵深须要在上升时大于篮筐而下落时小于篮筐;微信

    为了解决第一个问题,能够利用P2 提供的碰撞分组来避免碰撞。工具

    在P2 中,刚体须要一个或多个Shape 决定刚体的外形,而Shape 又具备collisionGroup 和 collisionMask 两个属性,前者决定了Shape 的碰撞分组,后者决定了Shape 会与哪些碰撞分组发生碰撞。须要注意的是,collisionGroup 的取值是 Math.pow(2,0) 到 Math.pow(2,32), 具体参考(Shape 的碰撞分组);

    // 建立篮球刚体的形状
    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每刷新一帧的时候,会执行四步操做。在制做游戏的时候应该清晰的记住四步操做都在干什么。

    1. 咱们执行了一次EnterFrame,此时,引擎会执行游戏中的逻辑。而且抛 EnterFrame事件。
    2. 执行一个clear。将上一帧的画面所有擦除。
    3. Egret内核会遍历你游戏场景中的全部DisplayObject,并从新计算全部显示对象的transform
    4. 若是你接触过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 渲染模式下。

相关文章
相关标签/搜索