使用cocos2d-x制作 Texture unpacker
使用cocos2d-x制作 Texture unpacker没错,就是unpacker。 1. 解析plist文件cocos2d-x引擎中实现了解析plist纹理的逻辑,SpriteFrameCache类。可以看到SpriteFrameCache解析plist后,使用 SpriteFrameCache类没有提供获取_spriteFrames的接口,那么我们更改一下SpriteFrameCache类,提供一个获取该成员的接口即可: const Map<std::string,SpriteFrame*>& SpriteFrameCache::getSpriteframes()
{
return _spriteFrames;
}
2. 生成图片从SpriteFrameCache中获取到的是SpriteFrame,SpriteFrame是不能直接保存的,所以我们需要将它渲染到一张纹理上,再保存。 1) 将SpriteFrame渲染成一张纹理由于在cocos3.x版本中渲染方式已经和2.x版本中的方式不一样了(使用渲染命令,而非2.x版本中的直接渲染),所以在生成纹理的时候需要注意一下: Sprite* pSp = Sprite::createWithSpriteFrame(pSpriteFrame /*one sprite frame*/);
RenderTexture* texture = RenderTexture::create(pSp->getContentSize().width,pSp->getContentSize().height);
texture->setName(m_savePath + tempBuf);
texture->begin();
pSp->setPosition(pSp->getContentSize()/2); //--- be careful
pSp->visit();
texture->end();
以上代码只是添加了渲染纹理的命令,真正渲染完成这张纹理是在下一帧的时候,所以添加一个schedule,在下一帧将这个texture保存为图片。 2) 保存为图片Image* image = texture->newImage(true); //frame渲染出的一个texture
if (image)
{
image->saveToFile("filename.png",false);
}
CC_SAFE_DELETE(image);
其实RenderTexture类提供了saveToFile的接口,为什么没有直接调用?因为该接口会将图片保存在doc目录下,我想在win32上把它保存在其他磁盘。 3. 除去无效图片由于打纹理图集的时候,添加了一下加密操作,这样会导致plist文件里面解析出来会有很多无效图片(如:宽高只有1像素,多张完全一样的图片),明明有效图片只有10多张,解析出来后有几十张 1) 去除宽高只有1像素的frameplist中的配置: <key>1002_effup/0000</key> <dict> <key>frame</key> <string>{{440,56},{1,1}}</string> <key>offset</key> <string>{-479.5,319.5}</string> <key>rotated</key> <false/> <key>sourceColorRect</key> <string>{{0,0},1}}</string> <key>sourceSize</key> <string>{960,640}</string> </dict> <key>1002_effup/0001</key> <dict> <key>frame</key> <string>{{440,640}</string> </dict>
如上这两个frame宽高都是1像素,解析出来是无用的,所以需要剔除。 2) 去除重复的图片plist中的配置: <key>1002_effup/0010</key> <dict> <key>frame</key> <string>{{440,{102,88}}</string> <key>offset</key> <string>{5,7}</string> <key>rotated</key> <false/> <key>sourceColorRect</key> <string>{{363,355},{212,50}}</string> <key>sourceSize</key> <string>{960,640}</string> </dict> <key>1002_effup/0093</key> <dict> <key>frame</key> <string>{{440,640}</string> </dict>
如上所以,除了frame名称,其它字段均相同,这样的图片保存一张即可。 那么如何实现呢? Map<std::string,SpriteFrame*> framesMap = SpriteFrameCache::getInstance()->getSpriteframes();
for (Map<std::string,SpriteFrame*>::const_iterator itor = framesMap.begin(); itor != framesMap.end(); ++itor)
{
SpriteFrame* frame = itor->second;
GLuint textName = frame->getTexture()->getName();
const Rect& rect = frame->getRectInPixels();
bool isRotate = frame->isRotated();
const Vec2& offset = frame->getOffsetInPixels();
const Size& origSize = frame->getOriginalSizeInPixels();
// 去掉 过小的无效图片 (加密后?的plist会生成很多无效图片)
// #define INVALID_IMAGE_WIDTH 2
if (rect.size.width <= INVALID_IMAGE_WIDTH && rect.size.height <= INVALID_IMAGE_HEIGHT)
{
continue;
}
// key --- 去掉重复的图片 (加密后?的plist会有很多张重复图片)
sprintf(fileKeyBuf,"%d_%.1f%.1f%.1f%.1f_%s_%.1f%.1f_%.1f%.1f",textName,rect.origin.x,rect.origin.y,rect.size.width,rect.size.height,isRotate ? "1" : "0",offset.x,offset.y,origSize.width,origSize.height);
if (m_textureList.find(fileKeyBuf) != m_textureList.end())
{
continue;
}
Sprite* pSp = Sprite::createWithSpriteFrame(itor->second);
RenderTexture* texture = RenderTexture::create(pSp->getContentSize().width,pSp->getContentSize().height);
texture->setName(itor->first + ".png");
texture->begin();
pSp->setPosition(pSp->getContentSize()/2); //--- be careful
pSp->visit();
texture->end();
m_textureList.insert(fileKeyBuf,texture);
++m_iFramesCount;
}
4. 按顺序重命名当执行完上面第三步(删除无效、冗余图片)后,保存的每一个frame会出现不连续的情况。 如:frame0001.png过后就是frame0008.png 那么我们在保存图片的时候,就要重命名每一个frame,用m_iFramesCount记录当前是第几个了,然后根据它命名即可。 5. 说明该功能已经封装为一个类,放在github上了,需要的朋友可以自己去clone一份。 PlistTool *tool = new PlistTool();
std::vector<std::string> vec;
vec.push_back("Enemy.plist");
vec.push_back("1001_effup.plist");
tool->addUnpackList(vec);
tool->startUnpack([](){
MessageBox("unpack finished","info");
});
这样就会在当前目录生成两个文件夹,存放两个plist解包出来的小图。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |