使用CCTMXLayer做了一个小测试,需要经常添加或移除tile,添加时使用方法setTileGID,移除时使用方法removeTileAt。为了使tile在出现时有些效果,使用tileAt方法获取sprite。
问题: tileAt发生各种奇怪的问题,如本该移除的tile没有移除,在移除(0,0)的tile时报错等。不使用tileAt获取sprite则一切正常。
检查发现CCTMXLayer继承自CCSpriteBatchNode,sprite只有在tileAt时才会创建,在删除tile时是如果sprite存在使用这行代码:
CCSpriteBatchNode::removeChild(sprite, true);
继续跟踪找到这个函数void CCSpriteBatchNode::removeSpriteFromAtlas(CCSprite *pobSprite);
其中如下这段代码:
// update all sprites beyond this one
unsigned int count = m_pobDescendants->count();
for(; uIndex < count; ++uIndex)
{
CCSprite* s = (CCSprite*)(m_pobDescendants->objectAtIndex(uIndex));
s->setAtlasIndex( s->getAtlasIndex() - 1 );
}
觉得有问题,它的逻辑是将m_pobDescendants中排在待删除对象后面的sprite的atlasIndex减1;而实际的需求应当是将m_pobDescendants中所有atlasIndex大于或等于待删除对象的atlasIndex减1;把整个函数修改一下:
void CCSpriteBatchNode::removeSpriteFromAtlas(CCSprite *pobSprite)
{
unsigned int popSpriteAtlasIndex=pobSprite->getAtlasIndex();
// remove from TextureAtlas
m_pobTextureAtlas->removeQuadAtIndex(pobSprite->getAtlasIndex());
// Cleanup sprite. It might be reused (issue #569)
pobSprite->useSelfRender();
unsigned int uIndex = m_pobDescendants->indexOfObject(pobSprite);
if (uIndex != UINT_MAX)
{
m_pobDescendants->removeObjectAtIndex(uIndex);
// update all sprites beyond this one
unsigned int count = m_pobDescendants->count();
//{sayid
for(int i=0; i < count; i++)
{
CCSprite* s = (CCSprite*)(m_pobDescendants->objectAtIndex(i));
if( s->getAtlasIndex()>=popSpriteAtlasIndex)
s->setAtlasIndex( s->getAtlasIndex() - 1 );
}
//}
}
// remove children recursively
CCArray *pChildren = pobSprite->getChildren();
if (pChildren && pChildren->count() > 0)
{
CCObject* pObject = NULL;
CCARRAY_FOREACH(pChildren, pObject)
{
CCSprite* pChild = (CCSprite*) pObject;
if (pChild)
{
removeSpriteFromAtlas(pChild);
}
}
}
}
发现一切症状消除,其它相关的逻辑没仔细看,也不知道这样改有风险没。。。。