Egret 游戏开发:投篮

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

需求分析

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

技术选型

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

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

实现思路

  • 伪3D 运动

    1. 近大远小的显示

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

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

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

  1. 篮球与篮筐的交互

    由于篮球上升时,在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 渲染模式下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值