使用cocos2d-js做项目,遇到cc.ParticleSystem加载plist文件失败,一般是以下几个原因造成的:一般都是发生在网页调试,vs的win32平台和手机原生平台运行正常,问题就定位到cocos-html的js文件中。一般都是发生在只有plist文件,没有plist文件对应的png文件的时候(plist粒子文件是用cocos studio生成的)。
- 首先plist文件需要预加载,否则在initWithFile时,获取的plist文件信息为空。
initWithFile: function (plistFile) { this._plistFile = plistFile; var dict = cc.loader.getRes(plistFile); if (!dict) { cc.log("cc.ParticleSystem.initWithFile(): Particles: file not found"); return false; } // XXX compute path from a path, should define a function somewhere to do it return this.initWithDictionary(dict, ""); },
因为cc.loader.getRes()是从cc.cahe中获取文件信息的。
getRes: function (url) { return this.cache[url] || this.cache[_aliases[url]]; },
- 如果plist粒子文件中不包含png的base64编码信息,那么需要将文件用到的png文件也添加到预加载里面去,最好是在plist之前预加载。
- 如果plist粒子文件中包含了png的base64编码信息,那么其实是可以不用把plist用到的png文件添加进来的,通常创建粒子后在网页端不显示就是这种情况下发生的。
if (tex) { this.setTexture(tex); } else { var textureData = locValueForKey("textureImageData", dictionary); if (!textureData || textureData.length === 0) { tex = cc.textureCache.addImage(imgPath); if (!tex) return false; this.setTexture(tex); } else { buffer = cc.unzipBase64AsArray(textureData, 1); if (!buffer) { cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData"); return false; } var imageFormat = cc.getImageFormatByData(buffer); if (imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG) { cc.log("cc.ParticleSystem: unknown image format with Data"); return false; } var canvasObj = document.createElement("canvas"); if (imageFormat === cc.FMT_PNG) { var myPngObj = new cc.PNGReader(buffer); myPngObj.render(canvasObj); } else { var myTIFFObj = cc.tiffReader; myTIFFObj.parseTIFF(buffer, canvasObj); } cc.textureCache.cacheImage(imgPath, canvasObj); var addTexture = cc.textureCache.getTextureForKey(imgPath); if (!addTexture) cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture"); this.setTexture(addTexture); } }
通过cc.ParticleSystem类的initWithDictionary方法可以看出来,将图片添加到预加载后,tex就不是从base64编码中获取的了,而是直接读取图片文件的。所以问题出现在base64解码方法里,断点后的结果显示是cc.unzipBase64AsArray的cc.unzipBase64报错:
cc.unzipBase64 = function () { var tmpInput = cc.Codec.Base64.decode.apply(cc.Codec.Base64, arguments); return cc.Codec.GZip.gunzip.apply(cc.Codec.GZip, [tmpInput]); };
cc.Codec.GZip.gunzip = function (string) { if (string.constructor === Array) { } else if (string.constructor === String) { } var gzip = new cc.Codec.GZip(string); return gzip.gunzip()[0][0]; };
cc.Codec.GZip.prototype.gunzip = function () { this.outputArr = []; //convertToByteArray(input); //if (this.debug) alert(this.data); this.nextFile(); return this.unzipped; };
而cc.Codec.GZip.prototype.nextFile方法里出现了如下代码:
if (tmp[0] === 0x78 && tmp[1] === 0xda) { //GZIP if (tmp[0] === 0x1f && tmp[1] === 0x8b) { //GZIP if (tmp[0] === 0x50 && tmp[1] === 0x4b) { //ZIP
0x1f,0x8b等等是用来判断压缩标准的,问题就出在这里:读取的plist文件里的base64解码后解压时读取到头是0x78和0x9c,原来的代码里没有这个选择语句,解决办法就是添加一个选择语句,判断条件为0x78和0x9c,解压逻辑复制0x78和0xda的就好了。这样网页调试就可以根据plist创建出粒子了。
写在最后:
其实就两种方法:
- 将plist文件对应的png文件也添加到预加载中;
- 修改js代码。
现在用cocos-js的人少了,这篇博客估计也没多少人看吧。