zl程序教程

您现在的位置是:首页 >  其他

当前栏目

cocos2dx(3.17)中csb文件使用方法

文件方法 使用 cocos2dx
2023-06-13 09:16:26 时间

开发环境:xcode 、vscode 开发语言:lua

一、手写代码加载csb文件,并获取控件

--加载csb场景文件,并将场景添加到节点中。
local node = cc.CSLoader:createNode("MenuScene.csb")
self:addChild(node)
--获取场景中的根节点(场景的跟节点一般是容器)
local rootLayout = node:getChildByName("Panel_2")
--强制转换,目前还没搞懂为啥要强制转换,可有可无,测试不写这串代码,一样可以获取到它的子节点。
-- local rootNode = tolua.cast(root, "ccui.Widget")
--获取控件(按钮  复选框   图片   文本 进度条  滑动条  出入框等)
local button =rootLayout:getChildByName("Button_2")
--给控件添加事件(不同控件,他的事件类型不同,使用的方法也就不同,),下面是给按钮添加点击事件
button:addClickEventListener(function(sender,eventType) 
            print("点击了开始按钮")
end)    

控件的通用事件

一般想封装控件的通用事件的话,可以通过addTouchEventListener(sender,eventType)来添加事件,下面示例:

--[[
    btn 控件本身对象
    ended 事件类型(放开)对应的回调函数
    began 事件类型(按下)对应的回调函数
    moved 事件类型(移动)对应的回调函数
    canceled 事件类型(取消)对应的回调函数
]]
function cc.exports.setButtonFunction(btn, ended, began, moved, canceled)
    btn:addTouchEventListener(function(sender, eventType)
        if eventType == ccui.TouchEventType.began then
            if began then began(sender) end
        elseif eventType == ccui.TouchEventType.ended then
            if ended then ended(sender) end
        elseif eventType == ccui.TouchEventType.moved then
            if moved then moved(sender) end
        elseif eventType == ccui.TouchEventType.canceled then
            if canceled then canceled(sender) end
        end
    end)
end

二、通过mvc ViewBase加载csb文件

博主一般都采用这种方法

local MainScene = class("MainScene",cc.load("mvc").ViewBase)
    MainScene.RESOURCE_FILENAME="MenuScene.csb"    --自己在cocos studio上建立的csb文件导入工程文件res文件夹下面
    MainScene.RESOURCE_BINDING = {
        ["Button_2"]   = {

            ["varname"] = "bn_StartGame",  

            ["events"] = { 
                {
                    event = "touch" ,  
                    method ="onBack"   
                }
            }  
        }
    } 
    funcation MainScene:ctor()
        self.bn_StartGame:addClickEventListener(function(sender,eventType)
            print("点击了开始按钮")
        end)
    end

    funcation MainScene:onBack()
        print("触摸了")
    end

return MainScene

1、MainScene.RESOURCE_FILENAME=”MenuScene.csb”

这个变量是设置场景的csb文件名称,读取时在ViewBase类中读取的 下面会讲一下ViewBase类怎么读取的。

2、MainScene.RESOURCE_FILENAME

这个变量是设置绑定控件,获取控件的实例

MainScene.RESOURCE_BINDING = {
       ["Button_2"]   = {

           ["varname"] = "bn_StartGame",  

           ["events"] = { 
               {
                   event = "touch" ,  
                   method ="onBack"   
               }
           }  
       }
   } 

使用方式模板(两种方式):

MainScene.RESOURCE_BINDING =
{
    --不添加事件
    ["cocos控件名"] = {["varname"] = "引用变量名" } 
    --添加事件
    ["cocos控件名"] = {["varname"] = "引用变量名",["events"]={{["event"]="事件类型(原生现在支持一种)",["method"]="回调函数"},...}} 
}

获取子控件
self.root = self:getResourceNode()
local Button = self.root:getChildByName("Button_1")

三、ViewBase类源码讲解 源码示例:

local ViewBase = class("ViewBase", cc.Node)

function ViewBase:ctor(app, name)
    self:enableNodeEvents()
    self.app_ = app
    self.name_ = name

    -- 检查子类中是否设置RESOURCE_FILENAME属性,并得到他的value值
    local res = rawget(self.class, "RESOURCE_FILENAME")
    if res then
        --加载csb文件
        self:createResourceNode(res)
    end
    --检查子类中是否设置RESOURCE_BINDING属性,并得到他的value值
    local binding = rawget(self.class, "RESOURCE_BINDING")
    if res and binding then
        --获取控件的实例
        self:createResourceBinding(binding)
    end
    --判断子类有没有重写onCreate方法,有,调用子类的onCreate方法
    if self.onCreate then self:onCreate() end
end

function ViewBase:getApp()
    return self.app_
end

function ViewBase:getName()
    return self.name_
end

function ViewBase:getResourceNode()
    return self.resourceNode_
end
--[[
    *加载csb文件的方法
    *resourceFilename 文件名称(带后缀名)
]]
function ViewBase:createResourceNode(resourceFilename)
    --判断是否已经加载过csb文件
    if self.resourceNode_ then
        --移除自己
        self.resourceNode_:removeSelf()
        --设置为nil
        self.resourceNode_ = nil
    end
    --通过CSLoader加载csb文件,得到一个节点
    self.resourceNode_ = cc.CSLoader:createNode(resourceFilename)
    assert(self.resourceNode_, string.format("ViewBase:createResourceNode() - load resouce node from file \"%s\" failed", resourceFilename))
    --将节点添加到该父节点(场景,层)中
    self:addChild(self.resourceNode_)
end
--[[
    *绑定控件
    *binding 在ViewBase子类中设置的RESOURCE_BINDING(规则模板(表))
]]
function ViewBase:createResourceBinding(binding)
    assert(self.resourceNode_, "ViewBase:createResourceBinding() - not load resource node")
    --遍历规则表
    for nodeName, nodeBinding in pairs(binding) do
        --节点通过名称直接获取子控件实例
        --这里就是我上面说的问题所在了,这里是直接通过根节点获取控件,往往,根节点的子节点是容器,而不是控件,所以这里会得不到控件
        local node = self.resourceNode_:getChildByName(nodeName)
        --如果设置变量名不为nil
        if nodeBinding.varname then
            --则将node赋值类nodeBinding.varname变量
            self[nodeBinding.varname] = node
        end
        --遍历规则表中的事件
        --nodeBinding.events or {}这个表达式相当于三目运算 nodeBinding.events~=nil?nodeBinding.events:{}
        for _, event in ipairs(nodeBinding.events or {}) do
            --原生这里只支持touch事件,如果有别的需求可自行添加
            if event.event == "touch" then
                --给控件设置onTouch事件并设置回调函数。
                node:onTouch(handler(self, self[event.method]))
            end
        end
    end
end
--[[
    *跳转场景(翻译:展示场景)
    *transition 衔接动画
    *time  衔接动画播放时间
    *more  动画类型
]]
function ViewBase:showWithScene(transition, time, more)
    self:setVisible(true)
    local scene = display.newScene(self.name_)
    scene:addChild(self)
    display.runScene(scene, transition, time, more)
    return self
end

return ViewBase

修改createResourceBinding方法,达到可以使用RESOURCE_BINDING来绑定控件事件的目的(修复原生方法不能绑定使用容器包裹的控件的问题。)

--新增一个dom树表,用于存储dom树各个节点
ViewBase.dom = {}
--[[
    *递归遍历整个场景树中的容器和控件,将容器和控件存入dom表中
    *rootNode 节点类型
]]
local function recursionChlidNOde(rootNode)
    local  children = rootNode:getChildren()
    for _,childNOde in ipairs(children or {}) do
        local name =childNOde:getName()
        print("name ",name)
        ViewBase.dom[name]=childNOde
        recursionChlidNOde(childNOde)
    end

end
function ViewBase:createResourceBinding(binding)
    assert(self.resourceNode_, "ViewBase:createResourceBinding() - not load resource node")
    recursionChlidNOde(self.resourceNode_)
    for bindWidgetName, ruleTable in pairs(binding) do
        for widgetName,node in pairs(ViewBase.dom) do
            print(widgetName,tolua.type(node)) 
            if ruleTable.varname and widgetName==bindWidgetName then
                self[ruleTable.varname] = node
                for _, event in ipairs(ruleTable.events or {}) do
                    if event.event == "touch" then
                        node:onTouch(handler(self, self[event.method]))
                    end
                end
            end
        end

    end
end