微信小游戏实现原理

1.原理说明

从技术角度来说,微信小游戏是微信小程序的基础上添加了游戏库 API。小游戏只能运行在小程序环境中,所以小游戏既不是原生游戏,也不完全等同于 HTML5 游戏。但实际上小游戏面向的就是 HTML5 游戏开发者,为了能够让 HTML5 游戏可以尽可能低成本得移植,小游戏尽可能复用了 WebGL,JavaScript 等源自 浏览器的 HTML5 技术。可以说小游戏是使用 HTML5 技术搭建,具有原生体验的微信内游戏产品。

从技术角度来说,微信小游戏是微信小程序的基础上添加了游戏库 API。小游戏只能运行在小程序环境中,所以小游戏既不是原生游戏,也不完全等同于 HTML5 游戏。但实际上小游戏面向的就是 HTML5 游戏开发者,为了能够让 HTML5 游戏可以尽可能低成本得移植,小游戏尽可能复用了 WebGL,JavaScript 等源自 浏览器的 HTML5 技术。可以说小游戏是使用 HTML5 技术搭建,具有原生体验的微信内游戏产品。小游戏采用这样的模式有很多优点,最大的优点在于稳定和可控。相比于原生,微信可以将游戏闭环在微信内部;相比于纯 HTML5,则不用担心被游戏切广告切支付。

微信小游戏的运行时环境与曾出现过的其他 runtime 形态相比有一个很大的好处是「兼容 HTML5 生态」。也就是说不论你用哪个游戏引擎开发的 HTML5 游戏,都可以很容易地移植到小游戏上面。这使得微信小游戏可以直接从巨大的 HTML5 生态中借力。

2.开发小游戏的必备知识点

2.1 底层技术

首先是开发语言,微信小游戏只支持 JavaScript,当然可以编译为 JS 的 TypeScript 以及 CoffeeScript 都可以作为开发语言使用。

其次是小游戏所支持的游戏库 API,主要包含 HTML5 的 Canvas 2D API 和 WebGL 1.0 API,使用任何一种 API 都可以完成游戏最重要的渲染功能,不过不能够混用,除此之外,只有 WebGL 渲染模式可以支持 3D 渲染。

2.2 中间件:游戏引擎

当然,直接使用 Canvas 2D 或 WebGL 来制作游戏是门槛很高,也非常费时费力的一件事,你肯定不希望一个小游戏项目拖上一年半载吧?所以使用 HTML5 游戏引擎其实是非常明智的选择,引擎封装出的高层接口可以大大降低开发者的开发门槛,缩短项目周期。目前国内的三家主流引擎 Cocos Creator、Egret、Laya 均已支持小游戏发布,Phaser.js、Three.js 等国外 HTML5 引擎虽然并没有支持直接发布,经过一些定制也是可以成功运行在小游戏环境中。

2.3 微信 SDK

除此之外,微信小游戏还提供了丰富的微信内部 SDK 供开发者调用,使用这些接口可以完成用户登陆、转发、排行榜等常规的社交功能。

3.理解小游戏的底层技术架构

小游戏的运行环境其实是微信的原生环境,游戏的 JavaScript 代码并不是通过浏览器来执行的,而是通过图中 JS VM 层独立的 JavaScript 引擎来执行的。 在 Android 平台使用 Google 的 v8 引擎,而在 iOS 上则使用苹果的 JavaScript Core 引擎。

当然 JS 引擎只负责解释执行 JS 逻辑,并没有支持渲染接口,那么渲染接口和诸多的微信功能接口又是怎么实现的呢?这就不得不提到脚本绑定技术,这种技术可以将某种原生语言的接口桥接到脚本接口上,当在脚本层调用接口时,会自动转发到原生层,调用原生接口。微信小游戏环境用的就是这样的技术,将 iOS / Android 原生平台实现的渲染、用户、网络、音视频等接口绑定为 JavaScript 接口。这也就是图中的微信原生层模块到小游戏层模块的原理。脚本绑定技术无法在这篇文章中深入探讨,如果大家有兴趣,可以去了解 Cocos Creator 的 JSB 绑定实现,这也是游戏引擎中唯一一家完全开源的绑定技术实现。

小游戏在有了这样一套框架之后,HTML5 游戏在移植过程中仍然是会遇到无数 API 兼容性问题,最简单的比如 document 对象不存在,Image 对象不存在。为了降低移植成本,微信团队提供了一个 Adapter 脚本,适配了一部分浏览器接口。

4.网络接口

网络接口分为三个部分:网络请求,WebSocket,上传下载。

4.1 网络请求

网络请求的 API 是 wx.request,这个接口可以理解为浏览器中的 XMLHttpRequest,实际上 Adapter 中的 XHR 对象也正是用它来封装的。它可以用来发出网络请求,获取远程服务器返回的数据。值得一提的是,这份数据是存储在内存中的,用户可以直接使用,不涉及到任何文件 IO 操作。

4.2 WebSocket

WebSocket 相关接口的使用方式可以参考 API 文档,虽然接口定义和浏览器中并不相同,不过 Adapter 再次基于微信基础 API 提供了等同于浏览器接口的封装,所以我们建议大家不需要根据微信基础 API 进行适配,直接引入 Adapter 脚本,省去适配的烦恼。当然,如果游戏中的网络请求遇到奇怪的问题,你可能需要通过原始 API 进行调试和定位。

4.3 上传下载

微信还提供了浏览器中所没有的直接上传(wx.uploadFile)和下载(wx.downloadFile) API。

对于游戏开发来说,我们需要重点关注的是下载 API。首先它和 request 的用途不同,request 用来请求多种形式的数据,包括字符串、文件数据、ArrayBuffer、json 对象,所以适合用来做短链接请求,调用服务器 Restful API,而 wx.downloadFile 则是用来直接下载文件到本地的。

如果在调用参数对象中指定 filePath,那么下载下来的文件会被存储到小游戏的本地缓存空间,否则下载下来的文件会被存储在临时空间,退出小游戏时就会被删除,这取决于你是否需要长期保留这个文件。不过需要注意的是,如果 filePath 带有相对路径,而本地缓存中不存在这个路径,会下载失败,这个需求就要配合文件系统 API 才能满足了。

5. 文件系统

小游戏给开发者开放了很完整的文件系统接口,这点和浏览器中不支持文件 IO 的情况完全不同。一方面这给了开发者更大的自由度和发挥空间,但另一方面,这也是目前微信小游戏环境所必要的 API,因为微信小游戏环境不支持类似浏览器的资源缓存和资源过期机制。

具体来说,浏览器对于用户已经访问过的资源,会进行缓存,再次访问时,会优先从缓存获取,而不是发送请求给服务端,这样可以尽可能减少网络使用,优化页面响应速度。当服务端资源更新时,浏览器会发现本地资源已过期,自动清除对应本地资源并从服务端获取最新版本。

而在小游戏环境中,如果想要避免每次都从服务端获取资源,就需要自己实现一套类似的资源缓存和过期方案,这样的方案就不得不依赖于上面的下载接口以及文件系统接口。好消息是,Cocos Creator 提供了一套完整的资源管理方案,我们会在下一篇分享中详细讨论。

要理解小游戏的文件系统,首先要理解小游戏的文件沙盒环境:

小游戏的文件沙盒环境

所有的文件系统接口,都是在这个文件沙盒环境中执行的,所有的文件目录也是相对于沙盒环境的,所以我们不用担心不同小游戏或者不同用户之间的文件冲突。

从 API 使用的角度来说,所有文件系统接口都是由 FileSystemManager 来提供的,开发者需要首先通过

let fs = wx.getFileSystemManager();

来获取 FileSystemManager 对象,然后调用它的 API 来完成需要的功能,下面通过下载、读取、删除文件流程展示 API 的用法

以上只是最基本的一些接口使用。除此之外,微信小游戏还提供了 renameFile、copyFile、readdir、writeFile 等,大家可以参考 API 文档自行探索。细心的开发者还会注意到这些接口大多包含同步版本,比如 fs.readFileSync,我们建议一律使用异步版本的接口,否则文件 IO 造成的阻塞会影响到游戏运行的流畅度和游玩体验,相比之下,显然编写异步代码这点麻烦还是可以承受的。

6.小游戏的资源管理

除了前两篇中提到的 API 级别的差异以外,小游戏环境和浏览器环境的另一大差异就是资源管理了。

资源加载

首先是资源加载的差异,我们通过首场景加载的流程来展示这种差异:

在浏览器中始终遵循按需加载的原则,执行到加载的标签或者脚本,才会去作出网络请求加载内容。而在小游戏中,会首先下载你提交的完整游戏包,再运行 game.js 来启动游戏。所谓完整游戏包,也就是开发者在微信开发者工具中所导入的资源,不管你是否需要这些资源,在玩家打开你的小游戏时,都会被完整下载。所以为了首场景加载的体验,我们应该尽可能减小自己的小游戏包体,将可以按需加载的资源,放在远程服务器上,用脚本进行加载。微信团队也考虑到了首场景加载体验,所以将小游戏包体限制在了 4mb。下面是具体的小游戏包体方面的限制:

  • 小游戏的包内体积不能够超过 4mb,包含所有代码和资源,额外的资源必须通过网络请求下载;

  • 对于小游戏包内资源,小游戏环境内并不是按需加载的,而是一次性加载所有包内资源,然后再启动页面;

  • 不可以从远程服务器下载脚本文件。

基于这些限制,我们给出的建议就是,将所有引擎和游戏脚本,放在小游戏包内,同时可以将首场景资源或者预加载场景资源放在包内。其他资源都应该放在远程服务器上。

缓存与更新机制

资源管理上的第二点差异我们在第二篇文章中也提到过,对于从远程服务器下载的文件,小游戏环境没有浏览器的缓存以及过期更新机制。

众所周知,浏览器对于用户已经访问过的资源,会进行缓存,再次访问时,会优先从缓存获取,而不是发送请求给服务端,这样可以尽可能减少网络使用,优化页面响应速度。微信小游戏环境所提供的接口则是更为基础的文件系统接口:

  • wx.downloadFile:下载文件到缓存文件

  • FileSystemManager.saveFile:保存缓存文件

  • FileSystemManager.access:判断文件/目录是否存在

  • FileSystemManager.readFile:读取本地文件内容

  • FileSystemManager.unlink:删除文件

基于以上接口来实现浏览器的缓存方案当然是可行的,但是对于普通开发者来说,太过于繁琐,所以我们为开发者提供了更完整的资源管理方案。

Cocos Creator 的资源管理方案

首先,微信内将小游戏的文件存储空间按照用户和游戏来划分。所有文件系统接口,都是在独立的文件沙盒环境中执行,所有的文件目录也是相对于沙盒环境的,所以不用担心不同小游戏或者不同用户之间的文件冲突。

在这个沙盒环境之下,Cocos Creator 为小游戏环境提供了一个 wxDownloader 对象用来加载远程资源。当用户给它设置 REMOTE_SERVER_ROOT 属性后,资源的加载流程就变成了下面这样:

  1. 检查资源是否在小游戏包内

  2. 不存在则查询本地缓存资源

  3. 如果没有缓存就从远程服务器下载

  4. 下载后保存到小游戏应用缓存内供再次访问时使用(按照资源相对路径保存)

只要用户保证 wxDownloader.REMOTE_SERVER_ROOT 路径下的资源相对路径与 Cocos Creator 发布的资源相对路径一致,那么再次访问同一个资源时,就会在小游戏的文件沙盒环境中找到对应的文件。这样就足够支撑游戏资源的加载和缓存需求了。

那么我们如何做到资源的更新呢?假设服务端资源内容更新了,而 url 没有变化,那么我们还是会优先使用缓存中的资源,岂不是就没有得到更新?的确如此,我们解决问题的思路,并不是从资源文件内容是否变化来判断,而是一旦内容变化就修改文件的 url。这点就依赖于 Cocos Creator 打包时的 md5Cache 功能,这个功能会在打包时给所有资源文件的文件名附加 md5 后缀,比如 example.png 变成 example.23j8s1.png,一旦文件内容变化,它的 md5 后缀自然会发生变化。而所有资源文件的相对路径,实际上是在运行时由 AssetLibrary 从 settings.js 中解析出来的。

在构建面板中勾选 MD5 Cache 选项

所以开发者只要更新了新的小游戏包,包含最新版本的 settings.js,那么所有资源的路径就得到了更新,自然会从服务端请求最新版本的资源。由此还可引申出多版本共存的方案,就是不同版本的游戏,指向不同的 wxDownloader.REMOTE_SERVER_ROOT 服务器路径,可以保障不同版本都可以访问,并且不会出现资源的冲突或缺失。

最后,如果想要在本地或非正式服务器上测试远程加载功能,需要在详情页面中勾选 "不检验安全域名、TLS 版本以及 HTTPS 证书"。

至此,Cocos Creator 对小游戏资源管理中,远程资源加载和更新就解释清楚了,虽然我们不希望用户感知到浏览器和小游戏环境的差异,不可否认的是,资源管理方面,用户仍然需要了解更多的细节,才能够更好保障自己的小游戏所带来的用户体验。

7.第三方库的使用

目前部分第三方库已经发现有很多不兼容小游戏环境了,这里可以分享一个判断原则,如果是纯 JS 库,那么是没问题的,但是如果第三方库使用到了 DOM API,多半是无法支持。举几个例子:

  1. lodash:纯 JS 库,可以放心使用。

  2. jQuery:此类对 DOM API 有强依赖的第三方库肯定是无法支持的,也无法通过适配来支持。

  3. SocketIO:支持,但是需要取消勾选 ES6 转 ES5 避免闭包的运行环境被改变,这点适用于很多 node module。

  4. protobuf.js:protobuf.js 已经被验证是会出现问题的,因为它包含了加载的逻辑,这部分逻辑需要适配到微信小游戏的 API 才可以使用。

8. Unity开发小游戏 (推荐使用团结引擎 + InstantGame)

团结引擎 - 手册: 微信小游戏

引用网址:

https://zhuanlan.zhihu.com/p/32826363

https://zhuanlan.zhihu.com/p/32950204

https://zhuanlan.zhihu.com/p/33026389

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丛小胖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值