深圳市进源盛塑胶材料有限公司

PEEK;PTFE;POM;PMMA

 
 
新闻中心
正文
如何用 JavaScript+Canvas 开发一款超级烧脑小游戏?
发布时间:2019-09-12        

  “启逻辑之高妙,因想象而自由。”层叠拼图Plus是一款需要空间想象力和逻辑推理能力完美结合的微信小游戏,偶消奇不消,在简单的游戏规则下却有着无数种可能性,需要你充分发挥想象力去探索,看似简单却具有极大的挑战性和趣味性,Talk is cheap. Show me the code!

  层叠拼图Plus微信小游戏采用Java+Canvas实现,没有使用任何游戏引擎,对于初学者来说,也比较容易入门。下面是小游戏页面:

  Canvas 绘图时,会从两个物理像素的中间位置开始绘制并向两边扩散 0.5 个物理像素。当设备像素比为 1 时,一个 1px 的线条实际上占据了两个物理像素(每个像素实际上只占一半),由于不存在 0.5 个像素,所以这两个像素本来不应该被绘制的部分也被绘制了,于是 1 物理像素的线 物理像素,视觉上就造成了模糊

  Canvas 绘图时,会从两个物理像素的中间位置开始绘制并向两边扩散 0.5 个物理像素。当设备像素比为 1 时,一个 1px 的线条实际上占据了两个物理像素(每个像素实际上只占一半),由于不存在 0.5 个像素,所以这两个像素本来不应该被绘制的部分也被绘制了,于是 1 物理像素的线 物理像素,视觉上就造成了模糊

  可以看到,我们先通过 wx.getSystemInfoSync.pixelRatio 获取设备的像素比ratio,然后将在屏 Canvas 的宽度和高度按照所获取的像素比ratio进行放大,在绘制文字、图片的时候,坐标点 x、y 和所要绘制图形的 width、height均需要按照像素比 ratio 进行缩放,这样我们就可以清晰的在高清屏中绘制想要的文字、图片。

  讲到这里,我们已经知道如何在Canvas画布内绘制出偶消奇不消效果的层叠图形了,接下来我们来看下玩家如何移动选中的图形。我们发现绘制出的图形对象并没有提供点击事件绑定之类的操作,那又如何判断玩家选中了哪个图形呢?这里我们就需要去实现如何判断玩家触摸事件的x,y坐标在哪个多边形图形内部区域,从而判断出玩家选中的是哪一个多边形图形。

  在层叠拼图Plus小游戏内,采用的是回转数法来判断玩家触摸点是否在多边形内部。宁波海运领涨7%。香港王中王正版挂牌,回转数是拓扑学中的一个基本概念,具有很重要的性质和用途。当然,展开讨论回转数的概念并不在该文的讨论范围内,我们仅需了解一个概念:当回转数为 0 时,点在闭合曲线外部。

  上面面这张图动态演示了回转数的概念:图中红色曲线关于点(人所在位置)的回转数为 2。

  Java 的数只有 64 位双精度浮点这一种。对于三角函数产生的无理数,浮点数计算不可避免会造成一些误差,因此在最后计算回转数需要做取整操作。

  通常情况下,平面直角坐标系内一个角的取值范围是 -π 到 π 这个区间,这也是 Java 三角函数 Math.atan2 返回值的范围。但 Java 并不能直接计算任意两条线的夹角,我们只能先计算两条线与 x 正轴夹角,再取两者差值。这个差值的结果就有可能超出 -π 到 π 这个区间,因此我们还需要处理差值超出取值区间的情况。

  通过前面的介绍我们可以知道,判断游戏结果是否正确其实就是比对玩家组合图形的 xor 结果与目标图形的 xor 结果。那么如何求多个多边形 xor 的结果呢?polygon-clipping 正是为此而生的。它不仅支持 xor 操作,还有其他的比如:union, intersection, difference 等操作。在层叠拼图Plus游戏内通过 polygon-clipping 又是怎样实现游戏结果判断的呢?

  需要注意的是,获取玩家的 xor 结果并不能直接拿来与目标图形xor 结果进行比较,我们需要将xor 的结果以左上角为参考点将图形平移至原点内,然后再进行比较,如果结果一致,则代表玩家答案正确。

  在看本章节内容之前,建议先浏览一遍排行榜相关的官方文档:好友排行榜、关系链数据,以便对相关内容有个大概的了解。

  开放数据域是一个封闭、独立的 Java 作用域。要让代码运行在开放数据域,需要在 game.json 中添加配置项 openDataContext 指定开放数据域的代码目录。添加该配置项表示小游戏启用了开放数据域,这将会导致一些限制。

  如果想要展示通过关系链 API 获取到的用户数据,如绘制排行榜等业务场景,需要将排行榜绘制到 sharedCanvas 上,再在主域将 sharedCanvas 渲染上屏。

  需要注意的是:sharedCanvas 的宽高只能在主域设置,不能在开放数据域中设置。

  性能优化,简而言之,就是在不影响系统运行正确性的前提下,对之前的学习内容进行复习,香港挂牌系列彩图资料,使之运行地更快,完成特定功能所需的时间更短。

  性能优化,简而言之,就是在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。

  一款能让人心情愉悦的游戏,性能问题必然不能成为绊脚石。那么可以从哪些方面对游戏进行性能优化呢?

  在层叠拼图Plus小游戏内,针对需要大量使用且绘图繁复的静态场景,都是使用离屏 Canvas进行绘制的,如首页网格背景、关卡列表、排名列表等。在微信内 wx.createCanvas 首次调用创建的是显示在屏幕上的画布,之后调用创建的都是离屏画布。初始化时将静态场景绘制完备,需要时直接拷贝离屏Canvas的图像即可。Canvas 绘制本身就是不断的更新帧从而达到动画的效果,通过使用离屏 Canvas,就大大减少了一些静态内容在上屏Canvas的绘制,从而提升了绘制性能。

  玩家在游戏过程中拖动方块的移动其实就是不断更新多边形图形的坐标信息,然后不断的清空画布再重新绘制,可以想象,这个绘制是非常频繁的,按照普通的做法就需要不断去创建多个新的 Block 对象。针对游戏中需要频繁更新的对象,我们可以通过使用对象池的方法进行优化,对象池维护一个装着空闲对象的池子,如果需要对象的时候,不是直接new,而是从对象池中取出,如果对象池中没有空闲对象,则新建一个空闲对象,层叠拼图Plus小游戏内使用的是官方demo内已经实现的对象池类,实现如下:

  小游戏中,Java 中的每一个 Canvas 或 Image 对象都会有一个客户端层的实际纹理储存,实际纹理储存中存放着 Canvas、Image 的真实纹理,通常会占用相当一部分内存。

  每个客户端实际纹理储存的回收时机依赖于 Java 中的 Canvas、Image 对象回收。在 Java 的 Canvas、Image 对象被回收之前,客户端对应的实际纹理储存不会被回收。通过调用 wx.triggerGC 方法,可以加快触发 JavaCore Garbage Collection(垃圾回收),从而触发 Java 中没有引用的 Canvas、Image 回收,释放对应的实际纹理储存。

  但 GC 具体触发时机还要取决于 JavaCore 自身机制,并不能保证调用 wx.triggerGC 能马上触发回收,层叠拼图Plus小游戏在每局游戏开始或结束都会触发一下,及时回收内存垃圾,以保证最良好的游戏体验。

  对于游戏来说,每帧 16ms 是极其宝贵的,如果有一些可以异步处理的任务,可以放置于 Worker 中运行,待运行结束后,再把结果返回到主线程。Worker 运行于一个单独的全局上下文与线程中,不能直接调用主线程的方法,Worker 也不具备渲染的能力。Worker与主线程之间的数据传输,双方使用 Worker.postMessage 来发送数据,Worker.onMessage 来接收数据,传输的数据并不是直接共享,而是被复制的。

  短短的一篇文章,定不能将层叠拼图Plus小游戏的前前后后讲明白讲透彻。其实最让人心累的还是软著的申请过程,由于各种原因前前后后花了将近三个月的时间,后续可以给大家分享软著申请相关的内容,希望可以帮助到需要的童鞋。

  作者简介:huangjianke,高级iOS开发/前端开发工程师,五年开发经验。