cocos2d-x3.7 cclabel文字破碎,异常,变乱
效果图如下:
无论是按钮(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的概率是很小的:
- 首先得用ttfconfig创建一个label,且显示过大量文字,导致创建了第二个缓存纹理
- 然后更换字体,或者更改字体大小(setTTFSize)
- 更改后的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文字破碎,异常,变乱的更多相关文章
- cocos2d-x在IOS7下面文字显示异常的解决办法 CGBitmapContextCreate: unsupported parameter combination
首先定位到libs-->cocos2dx-->platform-->iOS-->CCImage.mm 找到这个文件. 打开CCImage.mm文件,定位到如下函数: [cp ...
- [cocos2d] 显示状态与文字
前言: 对于显示数值与文字一般有三种方式可以使用: CCLabelTTF .CCLabelBMFont .CCLabelAtlas 详细区别可参考:cocos2d 中添加显示文字的三种方式(CCLab ...
- cocos2d 中加入显示文字的三种方式(CCLabelTTF 、CCLabelBMFont 和CCLabelAtlas)
在 cocos2d 中有三个类能够在层或精灵中加入文字: CCLabelTTF CCLabelBMFont CCLabelAtlas CCLabelTTF CCLabelTTF 每次调用 s ...
- 完美解决移动Web小于12px文字居中的问题
前几天的一篇博文:移动Web单行文字垂直居中的问题,提到了移动web里小于12px的文字居中异常的问题,最后还是改为12px才近乎解决了问题.但是有时候或许并不是那么乐观,你并不能将原本定为10px的 ...
- Canvas 笔记(持续更新中)
1.从线条开始 HTML <canvas id="canvas"></canvas> Javascript var canvas=document.getE ...
- cocos2d-x学习知识点记录
环境搭建 http://4137613.blog.51cto.com/4127613/751149 Cocos2d-x初探,HelloWorld解读 http://www.cnblogs.com/Ke ...
- pytest自动化7:assert断言
前言:assert断言就是将实际结果和期望结果做对比,符合预期结果就测试pass,不符合预期就测试failed. 实例1:简单断言 实例1优化版--增加异常信息文字描述 异常断言 excinfo 是一 ...
- 移动端网页使用flexible.js加入百度联盟广告样式不一致问题解决
flexible.js是淘宝推出的一款移动端手机自适应的库,源码内容很简洁,当网页使用了该库之后,页面会在head中加入对应的页面响应式的meta标签. 当使用flexible.js的时候,引入百度联 ...
- Android自定义控件练手——简单的时钟
首先这应该是一个老生常谈的设计了,但是毕竟身为小白的自己都没动手做过,不动手怎么提高自己呢,所以在这梅林沉船闲暇之际,我就把我的设计流程与思路记录下来.首先来看看效果图吧: 如上图就是一个简单并没有美 ...
随机推荐
- css层叠样式表总结
一.css css里注释只有一种 /* */ 二.css与HTML四种结合方式 1.行内样式 在标签中加入style属性 内部的写法:key1:value;key2:value; <div s ...
- MyBatis框架(4)全局文件
本次全部学习内容:MyBatisLearning 全局配置文件(本次案例中):
- vue2中用swiper
一.安装swiper npm install --save swiper 二.home组件 //home.js <app-banner :listImg="bannerList&quo ...
- 最简单的Servlet继承HttpServlet查询数据库登录验证
<%-- Created by IntelliJ IDEA. User: yunqing Date: 2017-12-06 Time: 9:11 To change this template ...
- Linux下rm -rf删除文件夹报错_ Device or resource busy
1.错误信息 rm: cannot remove `speechd-centos_6.2-prtl-pred-mf34/modules/t2p/py/third/g2p/.nfs00000000039 ...
- asp.net mvc HtmlHelperExt EnumDropDownList
public static class HtmlHelperExt { public static MvcHtmlString EnumDropDownList<TEnum>(this H ...
- unittest单元测试框架之测试结果输出到外部文件(四)
1.test_suit执行测试用例及输出结果前 添加如下代码(打开会新建d:/result.txt文件): with open("d:\\result.txt","a&q ...
- 通过ES6写法去对Redux部分源码解读
在Redux源码中主要有四个文件createStore,applyMiddleware,bindActionCreators,combineRedures createStore.js export ...
- 编程界失传秘术,SSO单点登录,什么是单点,如何实现登录?
单点登录 多系统,单一位置登录,实现多系统同时登录的一种技术. 常出现在互联网应用和企业级平台中. 如:京东. 单点登录一般是用于互相授信的系统,实现单一位置登录,全系统有效的. 三方登录:某系统,使 ...
- 在centos6.7通过源码安装python3.6.7报错“zipimport.ZipImportError: can't decompress data; zlib not available”
在centos6.7通过源码安装python3.6.7报错: zipimport.ZipImportError: can't decompress data; zlib not available 从 ...