转载自:http://www.cocoachina.com/bbs/read.php?tid=188226
使用TexturePacker可以将若干小图,合成一张大图,
生成的.png和.plist文件可以让cocos2dx解析。cocos2dx可以将这些小图从大图中“取出”。
如果反过来呢?
能否将这张大图分解出若干小图呢?
自然也是可以的。
使用TexturePacker编辑时,记得要保存.tps文件,也要保存好原来的单图,因为有可以会遇到之后要修改其中的某个单图的情况。
两年前,我遇到一个项目,这个项目最恐怖的地方就是,
美术和程序都找不到大图中的小图的原文件了。
因为不断修改,整个项目可以用“混乱”二字来形容,谁遇到过一个项目,程序和美工都找不到这个项目原来图片的情况?
而在这种混乱的情况下,竟然还要修改其中的一些单图。
此时,急需一个工具可以将那些小图从合成的大图中分解出来。
面临的难题就是,如何使用.plist和.png文件将这些小图分解出来。
既然cocos2dx可以通过.plist和.png分解出小图,
那么,直接使用cocos2dx来当成这个分解工具不就可以了吗?
源代码引用 开始
void CCSpriteFrameCache::addSpriteFramesWithFile(const char *pszPlist)
{
CCAssert(pszPlist, "plist filename should not be NULL");
if (m_pLoadedFileNames->find(pszPlist) == m_pLoadedFileNames->end())
{
std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszPlist);
CCDictionary *dict = CCDictionary::createWithContentsOfFileThreadSafe(fullPath.c_str());
string texturePath("");
CCDictionary* metadataDict = (CCDictionary*)dict->objectForKey("metadata");
if (metadataDict)
{
// try to read texture file name from meta data
texturePath = metadataDict->valueForKey("textureFileName")->getCString();
}
if (! texturePath.empty())
{
// build texture path relative to plist file
texturePath = CCFileUtils::sharedFileUtils()->fullPathFromRelativeFile(texturePath.c_str(), pszPlist);
}
else
{
// build texture path by replacing file extension
texturePath = pszPlist;
// remove .xxx
size_t startPos = texturePath.find_last_of(".");
texturePath = texturePath.erase(startPos);
// append .png
texturePath = texturePath.append(".png");
CCLOG("cocos2d: CCSpriteFrameCache: Trying to use file %s as texture", texturePath.c_str());
}
CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(texturePath.c_str());
if (pTexture)
{
addSpriteFramesWithDictionary(dict, pTexture);
m_pLoadedFileNames->insert(pszPlist);
}
else
{
CCLOG("cocos2d: CCSpriteFrameCache: Couldn't load texture");
}
dict->release();
}
}
源代码引用 结束
重点在于这条语句 addSpriteFramesWithDictionary(dict, pTexture);
将解析后的.plist信息进一步处理。
源代码引用 开始
void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary* dictionary, CCTexture2D *pobTexture)
{
/*
Supported Zwoptex Formats:
ZWTCoordinatesFormatOptionXMLLegacy = 0, // Flash Version
ZWTCoordinatesFormatOptionXML1_0 = 1, // Desktop Version 0.0 - 0.4b
ZWTCoordinatesFormatOptionXML1_1 = 2, // Desktop Version 1.0.0 - 1.0.1
ZWTCoordinatesFormatOptionXML1_2 = 3, // Desktop Version 1.0.2+
*/
CCDictionary *metadataDict = (CCDictionary*)dictionary->objectForKey("metadata");
CCDictionary *framesDict = (CCDictionary*)dictionary->objectForKey("frames");
int format = 0;
// get the format
if(metadataDict != NULL)
{
format = metadataDict->valueForKey("format")->intValue();
}
// check the format
CCAssert(format >=0 && format <= 3, "format is not supported for CCSpriteFrameCache addSpriteFramesWithDictionary:textureFilename:");
CCDictElement* pElement = NULL;
CCDICT_FOREACH(framesDict, pElement)
{
CCDictionary* frameDict = (CCDictionary*)pElement->getObject();
std::string spriteFrameName = pElement->getStrKey();
CCSpriteFrame* spriteFrame = (CCSpriteFrame*)m_pSpriteFrames->objectForKey(spriteFrameName);
if (spriteFrame)
{
continue;
}
if(format == 0)
{
float x = frameDict->valueForKey("x")->floatValue();
float y = frameDict->valueForKey("y")->floatValue();
float w = frameDict->valueForKey("width")->floatValue();
float h = frameDict->valueForKey("height")->floatValue();
float ox = frameDict->valueForKey("offsetX")->floatValue();
float oy = frameDict->valueForKey("offsetY")->floatValue();
int ow = frameDict->valueForKey("originalWidth")->intValue();
int oh = frameDict->valueForKey("originalHeight")->intValue();
// check ow/oh
if(!ow || !oh)
{
CCLOGWARN("cocos2d: WARNING: originalWidth/Height not found on the CCSpriteFrame. AnchorPoint won't work as expected. Regenrate the .plist");
}
// abs ow/oh
ow = abs(ow);
oh = abs(oh);
// create frame
spriteFrame = new CCSpriteFrame();
spriteFrame->initWithTexture(pobTexture,
CCRectMake(x, y, w, h),
false,
CCPointMake(ox, oy),
CCSizeMake((float)ow, (float)oh)
);
}
else if(format == 1 || format == 2)
{
CCRect frame = CCRectFromString(frameDict->valueForKey("frame")->getCString());
bool rotated = false;
// rotation
if (format == 2)
{
rotated = frameDict->valueForKey("rotated")->boolValue();
}
CCPoint offset = CCPointFromString(frameDict->valueForKey("offset")->getCString());
CCSize sourceSize = CCSizeFromString(frameDict->valueForKey("sourceSize")->getCString());
// create frame
spriteFrame = new CCSpriteFrame();
spriteFrame->initWithTexture(pobTexture,
frame,
rotated,
offset,
sourceSize
);
}
else if (format == 3)
{
// get values
CCSize spriteSize = CCSizeFromString(frameDict->valueForKey("spriteSize")->getCString());
CCPoint spriteOffset = CCPointFromString(frameDict->valueForKey("spriteOffset")->getCString());
CCSize spriteSourceSize = CCSizeFromString(frameDict->valueForKey("spriteSourceSize")->getCString());
CCRect textureRect = CCRectFromString(frameDict->valueForKey("textureRect")->getCString());
bool textureRotated = frameDict->valueForKey("textureRotated")->boolValue();
// get aliases
CCArray* aliases = (CCArray*) (frameDict->objectForKey("aliases"));
CCString * frameKey = new CCString(spriteFrameName);
CCObject* pObj = NULL;
CCARRAY_FOREACH(aliases, pObj)
{
std::string oneAlias = ((CCString*)pObj)->getCString();
if (m_pSpriteFramesAliases->objectForKey(oneAlias.c_str()))
{
CCLOGWARN("cocos2d: WARNING: an alias with name %s already exists", oneAlias.c_str());
}
m_pSpriteFramesAliases->setObject(frameKey, oneAlias.c_str());
}
frameKey->release();
// create frame
spriteFrame = new CCSpriteFrame();
spriteFrame->initWithTexture(pobTexture,
CCRectMake(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height),
textureRotated,
spriteOffset,
spriteSourceSize);
}
// add sprite frame
m_pSpriteFrames->setObject(spriteFrame, spriteFrameName);
spriteFrame->release();
}
}
源代码引用 结束
现在,通过 std::string spriteFrameName = pElement->getStrKey();,
知道了这张单图的名字,
也获取了这张单图的 CCSpriteFrame ,
通过之前那篇文章提到的方法,
static CCRenderTexture* getRenderTexture(int widthP,int heightP,CCNode* nodeP,float node_xP,float node_yP);
//
CCRenderTexture* JarodGameTools:: getRenderTexture(int widthP,int heightP,CCNode* nodeP,float node_xP,float node_yP)
{
CCRenderTexture *rt = CCRenderTexture::create(widthP, heightP);
//
rt->begin();
nodeP->setPosition(node_xP,node_yP);
nodeP->visit();
rt->end();
//
return rt;
}
static bool createPng(const char* pngName,CCRenderTexture* textureP);
//
bool JarodGameTools:: createPng(const char* pngName,CCRenderTexture* textureP)
{
CCImage* image = textureP->newCCImage();
return image->saveToFile(pngName,false);
}
直接就可以将读入的所有.plist文件分解成原来的小图了。
现在,我不再使用这种方式了,原因是,
我选择使用保存单图和.tps的方式。
现在,给出一个 自己测试后运行正确的代码
//--------------------------------------------------------------------------------------------------------------------------------------------
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("stageA.plist");
//第一步,载入一个plist
CCSpriteFrame* buttonBgFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( "buttonBg.png" );
//第二步,根据名称提取出 frame
CCSize sizeTemp = buttonBgFrame->getOriginalSize();
//第三步,获取单图的尺寸
CCSprite* buttonBgSprite = CCSprite::createWithSpriteFrame(buttonBgFrame);
//创建一个 sprite
CCRenderTexture* testT = JarodGameTools::getRenderTexture(sizeTemp.width,sizeTemp.height,buttonBgSprite,sizeTemp.width/2,sizeTemp.height/2);
//将这个sprite绘制在图片的几何中心点的位置,因为锚点默认是 (0.5,0.5 )
JarodGameTools::createPng("testButtonBg.png",testT);
//将这个图片取一个名字,然后提取出来。
//----------------------------------------------------------------------------------------------------------------------------------------------