转:cocos2d-x里的TiledMap出现黑线和抖动的解决方案(不影响其他类使用)
本文转载自 cocos2d-x里的TiledMap出现黑线和抖动的解决方案(不影响其他类使用)
今天搞tiled map发现黑边,开始认为是反锯齿问题,但发现无论开启与否都有边,只是程度不同而已。简单网上搜了下发现有解决方案是 修改ccconfig.h让
#define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1
同时开启tile图块texture的反锯齿避免抖动。
但简单看了下CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL, 发现对texture coordinates作了圈限制。
这是原始的注释:
If enabled, the texture coordinates will be calculated by using this formula:
- texCoord.left = (rect.origin.x*2+1) / (texture.wide*2);
- texCoord.right = texCoord.left + (rect.size.width*2-2)/(texture.wide*2);
The same for bottom and top.
This formula prevents artifacts by using 99% of the texture.
The "correct" way to prevent artifacts is by using the spritesheet-artifact-fixer.py or a similar tool.
Affected nodes:
- CCSprite / CCSpriteBatchNode and subclasses: CCLabelBMFont, CCTMXTiledMap
- CCLabelAtlas
- CCQuadParticleSystem
- CCTileMap
可见影响了全部CCSprite,事实也发现Sprite只要使用的贴图是紧贴边的,周围都有可能都被切掉了一部分。
其实你只要解决tilemap的显示问题,就没必要去动到别的类。简单看了下加载tiledmap相关源码,其实只需很小改动。
首先不要改CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL, 让它仍然是0.
知道的是tiledmap显示部分要用到CCSprite,但这个CCSprite要CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL开启时的作用, 所以这里要新建个CCSprite的子类CCSpriteTileMap。
class CCSpriteTileMap : public CCSprite
{
protected:
virtual void setTextureCoords(CCRect rect);
};
void CCSpriteTileMap::setTextureCoords( CCRect rect )
{
rect = CC_RECT_POINTS_TO_PIXELS(rect);
CCTexture2D *tex = m_pobBatchNode ? m_pobTextureAtlas->getTexture() : m_pobTexture;
if (! tex)
{
return;
}
float atlasWidth = (float)tex->getPixelsWide();
float atlasHeight = (float)tex->getPixelsHigh();
float left, right, top, bottom;
if (m_bRectRotated)
{
#if 1//CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
left = (2*rect.origin.x+1)/(2*atlasWidth);
right = left+(rect.size.height*2-2)/(2*atlasWidth);
top = (2*rect.origin.y+1)/(2*atlasHeight);
bottom = top+(rect.size.width*2-2)/(2*atlasHeight);
#else
left = rect.origin.x/atlasWidth;
right = (rect.origin.x+rect.size.height) / atlasWidth;
top = rect.origin.y/atlasHeight;
bottom = (rect.origin.y+rect.size.width) / atlasHeight;
#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
if (m_bFlipX)
{
CC_SWAP(top, bottom, float);
}
if (m_bFlipY)
{
CC_SWAP(left, right, float);
}
m_sQuad.bl.texCoords.u = left;
m_sQuad.bl.texCoords.v = top;
m_sQuad.br.texCoords.u = left;
m_sQuad.br.texCoords.v = bottom;
m_sQuad.tl.texCoords.u = right;
m_sQuad.tl.texCoords.v = top;
m_sQuad.tr.texCoords.u = right;
m_sQuad.tr.texCoords.v = bottom;
}
else
{
#if 1//CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
left = (2*rect.origin.x+1)/(2*atlasWidth);
right = left + (rect.size.width*2-2)/(2*atlasWidth);
top = (2*rect.origin.y+1)/(2*atlasHeight);
bottom = top + (rect.size.height*2-2)/(2*atlasHeight);
#else
left = rect.origin.x/atlasWidth;
right = (rect.origin.x + rect.size.width) / atlasWidth;
top = rect.origin.y/atlasHeight;
bottom = (rect.origin.y + rect.size.height) / atlasHeight;
#endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
if(m_bFlipX)
{
CC_SWAP(left,right,float);
}
if(m_bFlipY)
{
CC_SWAP(top,bottom,float);
}
m_sQuad.bl.texCoords.u = left;
m_sQuad.bl.texCoords.v = bottom;
m_sQuad.br.texCoords.u = right;
m_sQuad.br.texCoords.v = bottom;
m_sQuad.tl.texCoords.u = left;
m_sQuad.tl.texCoords.v = top;
m_sQuad.tr.texCoords.u = right;
m_sQuad.tr.texCoords.v = top;
}
}
CCTileMapAtlas.cpp里
CCTileMapAtlas::updateAtlasValueAt 函数中将CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL强行开启
#if 1//CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
float left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide);
float right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide);
float top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh);
float bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh);
#else
float left = (row * itemWidthInPixels) / textureWide;
float right = left + itemWidthInPixels / textureWide;
float top = (col * itemHeightInPixels) / textureHigh;
float bottom = top + itemHeightInPixels / textureHigh;
#endif
然后找到CCTMXLayer类里面申请new CCSprite的地方替换成new CCSpriteTileMap就OK了。
发现有两处,在这两个函数内
CCTMXLayer::reusedTileWithRect
CCTMXLayer::tileAt
完工!重新BUILD,就看不见恶心的黑线了,同时也不影响别的类使用。
想想如果cocos2d出CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL这个定义最初目的是为了解决tiledmap显示问题的话,为什么不独立出一个针对tiledmap显示问题的编译项呢?当然还有其他目的就另当别论了。
注明下笔者用的cocos2d-x版本是2.1.5,其实2.0.0后版本应该都适用