基于Cocos2dx+Lua v3.x的RichLabel

RichLabel

简介

RichLabel基于Cocos2dx+Lua v3.x
解析字符串方面使用了labelparser,它可以将一定格式的字符串,转换为lua中的表结构
扩展标签极其简单,只需添加一个遵守规则的标签插件即可,无需改动已存在代码!!!

(标签插件都在labels文件夹下)

labelparser的详解
labelparser在github上的源码
RichLabel在github上的源码

  • 支持图片(缩放,旋转,是否可见)
  • 支持文本属性(字体,大小,颜色,阴影,描边,发光)
  • 支持标签嵌套修饰文本,但是内部标签不会继承嵌套标签的属性
  • 支持标签扩展(labels文件夹中可添加标签支持)
  • 支持渐入动画,动画逐字回调
  • 支持设置最大宽度,自动换行布局
  • 支持手动换行,使用‘\n‘换行
  • 支持设置行间距,字符间距
  • 支持添加debug绘制文字范围和锚点
  • 支持获得文字的精灵节点
  • 支持设置标签锚点,透明度,颜色...
  • 支持遍历字符,行等
  • 支持获得任意行的行高

效果图:

 

由于解析字符串使用了labelparser,那么我们先简单了解一下它,详细了解 传送门

local text1 = "hello worldd   <div>hello world</div> 你好 <div fontName=‘nihao‘ fontColore=#ff33ee>hello,world</div><div></div>"
local parsedtable = labelparser.parse(text1)
-- output:
<parsedtable> = {
    {
        content = "hello worldd   ",
        labelname = "div",
    },
    {
        content = "hello world",
        labelname = "div",
    },
    {
        content = " 你好 ",
        labelname = "div",
    },
    {
        content = "hello,world",
        fontname = "nihao",
        fontsize = "#123456",
        labelname = "div",
    },
}

这中格式十分方便我们处理,它将每个文本片段及其属性分拆成table,然后按顺序组织好返回给我们
这样我们处理就可以简单多了

原理

首先要说一下,这位前辈灵动君心他也有一个RichLabel,刚一开始我本来打算 使用他开源的RichLabel,但是我发现他的RichLabel无法满足我的需求,所以没办法只有自己实现了,我看了他的代码思路也大概和他的方式类似 
大体思路:

  1. 解析字符串
  2. 解析出来的表中元素的处理
    • 对于字符串的处理就是将字符串拆分成一个个字符,然后每个字符创建一个Label
    • 对于图片的处理就是直接创建精灵
  3. 将创建好的node布局即可

第一步
解析字符串,解析字符串使用了我的另一个开源工具labelparser,直接解析就可以返回table

第二步
我们按照顺序从表第一项开始处理
每一项都可以获得对应的标签名,根据标签名调用对应的标签的处理函数,同时要将表项中的属性传入标签处理函数
(这个处理函数是以插件形式提供的,很便于扩展)
具体的标签处理下面标签解析处详解

第三步
此时我们就获得了设置好属性的node,我们要做的就是布局文本
首先我们处理换行,什么时候换行呢?
+ 如果设置了MaxWidth那么,每行最大宽度不能超过MaxWidth,否则就换行
+ 如果文本内容中存在换行符\n,则直接换行

我们遍历所有的node(node存在顺序)然后检测是否为Label,为Label则检测内容是否为\n,然后检测此时累加宽度若超过了最大宽度,则将当前的node直接放到下一行
代码

-- 自动适应换行处理方法,内部会根据最大宽度设置和‘\n‘自动换行
-- 若无最大宽度设置则不会自动换行
function RichLabel:adjustLineBreak_(allnodelist, charspace)
    -- 如果maxwidth等于0则不自动换行
    local maxwidth = self._maxWidth
    if maxwidth <= 0 then maxwidth = 999999999999
    end
    -- 存放每一行的nodes
    local alllines = {{}, {}, {}}
    -- 当前行的累加的宽度
    local addwidth = 0
    local rowindex = 1
    local colindex = 0
    for _, node in pairs(allnodelist) do
        colindex = colindex + 1
        -- 为了防止存在缩放后的node
        local box = node:getBoundingBox()
        addwidth = addwidth + box.width
        local totalwidth = addwidth + (colindex - 1) * charspace
        local breakline = false
        -- 若累加宽度大于最大宽度
        -- 则当前元素为下一行第一个元素
        if totalwidth > maxwidth then
            rowindex = rowindex + 1
            addwidth = box.width -- 累加数值置当前node宽度(为下一行第一个)
            colindex = 1
            breakline = true
        end

        -- 在当前行插入node
        local curline = alllines[rowindex] or {}
        alllines[rowindex] = curline
        table.insert(curline, node)

        -- 若还没有换行,并且换行符存在,则下一个node直接转为下一行
        if not breakline and self:adjustContentLinebreak_(node) then
            rowindex = rowindex + 1
            colindex = 0
            addwidth = 0 -- 累加数值置0
        end
    end
    return alllines
end

-- 判断是否为文本换行符
function RichLabel:adjustContentLinebreak_(node)
    -- 若为Label则有此方法
    if node.getString then
        local str = node:getString()
        -- 查看是否为换行符
        if str == "\n" then
            return true
        end
    end
    return false
end

这样我们就将混在一块的node拆分成一个table中存一行
虽然我们知道哪些node在第一行,哪些在第二行... ...
但是我们还没有布局呢!!!
下面我们就遍历每一行,然后调用行布局函数layoutLine_, 行累加函数还返回行的真实宽度和高度,这样我们就可以计算出最宽的一行,即为RichLabel的宽度

精简后代码

for index, line in pairs(alllines) do
    local linewidth, lineheight = self:layoutLine_(basepos, line, 1, charspace)
    -- todo
end

行布局函数(精简后)

-- 布局单行中的节点的位置,并返回行宽和行高
function RichLabel:layoutLine_(basepos, line, anchorpy, charspace)
    local pos_x = basepos.x
    local pos_y = basepos.y
    local lineheight = 0
    local linewidth = 0
    for index, node in pairs(line) do
        local box = node:getBoundingBox()
        -- 设置位置
        node:setPosition((pos_x + linewidth + box.width/2), pos_y)
        -- 累加行宽度
        linewidth = linewidth + box.width + charspace
        -- 查找最高的元素,为行高
        if lineheight < box.height then lineheight = box.height
        end
    end
    return linewidth, lineheight
end

这样我们就一行行布局好了

标签处理函数

文本标签处理函数,首先要先将字符串拆分成一个个字符,如果字符串中存在中文那么直接拆分肯定是不行的

拆分字符串,支持Unicode编码

function RichLabel:stringToChars(str)
    -- 主要用了Unicode(UTF-8)编码的原理分隔字符串
    -- 简单来说就是每个字符的第一位定义了该字符占据了多少字节
    -- UTF-8的编码:它是一种变长的编码方式
    -- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
    -- 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。
    -- 剩下的没有提及的二进制位,全部为这个符号的unicode码。
    local list = {}
    local len = string.len(str)
    local i = 1
    while i <= len do
        local c = string.byte(str, i)
        local shift = 1
        if c > 0 and c <= 127 then
            shift = 1
        elseif (c >= 192 and c <= 223) then
            shift = 2
        elseif (c >= 224 and c <= 239) then
            shift = 3
        elseif (c >= 240 and c <= 247) then
            shift = 4
        end
        local char = string.sub(str, i, i+shift-1)
        i = i + shift
        table.insert(list, char)
    end
    return list, len
end

字符串拆分成一个表之后,就可以给表每一个字符创建一个Label,并且设置属性(颜色,字体,大小...)

处理颜色也要说一下,由于使用HTML方式标记颜色,所以要解析#FF0099这种类型的颜色

-- 解析16进制颜色rgb值
function  RichLabel:convertColor(xstr)
    if not xstr then return
    end
    local toTen = function (v)
        return tonumber("0x" .. v)
    end

    local b = string.sub(xstr, -2, -1)
    local g = string.sub(xstr, -4, -3)
    local r = string.sub(xstr, -6, -5)

    local red = toTen(r)
    local green = toTen(g)
    local blue = toTen(b)
    if red and green and blue then
        return cc.c4b(red, green, blue, 255)
    end
end

因为也支持了图片,所以图片的加载必须要考虑,无论是从图集中加载还是碎图加载都应该正常

-- 创建精灵,现在帧缓存中找,没有则直接加载
-- 屏蔽了使用图集和直接使用碎图创建精灵的不同
function RichLabel:getSprite(filename)
    local spriteFrameCache = cc.SpriteFrameCache:getInstance()
    local spriteFrame = spriteFrameCache:getSpriteFrameByName(filename)

    if spriteFrame then
        return cc.Sprite:createWithSpriteFrame(spriteFrame)
    end
    return cc.Sprite:create(filename)
end

要详细了解还是去看看代码吧!!!

时间: 2024-12-26 03:26:29

基于Cocos2dx+Lua v3.x的RichLabel的相关文章

Cocos2dx+lua合适还是Cocos2dx+js合适?

问题: 开发cocos2dx手游Cocos2dx+lua合适还是Cocos2dx+js合适 百牛信息技术bainiu.ltd整理发布于博客园 回答: 作者:廖宇雷链接:https://www.zhihu.com/question/21130385/answer/18485625来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 2014.02更新:请放心选择 Lua 吧.触控已经收购了 quick-cocos2d-x,2014年肯定会大力强化 cocos2d-x 的

【转】cocos2d-x Lua

Call custom c++ from Lua cocos2d-x lua binds c++ class, class functions ,enum and some global functions to lua through auto-binding by bindings-generator(tools/bindings-generator) and some manual binding,so we can call custom c++ from lua convenientl

Cocos2d-x Lua 读取Csv文件,更方便的使用数据

我的书上或者是我曾经出售的源码里,都有Csv文件的影子. 也许是先入为主吧,我工作那会用的最久的配置文件就是Csv,所以我在很多游戏里都会情不自禁地优先选择它. Csv文件,格式很简单,就是一行一条数据,字段之间用逗号分隔,策划也可以方便地使用Excel进行编辑. Csv格式的文件,解析起来也很简单,所以自己动手写写很快~(小若:我就喜欢拿来主义,你怎么着) 最近在用Lua写游戏,对于技能.怪物等配置,我还是选择用Csv~ 不得不说,Lua等脚本语言,在某些方面是C++没法比的,这次我就用Csv

cocos2d-x lua 中使用protobuf并对http进行处理

本文介绍 cocos2d-x lua 中使用http 和 基于cocos2d-x 对lua http的封装(部分ok) 本博客链接 http://blog.csdn.net/vpingchangxin/article/details/24458051 protobuf  Google的一个非常好用的数据传输的封装 说实话Google的东西确实比較好用 所以我们前后端数据交换就用他了 只是Google没有对lua进行支持 还好社区有开源的大侠们贡献 找了全部关于lua protobuf 我仅仅找到

第一个Cocos2d-x Lua游戏

我们的编写的第一个Cocos2d-x Lua程序,命名为HelloLua,从该工程开始学习其它的内容.创建工程我们创建Cocos2d-x Lua工程可以通过Cocos2d-x提供的命令工具cocos实现,但这种方式不能与Cocos Code IDE集成开发工具很好地集成,不便于程序编写和调试.由于Cocos Code IDE工具是Cocos2d-x开发的专门为Cocos2d-JS和Cocos2d-x Lua开发设计的,因此使用Cocos Code IDE工具很方便创建Cocos2d-x Lua工

Cocos2d-x Lua中使用标签

游戏场景中的文字包括了静态文字和动态文字.静态文字如下图所示游戏场景中①号文字“COCOS2DX”,动态文字如图4-1所示游戏场景中的②号文字“Hello World”.静态文字一般是由美工使用Photoshop绘制在背景图片上,这种方式的优点是表现力很丰富,例如:①号文字“COCOS2DX”中的“COCOS”.“2D”和“X”设计的风格不同,而动态文字则不能,而且静态文字无法通过程序访问,无法动态修改内容.动态文字一般是需要通过程序访问,需要动态修改内容.Cocos2d-x Lua可以通过标签

将cocos2dx+lua创建的游戏port到windows phone

在整个Port的过程中遇到的问题总结如下 1.一定要使用最新版本的cocos2dx,原因大家看一下changelog就知道了,最近的cocos2dx版本都是在修windows phone上的bug,所以为了避免少出问题,还是直接升级到最新版本吧 2.如果你使用的是cocos2dx + lua方式,目前的project-creator并不支持lua版本的windows phone平台,但是cpp版本是支持的,因此我们可以在cpp版本的基础上把libcocoslua以及liblua两个工程加到项目中

Cocos2d-x lua游戏开发之安装Lua到mac系统

注意:mac ox ,lua version :5.15 下载lua官网的lua, 注意:最好是5.15以下,5.2的lua不支持table的getn()方法,这让我情何以堪.(获取table长度,相当与cout,size,length) 下载解压, cd 目录 make macosx sudo make install (是的,就是小写的install,虽然文件夹下的是INSTALL) ook,进入命令行,输入lua 看下,效果 Cocos2d-x lua游戏开发之安装Lua到mac系统,布布

【课程下载】基于Cocos2d-x游戏引擎实战开发炸弹超人

我这里有套课程想和大家分享,需要的朋友可以加我qq和我联系.QQ2059055336. 课程讲师:Jason.Z 课程分类:ios适合人群:初级课时数量:31课时更新程度:完毕 一.本课程是怎么样的一门课程(全面介绍) 1.1.课程的背景 Cocos2d-x 是一个支持多平台的 2D 手机游戏引擎,使用 C++ 开发,基于OpenGL ES,基于Cocos2d-iphone,支持 WOPhone, iOS 4.1, Android 2.1 及更高版本, WindowsXP & Windows7,