quick-cocos2d-x lua框架解析(一)对UI进行操作的UiUtil脚本

  最近一段时间接手了一个cocos游戏项目,由于我是U3D开发入门,所以花了一段时间来钻研cocos2d的使用与项目架构。与U3D相比,cocos2d的开发界面实在做的不咋地。不过在看过源码之后,源码跑起来还是比较稳健的,在此基础上做些修改也无不可。

  言归正传,先从底层工具入手,逐步解析整个项目。关于整个项目的结构,有时间我会专门记录一下。不过最近要修改客户端部分,所以优先以战斗逻辑为主。这里要记录的是UI底层部分的代码。

  先写下项目中自己定义的几个方法,其余方法均引自framework,就此不再详述(逐步深入,底层与应用层分离解析)。

function cc.p(_x,_y)--传入参数_x,_y:如果_y为空,返回_x里的x、y值;否则返回原值
    if nil == _y then
         return { x = _x.x, y = _x.y }
    else
         return { x = _x, y = _y }
    end
end
-- load more library
cc.ui = import(".ui.init")
function cca.seq(acts)--序列发生器
   return cc.Sequence:create(acts)
end

  这个脚本中包含了点击判断、颜色变化以及滚动等操作(引用了frameworks关于各种数据的定义,详见Cocos2dConstants脚本),具体代码如下:

local Scheduler = require("framework.scheduler")--计时器的引用

local UiUtil = {}--UI工具

-- 判断是不是UIButton或者UIPushButton
function UiUtil.isButton(node)
    if type(node.getClass) ~= "function" then
        return false
    end--如果没有挂载方法则什么都不做

    return node.getClass() == "UIButton" or node.getClass() == "UIPushButton"
end

-- 将全局坐标转换成基于node的本地坐标
--在cocos中,node对象是场景图的基本元素
function UiUtil.convertToNodeSpace(node, global_p, global_y)
    if type(global_p) == "number" then
        global_p = cc.p(global_p, global_y)
    end

    local point = node:convertToNodeSpace(global_p)--将Vec2转换为节点(本地)空间坐标。

    if UiUtil.isButton(node) then
        local content_size = node:getContentSize()--返回节点的未转换大小(逻辑点)
        if content_size.width == 0 or content_size.height == 0 then
            content_size = node:getCascadeBoundingBox().size
        end

        --求出本地坐标
        local anchor_point = node:getAnchorPoint()
        point.x = point.x + (anchor_point.x) * content_size.width
        point.y = point.y + (anchor_point.y) * content_size.height
    end

    return point
end

-- 根据点击位置检查结点是否被点击
function UiUtil.checkNodeByPoint(node, global_p, global_y)
    local point = UiUtil.convertToNodeSpace(node, global_p, global_y)--将Vec2转换为节点(本地)空间坐标--#这里应该值得是相对于被点击区域的相对坐标
    local content_size = node:getContentSize()--返回节点的未转换大小(逻辑点)

    if content_size.width == 0 or content_size.height == 0 then
        content_size = node:getCascadeBoundingBox().size--求出边界大小
    end

    --如果在边界范围内则被点击,否则没有被点击
    if point.x >= 0 and point.x <= content_size.width and point.y >= 0 and point.y <= content_size.height then
        return true
    end

    return false
end

-- 根据点击位置找出被点击的子结点
function UiUtil.findChildByPoint(parent, global_p, global_y)
    local ret = nil

    for _, child in ipairs(parent:getChildren()) do
        if UiUtil.checkNodeByPoint(child, global_p, global_y) then
            if ret == nil or child:getLocalZOrder() > ret:getLocalZOrder() then--获取本节点的深度顺序
                ret = child
            end
        end
    end

    return ret
end

-- 按钮的长按回调:按钮、回调方法、首次点击时间、延迟回调时间
-- 刚按下时回调一次,过first_delay秒后,每repeat_delay秒回调一次
-- 当手指抬起,或者回调返回false时停止

function UiUtil.buttonLongClick(button, callback, first_delay, repeat_delay)
    local handle = nil
    first_delay = first_delay or 0.5
    repeat_delay = repeat_delay or 0.1

    button:onButtonPressed(function(event)
        if not callback(1) then
            return
        end

        local count = 1

        handle = button:performWithDelay(function()
            handle = button:schedule(function(dt)
                count = count + 1

                if not callback(count) and handle then
                    button:stopAction(handle)
                    handle = nil
                end
            end, repeat_delay)
        end, first_delay)
    end)

    button:onButtonRelease(function(event)
        if handle then
            button:stopAction(handle)
            handle = nil
        end
    end)
end

-- 用于非按钮组件监听clicked事件,会把符合条件的ended事件改成clicked事件
-- params.click_only : boolean,只监听clicked事件
-- params.distance_check :boolean,判定clicked事件时,是否检测松手时与按下时的距离
-- params.move_check :boolean,判定clicked事件时,是否检测移动的次数
function UiUtil.nodeTouchEvent(node, callback, params)
    params = params or {}

    local began_point
    local move_count

    node:setTouchEnabled(true)
    local handler = node:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
        if event.name == "began" then
            began_point = {x = event.x, y = event.y}
            move_count = 0
        elseif event.name == "moved" then
            move_count = move_count + 1
        elseif event.name == "ended" then
            if UiUtil.checkNodeByPoint(node, event) then
                if (not params.distance_check or UiUtil.distance(began_point, event) < 15) and
                    (not params.move_check or move_count < 6) then
                    callback({name = "clicked", x = event.x, y = event.y})

                    return true
                end
            end
        end

        if not params.click_only then
            callback(event)
        end

        return true
    end)

    return handler
end

-- 计算平面上两点间距离
-- x1, y1, x2, y2 或 p1, p2
function UiUtil.distance(a, b, c, d)
    local dx, dy

    if type(a) == "number" then
        dx = a - c
        dy = b - d
    else
        dx = a.x - b.x
        dy = a.y - b.y
    end

    return math.sqrt(dx * dx + dy * dy)
end

--移除节点的触摸事件监听
function UiUtil.removeNodeTouchEvent(node, handler)
    if not node or not handler then
        return false
    end

    node:removeNodeEventListener(handler)
    return true
end

-- 创建添加右上角的返回按钮
--ps:具体应用层,可以根据项目不同进行更改
function UiUtil.createBackButton(parent)
    display.addSpriteFrames("res/ui/common/common0.plist", "res/ui/common/common0.png")--加载返回按钮的美术资源

    local button = cc.ui.UIPushButton.new()
    button:setButtonImage(cc.ui.UIPushButton.NORMAL, "#ty_fanhui.png")--正常状态
    button:setButtonImage(cc.ui.UIPushButton.PRESSED, "#ty_fanhui002.png")--点击状态
    button:setScale(1)--按钮缩放
    button:setPosition(parent:convertToNodeSpace(cc.p(display.width - 50, display.height - 50)))
    button:setLocalZOrder(20)
    button:setTouchSwallowEnabled(true)
    button:addTo(parent)

    return button
end

-- 把组件改成灰阶显示
local program = nil
function UiUtil.changeToGray(node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_PMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec4 v_fragmentColor;
        varying vec2 v_texCoord;

        void main(void) {
            vec4 c = texture2D(CC_Texture0, v_texCoord);
            gl_FragColor.xyz = vec3(0.4 * c.r + 0.4 * c.g + 0.4 * c.b);
            gl_FragColor.w = c.w;
        }
    ]]

    if not program then
        program = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        program:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        program:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        program:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        program:link()
        program:updateUniforms()

        -- program:retain()
    end
    node:setGLProgram(program)
end

--将组件及其包含的子组件全部置灰
function UiUtil.changeToGrayRec(node)
    if node.setTextColor then
        return
    end

    UiUtil.changeToGray(node)

    for _, child in ipairs(node:getChildren()) do
        UiUtil.changeToGrayRec(child)
    end
end

-- 把组件改回彩色显示
function UiUtil.changeToColor(node)
    node:setGLProgramState(cc.GLProgramState:getOrCreateWithGLProgram(cc.GLProgramCache:getInstance():getGLProgram("ShaderPositionTextureColor_noMVP")))
end

--将组件及其包含的子组件全部改变颜色
function UiUtil.changeToColorRec(node)
    if node.setTextColor then
        return
    end

    UiUtil.changeToColor(node)

    for _, child in ipairs(node:getChildren()) do
        UiUtil.changeToColorRec(child)
    end
end

-- 把组件改成灰阶显示
local spineToGrayprogram = nil
function UiUtil.changeSpineToGray(node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_MVPMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec4 v_fragmentColor;
        varying vec2 v_texCoord;

        void main(void) {
            vec4 c = texture2D(CC_Texture0, v_texCoord);
            gl_FragColor.xyz = vec3(0.15 * c.r + 0.15 * c.g + 0.15 * c.b);
            gl_FragColor.w = c.w;
        }
    ]]

    if not spineToGrayprogram then
        spineToGrayprogram = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        spineToGrayprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        spineToGrayprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        spineToGrayprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        spineToGrayprogram:link()
        spineToGrayprogram:updateUniforms()

        -- program:retain()
    end
    node:setGLProgram(spineToGrayprogram)
end

-- 把组件改成黑色显示
local spineToBlackprogram = nil
function UiUtil.changeSpineToBlack(node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_MVPMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec4 v_fragmentColor;
        varying vec2 v_texCoord;

        void main(void) {
            vec4 c = texture2D(CC_Texture0, v_texCoord);
            gl_FragColor.xyz = vec3(0.0 * c.r + 0.0 * c.g + 0.0 * c.b);
            gl_FragColor.w = c.w;
        }
    ]]

    if not spineToBlackprogram then
        spineToBlackprogram = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        spineToBlackprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        spineToBlackprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        spineToBlackprogram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        spineToBlackprogram:link()
        spineToBlackprogram:updateUniforms()

        -- program:retain()
    end
    node:setGLProgram(spineToBlackprogram)
end

--褪色
function UiUtil._fadeActionRec(node, action, cb)
    if not node or not action then
        return
    end
    if cb then
        node:runAction(cca.seq({action:clone(), cca.cb(cb)}))--序列发生器
    else
        node:runAction(action:clone())
    end

    for _, child in ipairs(node:getChildren()) do
        UiUtil._fadeActionRec(child, action)
    end
end
--全部褪色
function UiUtil.fadeActionAll(node, time, to, cb)
    if not node then
        return
    end

    to = to or 0
    local action = cca.fadeTo(time, to)
    UiUtil._fadeActionRec(node, action, cb)
end

-- 把组件改成纯白色显示
local spine_program = nil
function UiUtil.changeSpineToWhite(spine_node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_MVPMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec4 v_fragmentColor;
        varying vec2 v_texCoord;

        void main(void) {
            vec4 c = texture2D(CC_Texture0, v_texCoord);
            gl_FragColor = vec4(c.r + c.g + c.b + c.a);
        }
    ]]

    if not spine_program then
        spine_program = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        spine_program:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        spine_program:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        spine_program:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        spine_program:link()
        spine_program:updateUniforms()

        -- spine_program:retain()
    end
    spine_node:setGLProgram(spine_program)
end

-- 把组件改成灰阶显示
local spine_color_program = nil
function UiUtil.changeSpineToColor(spine_node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_MVPMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec4 v_fragmentColor;
        varying vec2 v_texCoord;

        void main(void) {
            gl_FragColor = texture2D(CC_Texture0, v_texCoord);
        }
    ]]

    if not spine_color_program then
        spine_color_program = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        spine_color_program:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        spine_color_program:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        spine_color_program:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        spine_color_program:link()
        spine_color_program:updateUniforms()

        -- spine_color_program:retain()
    end
    spine_node:setGLProgram(spine_color_program)
end


-- 描边spine(黄色)
local spine_outline_program = nil
function UiUtil.outlineSpine(spine_node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_MVPMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        varying vec2 v_texCoord;
        varying vec4 v_fragmentColor;

        vec3 u_outlineColor = vec3(1,1,1);
        float u_threshold = 0.12;
        float u_radius = 0.005;

        void main()
        {
            float radius = u_radius;
            vec4 accum = vec4(0.0);
            vec4 normal = vec4(0.0);

            normal = texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y));

            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y + radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y + radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y + radius));

            accum *= u_threshold;
            accum.rgb =  u_outlineColor * accum.a;
            accum.a = normal.a;

            normal = ( accum * (1.0 - normal.a)) + (normal * normal.a);

            gl_FragColor = v_fragmentColor * normal;
        }
    ]]

    if not spine_outline_program then
        spine_outline_program = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        spine_outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        spine_outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        spine_outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        spine_outline_program:link()
        spine_outline_program:updateUniforms()

        -- spine_outline_program:retain()
    end
    spine_node:setGLProgram(spine_outline_program)
end

local outline_program = nil
function UiUtil.outline(node)
    local vertDefaultSource = [[
        attribute vec4 a_position;
        attribute vec2 a_texCoord;
        attribute vec4 a_color;

        #ifdef GL_ES
            varying lowp vec4 v_fragmentColor;
            varying mediump vec2 v_texCoord;
        #else
            varying vec4 v_fragmentColor;
            varying vec2 v_texCoord;
        #endif

        void main() {
            gl_Position = CC_PMatrix * a_position;
            v_fragmentColor = a_color;
            v_texCoord = a_texCoord;
        }
    ]]

    local pszFragSource = [[
        varying vec2 v_texCoord;
        varying vec4 v_fragmentColor;

        vec3 u_outlineColor = vec3(1,1,1);
        float u_threshold = 0.12;
        float u_radius = 0.01;

        void main()
        {
            float radius = u_radius;
            vec4 accum = vec4(0.0);
            vec4 normal = vec4(0.0);

            normal = texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y));

            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y + radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y + radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y - radius));
            accum += texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y + radius));

            accum *= u_threshold;
            accum.rgb =  u_outlineColor * accum.a;
            accum.a = normal.a;

            normal = ( accum * (1.0 - normal.a)) + (normal * normal.a);

            gl_FragColor = v_fragmentColor * normal;
        }
    ]]

    if not outline_program then
        outline_program = cc.GLProgram:createWithByteArrays(vertDefaultSource, pszFragSource)

        outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
        outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
        outline_program:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_FLAG_TEX_COORDS)
        outline_program:link()
        outline_program:updateUniforms()

        -- outline_program:retain()
    end
    node:setGLProgram(outline_program)
end

--总要
function UiUtil.outlineRec(node)
    UiUtil.outline(node)

    for _, child in ipairs(node:getChildren()) do
        UiUtil.outline(child)
    end
end

local NodeRec
function NodeRec(node, fun_name)
    if not node[fun_name] then
        _dump("node没有方法"..fun_name)
        return
    end

    node[fun_name](node)
    for _, child in ipairs(node:getChildren()) do
        NodeRec(child, fun_name)
    end
end

function UiUtil.activeNodeRec(node,  bflag)
    local fun_name = ""
    if bflag then
        fun_name = "resume"--摘要
    else
        fun_name = "pause"--暂停
    end

    NodeRec(node, fun_name)
end
--spine变色(项目中没使用)
function UiUtil.changeToColor2(node)
    node:setGLProgramState(cc.GLProgramState:getOrCreateWithGLProgram(cc.GLProgramCache:getInstance():getGLProgram("ShaderPositionTextureColor")))
end

-- 滚动到最上边
-- view:竖向滚动的UIScrollView或UIListView
function UiUtil.scrollToTop(view)
    local view_rect = view:getViewRect()
    view:scrollTo(view_rect.x, view_rect.y - view:getScrollNode():getContentSize().height + view_rect.height)
end

-- 滚动到最下边
-- view:竖向滚动的UIScrollView或UIListView
function UiUtil.scrollToBottom(view)
    local view_rect = view:getViewRect()
    view:scrollTo(view_rect.x, view_rect.y)
end

-- 滚动到最左边
-- view:横向滚动的UIScrollView或UIListView
function UiUtil.scrollToLeft(view)
    local view_rect = view:getViewRect()
    view:scrollTo(view_rect.x, view_rect.y)
end

-- 滚动到最右边
-- view:横向滚动的UIScrollView或UIListView
function UiUtil.scrollToRight(view)
    local view_rect = view:getViewRect()
    view:scrollTo(view_rect.x - view:getScrollNode():getContentSize().width + view_rect.width, view_rect.y)
end

-- UIScrollView滚动指定距离
function UiUtil.scrollBy(scroll_view, x, y, time, callback)
    x = x or 0
    y = y or 0

    if not time or time <= 0 then
        local px, py = scroll_view:getScrollNode():getPosition()
        scroll_view:scrollTo(px + x, py + y)
        if callback then
            callback()
        end
    else
        transition.moveBy(scroll_view:getScrollNode(), {x = x, y = y, time = time, onComplete = callback})
    end
end

-- UIScrollView滚动到指定位置
function UiUtil.scrollTo(scroll_view, x, y, time, callback)
    local px, py = scroll_view:getScrollNode():getPosition()
    x = x or px
    y = y or py

    if not time or time <= 0 then
        scroll_view:scrollTo(x, y)
        if callback then
            callback()
        end
    else
        transition.moveTo(scroll_view:getScrollNode(), {x = x, y = y, time = time, onComplete = callback})
    end
end

--根据横竖的格子数,格子的index,返回格子所在的行数i和列数j
function UiUtil.getGridPos(width, height, index)
    if not (width > 0 and height > 0 and index > 0) then
        print("error info")
        return nil, nil
    end

    local i, j = index % width, math.ceil(index / width)

    if i == 0 then
        i = width
    end

    return i, j
end

function UiUtil.getLabel(text, size, color, outline_color, outline, dimensions, align, valign)
    local text = text or ""
    local size = size or 20
    local color = color or cc.c3b(0xff, 0xff, 0xff)
    local align = align or cc.TEXT_ALIGNMENT_CENTER  --cc.TEXT_ALIGNMENT_LEFT cc.TEXT_ALIGNMENT_RIGHT = 0x2
    local valign = valign or cc.VERTICAL_TEXT_ALIGNMENT_CENTER

    local label_params = {
        text = text,
        font = "ms_yahei",
        size = size,
        color = color,
        align = align,
        valign = valign,
        dimensions = dimensions,--cc.size(400, 200)
    }
    local label = display.newTTFLabel(label_params)
    if outline_color then
        label:enableOutline(outline_color, outline or 2) --cc.c4b(0x28,0x2d,0x38,255)
    end
    return label
end
--变化
function UiUtil.setLabel(label, str, color, outline_color, outline)
    if not label then
        return
    end
    if str then
        label:setString(str)
    end
    if color then
        label:setTextColor(color)
    end
    if outline_color then
        label:enableOutline(outline_color, outline or 2)
    end
end
--格子变化
function UiUtil.runTask_(node)
    local task = node.task_queue[1]
    if not task then
        node.task_running = false
        return
    end

    table.remove(node.task_queue, 1)
    node.task_running = true

    node:performWithDelay(function()
        task()

        UiUtil.runTask_(node)
    end, 0.01)
end
--改变一个格子
function UiUtil.runTaskOnNode(node, task)
    if not node.task_queue then
        node.task_queue = {}
    end

    table.insert(node.task_queue, task)

    if not node.task_running then
        UiUtil.runTask_(node)
    end
end
--用于新手引导的开关
function UiUtil.setTouchSwallowEnabledRec(node, enabled)
    node:setTouchSwallowEnabled(enabled)

    local children = node:getChildren()
    for _, v in ipairs(children) do
        UiUtil.setTouchSwallowEnabledRec(v, enabled)
    end
end

return UiUtil

  脚本里面的原理也可以用于其他代码,如果是framework核心的cocos项目,改一改直接就可以使用。

  工作后看了不少代码,发现原理很多都相似,暂时写到这里,继续啃游戏逻辑去了。

原文地址:https://www.cnblogs.com/yangyadong66/p/9474982.html