zoukankan      html  css  js  c++  java
  • cocos2d-x的lua脚本加载CocostudioUI两种方式

    前言

       当前版本使用的是quick cocos2dx lua 3.3。UI使用cocostudio编辑器1.6.0。我们在程序里面可以使用两种方式进行解析UI。开始的时候用的是quick的方法,

    结果遇到了坑(百分比控件布局CCSUILoader.lua在解析时,没有对百分比进行处理,结果方案可以自己加上去)。

    特别提醒:

      如果在quick中使用源生的解析方案(c++),可能出现触摸bug。因为在quick中自己实现了新的触摸机制(详情请参考LuaTouchEventManager.h 中具体的实现)

    所有的触摸级别都是0,根据渲染层级处理事件

      建议:在项目实际开发中,应该自己封装一层,方便修改。

    一.quick使用cocostudio

     1.加载

    local uiNode = cc.uiloader:load("TestUI.json")
    self:addChild(uiNode)
    cc.uiloader:load("XXXX.json") 后面的参数是你的cocostudio导出文件,注意路径问题

     2.读取控件

      在程序中获取控件的方法,我们可以看下 framework/cc/uiloader/uiloader.lua, (CCSUILoader.lua文件可以看下,讲具体怎么实现的)

    -- @module uiloader
    
    --[[--
    
    初始化 cc.uiloader,并提供对外统一接口
    
    cc.uiloader 可以将CCS导出的json文件用quick的纯lua控件构建出UI布局
    
    ]]
    
    local UILoaderUtilitys = import(".UILoaderUtilitys")
    local uiloader = class("uiloader")
    local CCSUILoader = import(".CCSUILoader")
    local CCSSceneLoader = import(".CCSSceneLoader")
    
    -- start --
    
    --------------------------------
    -- 初始化 cc.uiloader,并提供对外统一接口
    -- @function [parent=#uiloader] new
    
    -- end --
    
    function uiloader:ctor()
    end
    
    -- start --
    
    --------------------------------
    -- 解析json文件
    -- @function [parent=#uiloader] load
    -- @param string jsonFile 要解析的json文件
    -- @param table params 解析参数
    -- @return node#node  解析后的布局
    
    -- end --
    
    function uiloader:load(jsonFile, params)
        local json
        if not params or not params.bJsonStruct then
            local pathInfo = io.pathinfo(jsonFile)
            if ".csb" == pathInfo.extname then
                return cc.CSLoader:getInstance():createNodeWithFlatBuffersFile(jsonFile)
            else
                json = self:loadFile_(jsonFile)
            end
        else
            json = jsonFile
        end
        if not json then
            print("uiloader - load file fail:" .. jsonFile)
            return
        end
    
        local node
    
        if self:isScene_(json) then
            node, w, h = CCSSceneLoader:load(json, params)
        else
            node, w, h = CCSUILoader:load(json, params)
        end
    
        UILoaderUtilitys.clearPath()
    
        return node, w, h
    end
    
    -- start --
    
    --------------------------------
    -- 按tag查找布局中的结点
    -- @function [parent=#uiloader] seekNodeByTag
    -- @param node parent 要查找布局的结点
    -- @param number tag 要查找的tag
    -- @return node#node 
    
    -- end --
    
    function uiloader:seekNodeByTag(parent, tag)
        if not parent then
            return
        end
    
        if tag == parent:getTag() then
            return parent
        end
    
        local findNode
        local children = parent:getChildren()
        local childCount = parent:getChildrenCount()
        if childCount < 1 then
            return
        end
        for i=1, childCount do
            if "table" == type(children) then
                parent = children[i]
            elseif "userdata" == type(children) then
                parent = children:objectAtIndex(i - 1)
            end
    
            if parent then
                findNode = self:seekNodeByTag(parent, tag)
                if findNode then
                    return findNode
                end
            end
        end
    
        return
    end
    
    -- start --
    
    --------------------------------
    -- 按name查找布局中的结点
    -- @function [parent=#uiloader] seekNodeByName
    -- @param node parent 要查找布局的结点
    -- @param string name 要查找的name
    -- @return node#node 
    
    -- end --
    
    function uiloader:seekNodeByName(parent, name)
        if not parent then
            return
        end
    
        if name == parent.name then
            return parent
        end
    
        local findNode
        local children = parent:getChildren()
        local childCount = parent:getChildrenCount()
        if childCount < 1 then
            return
        end
        for i=1, childCount do
            if "table" == type(children) then
                parent = children[i]
            elseif "userdata" == type(children) then
                parent = children:objectAtIndex(i - 1)
            end
    
            if parent then
                if name == parent.name then
                    return parent
                end
            end
        end
    
        for i=1, childCount do
            if "table" == type(children) then
                parent = children[i]
            elseif "userdata" == type(children) then
                parent = children:objectAtIndex(i - 1)
            end
    
            if parent then
                findNode = self:seekNodeByName(parent, name)
                if findNode then
                    return findNode
                end
            end
        end
    
        return
    end
    
    -- start --
    
    --------------------------------
    -- 按name查找布局中的结点
    -- 与seekNodeByName不同之处在于它是通过node的下子结点表来查询,效率更快
    -- @function [parent=#uiloader] seekNodeByNameFast
    -- @param node parent 要查找布局的结点
    -- @param string name 要查找的name
    -- @return node#node 
    
    -- end --
    
    function uiloader:seekNodeByNameFast(parent, name)
        if not parent then
            return
        end
    
        if not parent.subChildren then
            return
        end
    
        if name == parent.name then
            return parent
        end
    
        local findNode = parent.subChildren[name]
        if findNode then
            -- find
            return findNode
        end
    
        for i,v in ipairs(parent.subChildren) do
            findNode = self:seekNodeByName(v, name)
            if findNode then
                return findNode
            end
        end
    
        return
    end
    
    -- start --
    
    --------------------------------
    -- 根据路径来查找布局中的结点
    -- @function [parent=#uiloader] seekNodeByPath
    -- @param node parent 要查找布局的结点
    -- @param string path 要查找的path
    -- @return node#node 
    
    -- end --
    
    function uiloader:seekNodeByPath(parent, path)
        if not parent then
            return
        end
    
        local names = string.split(path, '/')
    
        for i,v in ipairs(names) do
            parent = self:seekNodeByNameFast(parent, v)
            if not parent then
                return
            end
        end
    
        return parent
    end
    
    -- start --
    
    --------------------------------
    -- 查找布局中的组件结点
    -- @function [parent=#uiloader] seekComponents
    -- @param node parent 要查找布局的结点
    -- @param string nodeName 要查找的name
    -- @param number componentIdx 在查找组件在它的直接父结点的位置
    -- @return node#node 
    
    
    --[[--
    
    查找布局中的组件结点
    
    ~~~ lua
    
    -- "hero" 是结点名称
    -- 1 是 "hero"这个结点下的第一个组件
    local hero = cc.uiloader:seekComponents(parentNode, "hero", 1)
    
    ~~~
    
    ]]
    -- end --
    
    function uiloader:seekComponents(parent, nodeName, componentIdx)
        local node = self:seekNodeByName(parent, nodeName)
        if not node then
            return
        end
        node = self:seekNodeByName(node, "Component" .. componentIdx)
        return node
    end
    
    -- private
    function uiloader:loadFile_(jsonFile)
        local fileUtil = cc.FileUtils:getInstance()
        local fullPath = fileUtil:fullPathForFilename(jsonFile)
    
        local pathinfo  = io.pathinfo(fullPath)
        UILoaderUtilitys.addSearchPathIf(pathinfo.dirname)
    
        local jsonStr = fileUtil:getStringFromFile(fullPath)
        local jsonVal = json.decode(jsonStr)
    
        return jsonVal
    end
    
    function uiloader:isScene_(json)
        if json.components then
            return true
        else
            return false
        end
    end
    
    return uiloader

      button我们肯定会和他打交道的,这里我说下。在CCSUILoader.lua中我们可以看到,这里加载的是quick自己的button控件

    如果我们没有在cocostudio中设置button的选中和禁止图片,这里点击是没有任何效果的,而使用c++时,会点击方法效果,我们可以根据自己的需求做相应修改

    function CCSUILoader:createButton(options)
        local node = cc.ui.UIPushButton.new(self:getButtonStateImages(options),
            {scale9 = options.scale9Enable,
            flipX = options.flipX,
            flipY = options.flipY})
    
        if options.opacity then
            node:setCascadeOpacityEnabled(true)
            node:setOpacity(options.opacity)
        end
        if options.text then
            node:setButtonLabel(
                cc.ui.UILabel.new({text = options.text,
                    size = options.fontSize,
                    color = cc.c3b(options.textColorR, options.textColorG, options.textColorB)}))
        end
        if not options.ignoreSize then
            node:setButtonSize(options.width, options.height)
        end
        node:align(self:getAnchorType(options.anchorPointX or 0.5, options.anchorPointY or 0.5),
            options.x or 0, options.y or 0)
    
        return node
    end

    下面是一个读取按钮的例子:

    
    
    local button = cc.uiloader:seekNodeByPath(self.uiNode, buttonName)
    if button ~= nil then 
       button:addButtonClickedEventListener(function(...)
       self:onCickSublistButton()
    end)
     

    二.cocos2dx自带使用cocostudio

      我觉得这个还是比较好的,因为触控一直在更新完善。而quick目前是没有在维护。

    1.加载

    local uiNode = ccs.GUIReader:getInstance():widgetFromJsonFile("Test.json")
    uiNode:addTo(self)

    可以参考GUIReader.lua 或者cocoseditor-supportcocostudio CCSGUIReader.h (GUIReader.lua 是c++绑定到lua 时生成的api)

     2.读取控件

      这里控件的解析我们使用的是Helper ,可以参考 api Helper.lua 和具体的c++类Helper.h

    --------------------------------
    -- @module Helper
    -- @parent_module ccui
    
    --------------------------------
    -- brief Get a UTF8 substring from a std::string with a given start position and length<br>
    -- Sample:  std::string str = "中国中国中国";  substr = getSubStringOfUTF8String(str,0,2) will = "中国"<br>
    -- param start The start position of the substring.<br>
    -- param length The length of the substring in UTF8 count<br>
    -- return a UTF8 substring
    -- @function [parent=#Helper] getSubStringOfUTF8String 
    -- @param self
    -- @param #string str
    -- @param #unsigned long start
    -- @param #unsigned long length
    -- @return string#string ret (return value: string)
            
    --------------------------------
    -- 
    -- @function [parent=#Helper] changeLayoutSystemActiveState 
    -- @param self
    -- @param #bool bActive
            
    --------------------------------
    -- 
    -- @function [parent=#Helper] seekActionWidgetByActionTag 
    -- @param self
    -- @param #ccui.Widget root
    -- @param #int tag
    -- @return Widget#Widget ret (return value: ccui.Widget)
            
    --------------------------------
    -- Finds a widget whose name equals to param name from root widget.<br>
    -- param root      widget which will be seeked.<br>
    -- name             name value.<br>
    -- return finded result.
    -- @function [parent=#Helper] seekWidgetByName 
    -- @param self
    -- @param #ccui.Widget root
    -- @param #string name
    -- @return Widget#Widget ret (return value: ccui.Widget)
            
    --------------------------------
    -- Finds a widget whose tag equals to param tag from root widget.<br>
    -- param root      widget which will be seeked.<br>
    -- tag             tag value.<br>
    -- return finded result.
    -- @function [parent=#Helper] seekWidgetByTag 
    -- @param self
    -- @param #ccui.Widget root
    -- @param #int tag
    -- @return Widget#Widget ret (return value: ccui.Widget)
            
    --------------------------------
    -- 
    -- @function [parent=#Helper] doLayout 
    -- @param self
    -- @param #cc.Node rootNode
            
    return nil

    下面是button的例子:

    local button = ccui.Helper:seekWidgetByName(self.uiNode, buttonName)
    function CampMainlayer:initButton()
        local function touchEvent(sender,event)
             if event == ccui.TouchEventType.ended then
                if sender ~= nil then
                    local tag = sender:getTag()-1000
                    --TODO:操作
                end    
            end
        end
        for i=1,3 do
            local buttonName = "Button_"..i
            local button = ccui.Helper:seekWidgetByName(self.uiNode, buttonName)
            if button ~= nil then 
                button:addTouchEventListener(touchEvent)
                button:setTag(1000+i)
            end
        end
    end

    注意 ccui.TouchEventType.ended  这是在 cocos.ui.GuiConstants中,所以我们想用这些的话,需要 require("cocos.ui.GuiConstants")。

      我们在实际的项目开发中,肯定会遇到很多问题,当然,遇到问题我们可以在网上找,但是并不是所有的问题都能找到,所以,自己动手解决问题的能力很重要,

    对于我们来说,去看源码,看具体的实现,就能很快找到解决问题的方式。

    如果有什么问题,请加我的QQ776274781,或者群:102349463 。大家一起学习。

  • 相关阅读:
    Neptune w800开发版ubuntu linux环境编译通过——如何搭建开发环境
    neptune HarmonyOS开发板视频教程-环境搭建-编译-烧录-外设控制
    Neptune开发板与hiSpark开发板底板的管脚不兼容
    《设计心理学》要点(上)
    NLP(三十二):大规模向量相似度检索方案
    VIM编辑器设置
    (十一)pytorch加速训练的17种方法
    (十)pytorch多线程训练,DataLoader的num_works参数设置
    NLP(三十一):用transformers库的BertForSequenceClassification实现文本分类
    NLP(三十):BertForSequenceClassification:Kaggle的bert文本分类,基于transformers的BERT分类
  • 原文地址:https://www.cnblogs.com/zhangfeitao/p/4560165.html
Copyright © 2011-2022 走看看