当 Creator 遇上 protobuf.js|升级版
Posted COCOS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当 Creator 遇上 protobuf.js|升级版相关的知识,希望对你有一定的参考价值。
当 a.proto 文件中 import 了 b.proto 文件,在成功加载 a.proto 文件后内部解析 a.proto 时会自动加载 b.proto,此时会触发 XMLHttpRequest API 的调用,导致在微信小游戏环境出现错误。
还是从 protobuf.js 源码入手,我增加了一些注释,方便理解:
从源码中可以看出,protobuf.js 有两种加载模式:同步与异步。
我们曾分析过 ProtoBuf.Util.fetch 函数,这里简单回顾一下:
浏览器:使用 XMLHttpRequest 实现的同步、异步 proto 文件加载
nodejs:异步使用 fs.readFile,同步使用 fs.readFileSync
Cocos-JSB:我们介绍了伪装 fs 模块的办法调用 jsb.fileUtils.getStringFromFile 来解决
微信小游戏环境我的理解是:阉割+定制过的浏览器,它没有提供 XMLHttpRequest API,这是导致 protobuf.js 失败的原因。
后来我又尝试了在 protobufjs 6.x 中使用的方案,ProtoBuf.loadProtoFile 函数,使用 cc.loader.load 代替 ProtoBuf.Util.fetch,采用异步加载的方式,同样存在问题。
在遇到问题个人不能很好解决时,去逛一逛论坛是一个不错的想法。当我把问题一提出,第二天就有一位ID a1990091 的热心朋友提供了一个思路:重写 ProtoBuf.Util.fetch 函数,在函数中检查当前是否为微信小游戏环境,然后可以利用微信提供的 API 去实现加载:
此方法做的非常的漂亮,分别检测了 JSB、微信、Web 环境,提供不同的加载实现。可对我来说,遗憾是 pbkiller 库对外一直提供的是同步加载方法,改为异步加载,对已经使用 pbkiller 用户不太友好,同步、异步如取舍呢?
发完帖从论坛回到问题,不解决估计是睡不着了,头脑中一阵自言自语,忽然想到 cc.loader.getRes 同步获取资源的接口与 ProtoBuf.Util.fetch 的同步方式一样,能否从这里下手呢?
在这里先简单介绍一下 cc.loader 的系列 load 函数。
1. cc.loader.load(url, callback)
cc.loader.load 的 ur l参数是从项目发布的根路径开始的完整路径,因此需要借助 cc.url.raw 函数来获取完整路径。
例如:加载文件assets/resources/a.json
cc.loader.load 除了可以加载当前项目资源,更重要是加载其它远程服务器上的资源。只需给出完整路径即可,但在浏览器上使用需要注意跨域问题。
加载当前项目 resources 目录下的资源,使用 cc.loader.loadRes 更为简单。
更多用法请参考 API 文档:
docs.cocos.com/creator/api/zh/classes/loader.html#load
2. cc.loader.loadRes(url, callback)
cc.loader.loadRes 的 url 参数路径是以 resources 为根路径。
例如:加载文件 assets/resources/a.json
cc.loader.loadRes 的用法比 cc.loader.load 简单很多,也有没那么多参数重载的用法。
API文档链接:
http://docs.cocos.com/creator/api/zh/classes/loader.html#loadres
3. cc.loader.loadResDir(url, callback)
cc.loader.loadResDir 顾名思义它是加载一个目录(及子目录),url 同样以 assets/resources 目录作为根路径。
例如:加载文件 assets/resources/json 目录下有 a.json、b.json 两个文件
4. cc.loader.getRes(url)
cc.loader.getRes 是 cc.loader 家族中唯一的同步资源获取函数。但是它有一个前提,需要被 cc.loader.loadXXX 加载成功过的资源才能使用,不然它会返回 null。
例如:加载文件 assets/resources/json/a.json
这里分享一个查看 cc.loader 缓存资源的一个方法,在浏览器中运行你的项目,在调试控制台上输入:cc.loader._catch,你会看到如下内容:
cc.loader._catch 对象中的所有资源,都可以使用 cc.loader.getRes 获取。讲到此处,我猜你已经大概知道怎么使用 cc.loader.getRes 解决微信小游戏中 proto 的加载问题了。
从分析 cc.loader 的系列加载函数,cc.loader.getRes 去代替 ProtoBuf.Util.fetch,同样使用同步方式,这样 pbkiller.loadAll/ pbkiller.loadFromFile 的接口用法可以保持不变。
要想 cc.loader.getRes 的返回值有效,需要预先将资源加载到 cc.loader 的缓存中,因此提供了一个 pbkiller.preload 函数
简单几行代码解决了所有问题,而且没有修改 protobuf.js 任何一行源代码。再看下如何使用预加载函数:
在实际项目中可以提前执行 pbkiller.preload,以前所有 pbkiller 的用法保持不变,利用 javascript 的动态属性赋值,特别是可以修改函数指针,基本上可以做到为所欲为,而且不需要修改源代码,有没有觉得特别爽呢?
pbkiller 的内核是 protobuf.js,我所做的工作只是将 protobuf.js 适配到 Cocos-JSB 和微信小游戏环境,让其能正常工作。希望我的经验能对你有所帮助,愿 pbkiller 能为你节省时间,提高效率!
pbkiller 插件下载:
http://store.cocos.com/stuff/show/178929.html
pbkiller 使用流程视频介绍
以上是关于当 Creator 遇上 protobuf.js|升级版的主要内容,如果未能解决你的问题,请参考以下文章