公司最近的游戏上了AppleStore,打开游戏的详细页面。策划突然发现游戏好大啊。怎么显示的是347M,之前上的另外一款游戏,我们没有注意这块,只是光顾着玩了。而实际我们做出来的IPA只有140多M,咨询几个超级资深的IOS开发人员,AppleStore显示的是IPA展开后的大小。但是玩家不这么认为啊。以为下载的游戏这么大。为了减小大小,看来只要压缩原始文件大小了,经过分析,特做出以下的方法:
- 图片文件,声音文件,不压缩,因为压缩比几乎没有。
- 压缩相关的文本文件,Plist,Json文件。尤其是动画文件,我们用的是ExportJson格式。大的惊人
在这里,做了一下简单的文件格式定义,文件由三部分构成,如下
- 在每个压缩的文件头部加eraygames做压缩标记(9字节长),(用来判断文件是否压缩)
- 然后是四个字节描述压缩前的文件原始长度 (用来解压)
- 然后是文件压缩后的内容
资源的压缩,可以用Python脚本语言,在项目打包之前做运行一下命令即可,下面主要修改Cocos2d-x的引擎部分CCFileUtils,因为所有的文件加载全部在这个类里。而最终的入口在FileUtils::getContents方法里。当然其他平台,在对应的CCFileUtils-Android,CCFileUtils-win32,里。修改如下,在CCFileUtils.h头文件添加方法如下:
protected:
enum COMPRESS_CODE
{
noCompress = 0,
unCompressOK,
unCompressError,
};
COMPRESS_CODE checkIsCompressFile(ResizableBuffer* buffer,int size);
private:
int m_ITagLen;
int m_ISizeLen;
CCFileUtils.cpp如下:
FileUtils::COMPRESS_CODE FileUtils::checkIsCompressFile(ResizableBuffer* buffer, int size) {
if (size <= m_itaglen="" +="" m_isizelen)="" {="" return="" nocompress;="" }="" unsigned="" char="" *="" sdata="new" char[m_itaglen="" 1];="" memcpy(sdata,="" buffer-="">buffer(), m_ITagLen);
sData[m_ITagLen] = '\0';
std::string tag((char*)sData);
if (tag.find("eraygames") != std::string::npos) {
CC_SAFE_DELETE_ARRAY(sData);
sData = new unsigned char[m_ISizeLen];
memcpy(sData, (unsigned char*)buffer->buffer() + m_ITagLen, m_ISizeLen);
std::reverse(&sData[0], &sData[m_ISizeLen]);
uLong fileLen = 0;
memcpy(&fileLen, sData, m_ISizeLen);
CC_SAFE_DELETE_ARRAY(sData);
int compressSize = size - m_ITagLen - m_ISizeLen;
sData = new unsigned char[compressSize];
memcpy(sData, (unsigned char*)buffer->buffer() + m_ITagLen + m_ISizeLen, compressSize);
unsigned char* fileData = new unsigned char[fileLen];
bool isCompress = true;
do
{
if (uncompress(fileData, &fileLen, sData, compressSize) != Z_OK) {
isCompress = false;
break;
}
buffer->setBuffer(fileData, fileLen);
} while (0);
CC_SAFE_DELETE_ARRAY(sData);
CC_SAFE_DELETE_ARRAY(fileData);
if (!isCompress) {
CCLOG("UnCompress Error");
return unCompressError;
}
return unCompressOK;
}
return noCompress;
}
=>
然后修改对应的getContents方法。在方法最后一句的前面添加,我修改CCFileUtils-win32.cpp
FileUtils::Status FileUtilsWin32::getContents(const std::string& filename, ResizableBuffer* buffer)
{
// 此处省略其他代码
if (!successed) {
CCLOG("Get data from file(%s) failed, error code is %s", filename.data(), std::to_string(::GetLastError()).data());
buffer->resize(sizeRead);
return FileUtils::Status::ReadFailed;
}
FileUtils::COMPRESS_CODE code = checkIsCompressFile(buffer, size);
if (code == FileUtils::COMPRESS_CODE::unCompressError) {
return FileUtils::Status::ReadFailed;
}
return FileUtils::Status::OK;
}
最近项目升级引擎到3.13.1,以上所有的研究代码基于此版本