前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >修复cocos2d-jsv3.1文本换行bug

修复cocos2d-jsv3.1文本换行bug

作者头像
IMWeb前端团队
发布2018-01-08 17:18:02
1.2K0
发布2018-01-08 17:18:02
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

本文作者:IMWeb vienwu 原文出处:IMWeb社区 未经同意,禁止转载

使用cocos2d-js版开发跨平台手游非常简单,并且在手机端也拥有不错的性能。但因为推出时间并不够久,用户也不够多,项目里仍然存在不少bug,这里介绍一个常见的bug和个人解决方案。

大段中文文字无法自动换行并且在不同终端行为不一致的bug修复

这个bug具体表现为,js版的cc.LabelBMFont类实现存在缺陷。 该类中,判断是否自动换行时,首先检测字符是否结束或者是否存在空格,满足条件后才会换行。 当字符串为英文时,此逻辑可以良好执行,但面对中文时就不能正常处理了。 理论上,在cocos2d-html5/cocos2d/labels/cclabelbmfont.js大约736行if (!self._lineBreakWithoutSpaces) {应该判断是否为中文,或者在后续的寻找空格逻辑中,增加寻找中文的判断。

其次,cocos2d-js在手机端执行时,会将js代码编译为jsb字节码,调用的cc.LabelBMFont类是c++实现的,并且该类实现的算法和web端的实现不同,导致字体大小、换行行为不一致,尤其在单独控制某个文本字符颜色时,定位某个文本的索引都会不同。

另,cocos2d自身不支持单独设置一段文本中某个字符的颜色,如需要实现该效果,只能使用cc.LabelBMFont类(不支持cc.LabelTTF),再单独查找到对应的cc.Sprite并设置颜色。所以这里我重写了一个类单独处理文本,支持使用类似ubb的方式单独设置某部分文本的颜色,例如:

代码语言:javascript
复制
var text = '这是一段测试文本,[color=#ff0000]这里是红色[/color],[color=green]这里是绿色[/color]';
var label = new game.Label(text,24,'#ffffff',100,50);

以上代码即可实现默认颜色为#ffffff即白色,这里是红色会显示为红色,这里是绿色会显示为绿色,字体大小24px,最大宽度100px,超过即会换行,最大高度为50px,超过时会自动添加一个滚动条。

以下为实现代码:(使用coffeescript编写,可使用相应工具转换为js代码)

代码语言:javascript
复制
注:cc.LabelBMFont使用了fnt字体文件,需要自行生成对应的fnt文件和png资源。
代码语言:javascript
复制
# 重新实现label类,by ying 

defaultSize = 32
game.Label = cc.Sprite.extend
    _str:''
    ctor:(str,fontSize=24,color='#ffffff',width=0,height=0)->
        this._super()
        this._str = String(str) or ''
        this._color = color or '#ffffff'
        this._fontSize=fontSize
        this._contentWidth = width
        this._contentHeight = height

        this.anchorY=1
        return if not str
        this.updateString()
    updateString:->
        locStr = String(this._str)
        _str = locStr.replace /\[color=#\w*\]/gi,''
        _str = _str.replace /\[\/color\]/gi,''

        color = this._color
        typeof color is 'string' and color = cc.color color
        colorList = [color]

        this.removeAllChildren()
        if cc.sys.isNative
            label=new cc.LabelBMFont _str,game.res.myfont,Math.floor(this._contentWidth*defaultSize/this._fontSize)
        else
            label=new cc.LabelBMFont _str,game.res.myfont,this._contentWidth
        label.setLineBreakWithoutSpace true
        label.setScale this._fontSize/defaultSize
        if cc.sys.isNative
            label.attr anchorY:0,anchorX:0,color:color
        else
            label.attr anchorY:0,anchorX:0,color:cc.color '#ffffff'
        maxWidth=label.width*label.getScaleX()
        maxHeight=label.height*label.getScaleY()

        len=locStr.length or 0
        tag=skip=i=0

        if this._contentWidth>0 and this._contentHeight>0
            size = cc.size this._contentWidth,this._contentHeight
            labelBgSprite=new cc.Sprite()
            labelBgSprite.attr anchorX:0,anchorY:0,width:size.width,height:maxHeight
            labelBgSprite.addChild label
            scroll=new cc.ScrollView size,labelBgSprite
            scroll.attr direction:cc.SCROLLVIEW_DIRECTION_VERTICAL
            scroll.setContentOffset x:0,y:scroll.minContainerOffset().y
            this.addChild scroll
            this.width = this._contentWidth
            this.height = this._contentHeight
            this.scroll = scroll
        else
            this.addChild label
            this.width=maxWidth
            this.height=maxHeight

        if locStr.indexOf('[color=') isnt -1 or  not cc.sys.isNative
            while i<len
                char=locStr[i]
                key=char.charCodeAt 0
                if char is '[' and locStr.substr(i,7) is '[color='
                    colorList.push cc.color(locStr.substr(i+7,7))
                    i=i+15
                    continue
                if char is '[' and locStr.substr(i,8) is '[/color]'
                    colorList.pop()
                    i=i+8
                    continue
                if key is 10
                    i++
                    skip++
                    continue
                while true
                    break if tag+skip>len
                    sprite=label.getChildByTag tag+skip
                    if not sprite
                        skip++
                    else
                        if cc.sys.isNative
                            nextSprite=label.getChildByTag tag+skip+1
                            break if not nextSprite
                            break if nextSprite.getPositionX()>=sprite.getPositionX()
                            skip++
                        else
                            break if sprite.visible
                            skip++
                sprite.color = colorList[colorList.length-1]  if sprite
                i++
                tag++
        # cc.log 'hello',this.width,this.height,this.anchorX,this.anchorY
    setString:(str)->
        this._str = String(str) or ''
        this.updateString()
game.LabelTTF = cc.Sprite.extend
    _str:'' # 文本
    _fontSize:24 # 文字大小
    _color:'#ffffff' # 文本颜色
    _charSprites:null
    _space:0 # 水平间距
    _lineHeight:2 # 行距
    _contentWidth:0 # 最大宽度 自动换行
    _contentHeight:0 # 最大高度,超过最大高度自动加滚动条
    ctor:(str,fontSize=24,color='#ffffff',width=0,height=0)->
        this._super()
        color = '#ffffff' if not color
        this._str = String(str) or ''
        this._fontSize = fontSize
        # this._lineHeight = Math.round this._fontSize * 0.5
        this._color = color
        this._charSprites = []
        this._contentWidth = width
        this._contentHeight = height
        this.anchorY=1
        return if not str
        this.updateString()
    updateString:->
        locStr = String this._str
        color = this._color
        fontSize = this._fontSize
        typeof color is 'string' and color = cc.color color
        colorList = [color]
        len = locStr.length or 0
        this.removeAllChildren()
        this._charSprites=[]
        posX = maxWidth = maxHeight = i = 0
        rows = 1
        fontHeight = 0 # 字体的高度和fontSize不一定相同
        if locStr.indexOf('[color=') is -1 and this._contentWidth is 0 # 不需要区分颜色和换行
            sprite = this.getStrSprite locStr,fontSize
            sprite.attr x:0,y:-1*fontSize,anchorY:0,anchorX:0,fillStyle:color
            maxWidth = sprite.width
            maxHeight = fontHeight = sprite.height
            this._charSprites.push sprite
        else
            while i<len
                char = locStr[i]
                key = locStr.charCodeAt i
                if char is '[' and locStr.substr(i,7) is '[color='
                    colorList.push cc.color locStr.substr i+7,7
                    i=i+15
                    continue
                if char is '[' and locStr.substr(i,8) is '[/color]'
                    colorList.pop()
                    i=i+8
                    continue
                if key is 10 # 换行
                    rows++
                    posX=0
                    i++
                    continue
                sprite = this.getStrSprite char,fontSize
                this._charSprites.push sprite
                fontHeight<sprite.height and fontHeight=sprite.height # 获取一个最大的字体高度用于计算
                sprite.attr x:posX,anchorY:0,anchorX:0,fillStyle:colorList[colorList.length-1]
                posX+=sprite.width+this._space # 增加字间距
                if this._contentWidth>0 and posX>this._contentWidth # 换行
                    sprite.attr x:0
                    rows++
                    posX=sprite.width+this._space
                sprite.attr y:(rows-1)*(fontHeight+this._lineHeight)*-1-fontHeight
                maxWidth<posX and maxWidth=posX
                i++
        maxHeight = rows * fontHeight + (rows-1) * this._lineHeight
        if this._contentWidth>0 and this._contentHeight>0
            # 如果设置了内容最大宽度高度,则添加一个可滚动层
            size = cc.size this._contentWidth,this._contentHeight
            labelBgSprite = new cc.Sprite()
            for sprite in this._charSprites
                sprite.attr y:maxHeight+sprite.y
                labelBgSprite.addChild sprite
            labelBgSprite.attr width:maxWidth,height:maxHeight,anchorX:0,anchorY:0
            scroll = new cc.ScrollView size,labelBgSprite
            scroll.attr direction:cc.SCROLLVIEW_DIRECTION_VERTICAL
            scroll.setContentOffset x:0,y:scroll.minContainerOffset().y
            this.addChild scroll
            this.width = this._contentWidth
            this.height = this._contentHeight
            this.scroll = scroll
        else
            this.width = maxWidth
            this.height = maxHeight
            for sprite in this._charSprites
                # 最大高度+偏移+向下移动一小部分(行距和字体刚度不同,增加这部分使得单行文字可以上下居中)
                sprite.attr y:maxHeight+sprite.y-(fontHeight-fontSize)
                this.addChild sprite
    setString:(str)->
        this._str = String(str) or ''
        this.updateString()
    getStrSprite:(str,fontSize)->
        new cc.LabelTTF str,'',fontSize
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 大段中文文字无法自动换行并且在不同终端行为不一致的bug修复
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档