效果图如下:





无论是按钮(control button),还是普通的label都有小概率出现这种情况。

该问题发现于cocos2d-x3.7

原因:

在3.x中使用ttfconfig创建的label,为了性能是创建了缓存的,字体纹理缓存的大小默认是512*512(不同版本大小可能不一样)

//CCFontAtlas.cpp
const int FontAtlas::CacheTextureWidth = 512;
const int FontAtlas::CacheTextureHeight = 512;

v3.7的label继承于batchnode:class CC_DLL Label : public SpriteBatchNode, public LabelProtocol,且有一个存放batchnode数组的成员变量std::vector<SpriteBatchNode*> _batchNodes;,这个数组的第一个元素就是cclabel自己,当一张512*512大小的字体纹理缓存不够用时,会再创建一个,此时就是push_back到这个数组中。该batchnode数组会在绘制使用ttfconfig创建的字体时被使用。

那么,问题主要在于当改变字体大小,或者改变字体,都会调用函数void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false */, bool useA8Shader /* = false */),该函数会重置字体的纹理缓存:

void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false */, bool useA8Shader /* = false */)
{
if (atlas == _fontAtlas)
{
FontAtlasCache::releaseFontAtlas(atlas);
return;
} if (_fontAtlas)
{
FontAtlasCache::releaseFontAtlas(_fontAtlas);
_fontAtlas = nullptr;
} _fontAtlas = atlas; if (_textureAtlas)
{
//这里重置了_batchNodes的第一个元素的问题,也就是cclabel自己,
//那么如果之前缓存了多个纹理,即_batchNodes.size>1,
//其他的纹理就还没有被释放!!!
_textureAtlas->setTexture(_fontAtlas->getTexture(0));
}
else
{
SpriteBatchNode::initWithTexture(_fontAtlas->getTexture(0), 30);
} //...
}

再来看一下_batchNodes添加新的缓存纹理相应的代码:

void Label::alignText()
{
if (_fontAtlas == nullptr || _currentUTF16String.empty())
{
setContentSize(Size::ZERO);
return;
} _fontAtlas->prepareLetterDefinitions(_currentUTF16String);
auto& textures = _fontAtlas->getTextures(); //如果上面旧的缓存一直没有释放,
//那么当新的字体纹理缓存创建第二个时,不会被更新!!!
//所以你看到的文字就是错乱的!
if (textures.size() > _batchNodes.size())
{
for (auto index = _batchNodes.size(); index < textures.size(); ++index)
{
auto batchNode = SpriteBatchNode::createWithTexture(textures.at(index));
batchNode->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT);
batchNode->setPosition(Vec2::ZERO);
Node::addChild(batchNode,0,Node::INVALID_TAG);
_batchNodes.push_back(batchNode);
}
}
//.......
}

根据上面的分析,其实可以发现,出现的这个bug的概率是很小的:

  1. 首先得用ttfconfig创建一个label,且显示过大量文字,导致创建了第二个缓存纹理
  2. 然后更换字体,或者更改字体大小(setTTFSize)
  3. 更改后的label显示过大量文字,导致创建第二个缓存纹理,如果显示了第二个纹理上的文字就会是错乱的。

解决方案:

因为更换字体、更改字体大小等,都会更换新的纹理(setFontAtlas),那么我们只用在该函数中重置_batchNodes即可:

void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false */, bool useA8Shader /* = false */)
{
if (atlas == _fontAtlas)
{
FontAtlasCache::releaseFontAtlas(atlas);
return;
} if (_fontAtlas)
{
FontAtlasCache::releaseFontAtlas(_fontAtlas);
_fontAtlas = nullptr;
} _fontAtlas = atlas; if (_textureAtlas)
{
_textureAtlas->setTexture(_fontAtlas->getTexture(0));
}
else
{
SpriteBatchNode::initWithTexture(_fontAtlas->getTexture(0), 30);
} //issue: text disorder
_batchNodes.clear();
_batchNodes.push_back(this); //...
}

v3.10

github上已经有3.10的代码,看了一下cclabel,已经重构了,label不再继承BatchNode

class CC_DLL Label : public Node, public LabelProtocol, public BlendProtocol

而每一个文字使用:class LabelLetter : public Sprite

看了一下setFontAtlas函数,上述的bug已经不存在了

void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false */, bool useA8Shader /* = false */)
{
if (atlas == _fontAtlas)
{
FontAtlasCache::releaseFontAtlas(atlas);
return;
} if (_fontAtlas)
{
_batchNodes.clear(); //这里已经重置
FontAtlasCache::releaseFontAtlas(_fontAtlas);
_fontAtlas = nullptr;
} _fontAtlas = atlas;
//.....
}

cocos2d-x3.7 cclabel文字破碎,异常,变乱的更多相关文章

  1. cocos2d-x在IOS7下面文字显示异常的解决办法 CGBitmapContextCreate: unsupported parameter combination

    首先定位到libs-->cocos2dx-->platform-->iOS-->CCImage.mm 找到这个文件. 打开CCImage.mm文件,定位到如下函数:   [cp ...

  2. [cocos2d] 显示状态与文字

    前言: 对于显示数值与文字一般有三种方式可以使用: CCLabelTTF .CCLabelBMFont .CCLabelAtlas 详细区别可参考:cocos2d 中添加显示文字的三种方式(CCLab ...

  3. cocos2d 中加入显示文字的三种方式(CCLabelTTF 、CCLabelBMFont 和CCLabelAtlas)

    在 cocos2d 中有三个类能够在层或精灵中加入文字: CCLabelTTF CCLabelBMFont CCLabelAtlas      CCLabelTTF CCLabelTTF 每次调用 s ...

  4. 完美解决移动Web小于12px文字居中的问题

    前几天的一篇博文:移动Web单行文字垂直居中的问题,提到了移动web里小于12px的文字居中异常的问题,最后还是改为12px才近乎解决了问题.但是有时候或许并不是那么乐观,你并不能将原本定为10px的 ...

  5. Canvas 笔记(持续更新中)

    1.从线条开始 HTML <canvas id="canvas"></canvas> Javascript var canvas=document.getE ...

  6. cocos2d-x学习知识点记录

    环境搭建 http://4137613.blog.51cto.com/4127613/751149 Cocos2d-x初探,HelloWorld解读 http://www.cnblogs.com/Ke ...

  7. pytest自动化7:assert断言

    前言:assert断言就是将实际结果和期望结果做对比,符合预期结果就测试pass,不符合预期就测试failed. 实例1:简单断言 实例1优化版--增加异常信息文字描述 异常断言 excinfo 是一 ...

  8. 移动端网页使用flexible.js加入百度联盟广告样式不一致问题解决

    flexible.js是淘宝推出的一款移动端手机自适应的库,源码内容很简洁,当网页使用了该库之后,页面会在head中加入对应的页面响应式的meta标签. 当使用flexible.js的时候,引入百度联 ...

  9. Android自定义控件练手——简单的时钟

    首先这应该是一个老生常谈的设计了,但是毕竟身为小白的自己都没动手做过,不动手怎么提高自己呢,所以在这梅林沉船闲暇之际,我就把我的设计流程与思路记录下来.首先来看看效果图吧: 如上图就是一个简单并没有美 ...

随机推荐

  1. BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  2. Linux学习总结(十)-文件复制及查看, 环境变量

    一 文件复制及移动 1.命令 cp --------copy 的意思格式 cp 选项 源文件 目标文件a: 对于文件我们直接cp 文件 目标文件假定我们在普通用户家目录下/home/lv新建两个普通文 ...

  3. 前端使用ajax传到后台的实体类的多个属性,直接用Map接收

    前端ajax传过来的数据按照以上方法接收Map中 var ip = $("#ip").val(); var port = $("#port").val(); v ...

  4. 支持向量机通俗导论(理解SVM的三层境界)[转]

    作者:July .致谢:pluskid.白石.JerryLead.说明:本文最初写于2012年6月,而后不断反反复复修改&优化,修改次数达上百次,最后修改于2016年11月.声明:本文于201 ...

  5. 算法是什么(二)手写个链表(java)

    算法是什么(二)手写个链表(java)   liuyuhang原创,未经允许禁止转载 目录 算法是什么(〇) 很多语言的API中都提供了链表实现,或者扩展库中实现了链表. 但是更多的情况下,Map(或 ...

  6. Drbd双机环境安装配置

    一.环境准备 1) 操作系统:ubuntu-14.04.1 x64 2) Ubuntu1 192.168.5.179 /dev/sdb1 主节点 Ubuntu2 192.168.5.178 /dev/ ...

  7. App 运行后屏幕顶部和底部各留黑边问题 - iOS

    App 启动后屏幕的顶部和底部各产生一条黑边,App 的内容会被压缩在两个黑条内显示,比例失调的情况. 初步判断是启动页资源图片适配问题. 首先,查看工程 project => General ...

  8. vue 样式渲染,添加删除元素

    <template> <div> <ul> <li v-for="(item,index) in cartoon" :key=" ...

  9. mysql的char,varchar,text,blob

    mysql的char,varchar,text,blob是几个有联系但是有有很大区别的字段类型,这算是mysql的基础吧,可是基础没有学好,恶补一下. 先简单的总结一下: char:定长,最大255个 ...

  10. 20190118-利用Python实现Pig Latin游戏

    1.利用Python实现Pig Latin字母游戏 “Pig Latin”是一个英语儿童文字改写游戏,整个游戏遵从下述规则:a. 元音字母是‘a’.‘e’.‘i’.‘o’.‘u’.字母‘y’在不是第一 ...