发布时间:2023-11-27 12:17:49 浏览量:109次
作者 | huangjianke
责编 | 伍杏玲
出品 | CSDN(ID:CSDNnews)
【CSDN 编者按】据微信最新数据,微信小游戏累计注册用户量已突破10亿。那么初学者如何开发一款好玩又烧脑的微信小游戏呢?本文作者将详细为大家讲解。
“启逻辑之高妙,因想象而自由。”层叠拼图Plus是一款需要空间想象力和逻辑推理能力完美结合的微信小游戏,偶消奇不消,在简单的游戏规则下却有着无数种可能性,需要你充分发挥想象力去探索,看似简单却具有极大的挑战性和趣味性,Talk is cheap. Show me the code!
层叠拼图Plus微信小游戏采用JavaScript+Canvas实现,没有使用任何游戏引擎,对于初学者来说,也比较容易入门。下面是小游戏页面:
绘图模糊的原因知道了,在微信小游戏里面又该如何解决呢?
可以看到,我们先通过 wx
.getSystemInfoSync.pixelRatio 获取设备的像素比ratio,然后将在屏 Canvas 的宽度和高度按照所获取的像素比ratio进行放大,在绘制文字、图片的时候,坐标点 x、y 和所要绘制图形的 width、height均需要按照像素比 ratio 进行缩放,这样我们就可以清晰的在高清屏中绘制想要的文字、图片。
可参考微信官方缩放策略调整
另外,需要注意的是,这里的 canvas 是由 weapp-adapter 预先调用 wx.createCanvas 创建一个上屏 Canvas,并暴露为一个全局变量 canvas。
在游戏画布内,我们以左上角为坐标原点 {x: 0, y: 0} ,一个多边形包含多个单位长度的平面坐标点,如:[{ x: 1, y: 3 }, { x: 5, y: 3 }, { x: 3, y: 5 }] 表示为一个三角形的区域,需要注意的是,x、y 并不是真实的平面坐标值,而是通过屏幕宽度计算出来的单位长度,在画布内的真实坐标值则为 {x: x * itemWidth, y: y * itemWidth} 。
绘制多边形代码实现如下:
使用:
效果如下图:
CanvasRenderingContext2D其他使用方法可参考:CanvasRenderingContext2D API 列表
有经验的同学,也许一眼就发现了,1 + 1 = 0 刚好符合通过异或运算得出的结果。当然,细心的同学也可能已经发现,上文有一句特殊的代码:
this.ctx.globalCompositeOperation = 'xor',也正是通过设置 CanvasContext 的 globalCompositeOperation 属性值为 xor 便实现了「偶消奇不消」的神奇效果。
globalCompositeOperation 是指 在绘制新形状时应用的合成操作的类型,其他效果可参考:globalCompositeOperation 示例
讲到这里,我们已经知道如何在Canvas画布内绘制出偶消奇不消效果的层叠图形了,接下来我们来看下玩家如何移动选中的图形。我们发现绘制出的图形对象并没有提供点击事件绑定之类的操作,那又如何判断玩家选中了哪个图形呢?这里我们就需要去实现如何判断玩家触摸事件的x,y坐标在哪个多边形图形内部区域,从而判断出玩家选中的是哪一个多边形图形。
判断一个点是否在任意多边形内部有多种方法,比如:
射线法
面积判别法
叉乘判别法
回转数法
...
在层叠拼图Plus小游戏内,采用的是回转数法来判断玩家触摸点是否在多边形内部。回转数是拓扑学中的一个基本概念,具有很重要的性质和用途。当然,展开讨论回转数的概念并不在该文的讨论范围内,我们仅需了解一个概念:当回转数为 0 时,点在闭合曲线外部。
图源:http://www.html-js.com/article/1538
上面面这张图动态演示了回转数的概念:图中红色曲线关于点(人所在位置)的回转数为 2。
对于给定的点和多边形,回转数应该怎么计算呢?
用线段分别连接点和多边形的全部顶点
图源:http://www.html-js.com/article/1538
计算所有点与相邻顶点连线的夹角
图源:http://www.html-js.com/article/1538
计算所有夹角和。注意每个夹角都是有方向的,所以有可能是负值
图源:http://www.html-js.com/article/1538
最后根据角度累加值计算回转数。360°(2π)相当于一次回转。
在使用 JavaScript 实现时,需要注意以下问题:
JavaScript 的数只有 64 位双精度浮点这一种。对于三角函数产生的无理数,浮点数计算不可避免会造成一些误差,因此在最后计算回转数需要做取整操作。
通常情况下,平面直角坐标系内一个角的取值范围是 -π 到 π 这个区间,这也是 JavaScript 三角函数 Math.atan2 返回值的范围。但 JavaScript 并不能直接计算任意两条线的夹角,我们只能先计算两条线与 x 正轴夹角,再取两者差值。这个差值的结果就有可能超出 -π 到 π 这个区间,因此我们还需要处理差值超出取值区间的情况。
代码实现:
通过前面的介绍我们可以知道,判断游戏结果是否正确其实就是比对玩家组合图形的 xor 结果与目标图形的 xor 结果。那么如何求多个多边形 xor 的结果呢?polygon-clipping 正是为此而生的。它不仅支持 xor 操作,还有其他的比如:union, intersection, difference 等操作。在层叠拼图Plus游戏内通过 polygon-clipping 又是怎样实现游戏结果判断的呢?
目标图形
多边形平面坐标点集合:
获取 多个多边形 xor 结果:
xor结果:
同理计算出玩家操作图形的xor结果进行比对即可得出答案正确与否。
需要注意的是,获取玩家的 xor 结果并不能直接拿来与目标图形xor 结果进行比较,我们需要将xor 的结果以左上角为参考点将图形平移至原点内,然后再进行比较,如果结果一致,则代表玩家答案正确。
在看本章节内容之前,建议先浏览一遍排行榜相关的官方文档:好友排行榜、关系链数据,以便对相关内容有个大概的了解。
开放数据域
开放数据域是一个封闭、独立的 JavaScript 作用域。要让代码运行在开放数据域,需要在 game.json 中添加配置项 openDataContext 指定开放数据域的代码目录。添加该配置项表示小游戏启用了开放数据域,这将会导致一些限制。
在游戏内使用 wx.setUserCloudStorage(obj) 对玩家游戏数据进行托管。
在开放数据域内使用 wx.getFriendCloudStorage(obj)拉取当前用户所有同玩好友的托管数据
展示关系链数据
如果想要展示通过关系链 API 获取到的用户数据,如绘制排行榜等业务场景,需要将排行榜绘制到 sharedCanvas 上,再在主域将 sharedCanvas 渲染上屏。
sharedCanvas 是主域和开放数据域都可以访问的一个离屏画布。在开放数据域调用 wx.getSharedCanvas 将返回 sharedCanvas。
在主域中可以通过开放数据域实例访问 sharedCanvas,通过 drawImage 方法可以将 sharedCanvas 绘制到上屏画布。
sharedCanvas 本质上也是一个离屏 Canvas,而重设 Canvas 的宽高会清空 Canvas 上的内容。所以要通知开放数据域去重绘 sharedCanvas。
需要注意的是:sharedCanvas 的宽高只能在主域设置,不能在开放数据域中设置。
一款能让人心情愉悦的游戏,性能问题必然不能成为绊脚石。那么可以从哪些方面对游戏进行性能优化呢?
在层叠拼图Plus小游戏内,针对需要大量使用且绘图繁复的静态场景,都是使用离屏 Canvas进行绘制的,如首页网格背景、关卡列表、排名列表等。在微信内 wx.createCanvas 首次调用创建的是显示在屏幕上的画布,之后调用创建的都是离屏画布。初始化时将静态场景绘制完备,需要时直接拷贝离屏Canvas的图像即可。Canvas 绘制本身就是不断的更新帧从而达到动画的效果,通过使用离屏 Canvas,就大大减少了一些静态内容在上屏Canvas的绘制,从而提升了绘制性能。
内存优化
玩家在游戏过程中拖动方块的移动其实就是不断更新多边形图形的坐标信息,然后不断的清空画布再重新绘制,可以想象,这个绘制是非常频繁的,按照普通的做法就需要不断去创建多个新的 Block 对象。针对游戏中需要频繁更新的对象,我们可以通过使用对象池的方法进行优化,对象池维护一个装着空闲对象的池子,如果需要对象的时候,不是直接new,而是从对象池中取出,如果对象池中没有空闲对象,则新建一个空闲对象,层叠拼图Plus小游戏内使用的是官方demo内已经实现的对象池类,实现如下:
垃圾回收
小游戏中,JavaScript 中的每一个 Canvas 或 Image 对象都会有一个客户端层的实际纹理储存,实际纹理储存中存放着 Canvas、Image 的真实纹理,通常会占用相当一部分内存。
每个客户端实际纹理储存的回收时机依赖于 JavaScript 中的 Canvas、Image 对象回收。在 JavaScript 的 Canvas、Image 对象被回收之前,客户端对应的实际纹理储存不会被回收。通过调用 wx.triggerGC 方法,可以加快触发 JavaScriptCore Garbage Collection(垃圾回收),从而触发 JavaScript 中没有引用的 Canvas、Image 回收,释放对应的实际纹理储存。
但 GC 具体触发时机还要取决于 JavaScriptCore 自身机制,并不能保证调用 wx.triggerGC 能马上触发回收,层叠拼图Plus小游戏在每局游戏开始或结束都会触发一下,及时回收内存垃圾,以保证最良好的游戏体验。
对于游戏来说,每帧 16ms 是极其宝贵的,如果有一些可以异步处理的任务,可以放置于 Worker 中运行,待运行结束后,再把结果返回到主线程。Worker 运行于一个单独的全局上下文与线程中,不能直接调用主线程的方法,Worker 也不具备渲染的能力。Worker与主线程之间的数据传输,双方使用 Worker.postMessage 来发送数据,Worker.onMessage 来接收数据,传输的数据并不是直接共享,而是被复制的。
需要注意的是:Worker 最大并发数量限制为 1 个,创建下一个前请用 Worker.terminate 结束当前 Worker
其他 Worker
相关的内容请参考微信官方文档:多线程 Worker
短短的一篇文章,定不能将层叠拼图Plus小游戏的前前后后讲明白讲透彻。其实最让人心累的还是软著的申请过程,由于各种原因前前后后花了将近三个月的时间,后续可以给大家分享软著申请相关的内容,希望可以帮助到需要的童鞋。
江湖不远,我们游戏里见!
作者简介:huangjianke,高级iOS开发/前端开发工程师,五年开发经验。
需要体验小游戏的童鞋可在微信小程序搜索层叠拼图Plus。
【END】
热门资讯
探讨游戏引擎的文章,介绍了10款游戏引擎及其代表作品,涵盖了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戏设计领域和数字艺术教育的重要性,欢迎点击咨询报名。
游戏中玩家将面临武侠人生的挣扎抉择,战或降?杀或放?每个抉定都将触发更多爱恨纠葛的精彩奇遇。《天命奇御》具有多线剧情多结局,不限主线发展,高自由...
3. B站视频剪辑软件「必剪」:免费、炫酷特效,小白必备工具
B站视频剪辑软件「必剪」,完全免费、一键制作炫酷特效,适合新手小白。快来试试!
4. 手机游戏如何开发(如何制作传奇手游,都需要准备些什么?)
如何制作传奇手游,都需要准备些什么?提到传奇手游相信大家都不陌生,他是许多80、90后的回忆;从起初的端游到现在的手游,说明时代在进步游戏在更新,更趋于方便化移动化。而如果我们想要制作一款传奇手游的
5. 3D动画软件你知道几个?3ds Max、Blender、Maya、Houdini大比拼
当提到3D动画软件或动画工具时,指的是数字内容创建工具。它是用于造型、建模以及绘制3D美术动画的软件程序。但是,在3D动画软件中还包含了其他类型的...
三昧动漫对于著名ARPG游戏《巫师》系列,最近CD Projekt 的高层回应并不会推出《巫师4》。因为《巫师》系列在策划的时候一直定位在“三部曲”的故事框架,所以在游戏的出品上不可能出现《巫师4》
一、声音优化在绝地求生游戏中能够提前听到脚步声往往能提前取得战机,主要有两种方法:1、利用SoundLock软件,软件的功能主要是限制最大音量。百度搜索...
众所周知,虚幻引擎5(下面简称UE5)特别占用存储空间,仅一个版本安装好的文件就有60G,这还不包括我们在使用时保存的工程文件和随之产生的缓存文件。而...
UI设计师、动画设计师、特效设计师每一个职位的功能和负责的方面都不同。所以,3D美术这方面需要大量的人才。但是要成为一个3D游戏建模师,也不是那么...
想让你的3D打印模型更坚固?不妨尝试一下Cura参数设置和设计技巧,让你轻松掌握!
最新文章