cocos2d-x3.7 cclabel文字破碎,异常,变乱

2024-01-20 18:32

本文主要是介绍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的概率是很小的:
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文字破碎,异常,变乱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/626924

相关文章

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

Java空指针异常NullPointerException的原因与解决方案

《Java空指针异常NullPointerException的原因与解决方案》在Java开发中,NullPointerException(空指针异常)是最常见的运行时异常之一,通常发生在程序尝试访问或... 目录一、空指针异常产生的原因1. 变量未初始化2. 对象引用被显式置为null3. 方法返回null