cocos2d-x的lua脚本加载CocostudioUI两种方式

时间:2023-03-09 07:29:46
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 < then
return
end
for i=, childCount do
if "table" == type(children) then
parent = children[i]
elseif "userdata" == type(children) then
parent = children:objectAtIndex(i - )
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 < then
return
end
for i=, childCount do
if "table" == type(children) then
parent = children[i]
elseif "userdata" == type(children) then
parent = children:objectAtIndex(i - )
end if parent then
if name == parent.name then
return parent
end
end
end for i=, childCount do
if "table" == type(children) then
parent = children[i]
elseif "userdata" == type(children) then
parent = children:objectAtIndex(i - )
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 , options.y or ) 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 或者\cocos\editor-support\cocostudio 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()-
--TODO:操作
end
end
end
for i=, do
local buttonName = "Button_"..i
local button = ccui.Helper:seekWidgetByName(self.uiNode, buttonName)
if button ~= nil then
button:addTouchEventListener(touchEvent)
button:setTag(+i)
end
end
end

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

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

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

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