前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >lua项目思想日常解读【1】

lua项目思想日常解读【1】

作者头像
渴望飞翔的猪
发布2022-07-17 10:48:31
1630
发布2022-07-17 10:48:31
举报
文章被收录于专栏:葵花宝典007

[先说个前提哈,以上所说的都是在lua这门语言中,不同的语言有不同的处理技巧,不过话说回来,真正的这种面向对象的思维方式作为程序都是通用的,只不过是在不同的语言有不同的数据结构来支撑的实现而已]. 今天再次看项目里面的现金赛代码,接着上篇提到的,我们是构造了一个完美二叉树的形,最开始我的比较初级(low)的想法的直接根据这个树的型(也就是指lua中的table的结构类型),即树的每个节点(table数据类型)一个大table包涵管理俩个人战斗的各种数据状态。 然后刚看了项目中的实现代码,发现上面的想法还是 too young too naive,实际上像如此大的数据状态的table需要存储管理的话,应该单独列一个模块出来处理,也就是在lua中的module ,然后里面内容也是包涵一个大table,加上各种实现处理的函数接口,调用

最后用一个全局函数OnNew () 如下 其实这个的思想也是使lua模仿c++的面向对象的编程思想来的

代码语言:javascript
复制
function OnNew()
    local b= class("BattleTree", battle_tree) --class函数是lua里面
    b:Init()
    return b
end
说明下 class()是cocos2d-x为我们封装的函数,本身Lua没有这个函数。
PS: 在Lua中类的概念就是table表,说白了,函数的代码功能主要做的就是对父类super的表进行拷贝,不必深究细节,会用就行,起码我在项目里面看到的使用calss函数就是只有复制拷贝这一个作用而已

然后再这个table实现一个OnCreate()方法 或者init方法 作用就是以初始化成员变量,完成一些数据的赋值。如下:

代码语言:javascript
复制
function battle_tree:OnCreateNode(node_id,node_level,node_no)
    self.node_id    = node_id
    self.node_level = node_level
    self.node_no    = node_no
    self.create_ts  = os.time()
end

然后这里就应该想到联系的问题了,这种思想是以完成了每个节点的俩俩人的一组对战状态的维护了,但是根据上面所说的比赛方式(32进16 - 16进8 - 8进4),我们还应该需要他们有关联的信息关系,而如何建立这种关系呢,就用到前面所建立的tree的信息了,主要就是dep 和num 这样能使他们有完善的联系,即给别人客户端也能根据这个num,dep所推出他们的各种节点的相关信息。

得有一个提供关联的SetRelation函数 如下:

代码语言:javascript
复制
function battle_tree:SetRelation(parent_node_id,lchild_node_id,rchild_node_id)
    self.parent_node_id = parent_node_id or ''
    self.lchild_node_id = lchild_node_id or ''
    self.rchild_node_id = rchild_node_id or ''
end
设置父子结构的关联 ,使得每个节点关联上父子节点的信息

最后在写一个创建整个战斗树结构的函数,其实使用二叉树的过程哈,就跟要遍历先序输出一样 代码如下:

代码语言:javascript
复制
--
--node为CreateTree的节点结构
--parent_tree为battle_tree结构
--
function CreateBattleTree(node,parent_tree)
    if node ~= nil then
        local dep   = node.dep
        local p = node.parent
        local l = node.lchild
        local r = node.rchild
        local num = node.node_num

        local node_id = GenNodeId(dep,num) --这个就是针对每个节点比赛的比赛id

        local bt = BattleTree.OnNew()
        bt:OnCreateNode(node_id,dep,num)
        battle_tree_list[node_id] = bt

        local lt = CreateBattleTree(node.lchild,bt)
        local rt = CreateBattleTree(node.rchild,bt)
        local pt = parent_tree

        bt:SetRelation((pt and pt:GetNode()),(lt and lt:GetNode()),(rt and rt:GetNode()))

        return bt
    end
end

到这里就是整个xx强的战斗树状图就建立完成了,module里面的信息就是BattleTree的结构信息里面包含关联俩个人的pk战斗的相关信息状态。

接下来的问题就是,x强树已经创建好了,比如拿32强举例,已经决出32个人了,现在我们当然知道树的每个节点对应的就是一组俩人的战斗信息了,还是先拿我初级的(low)思想来说,分别把32个人俩俩分配到树的16个根节点下,即table需要增加一个键值data为xxx_list{}里面有人员信息(uid,score),然后赢的人就去上一个节点。然后看了项目的代码实现,发现是这样分配的,还是使用了递归(发现这玩意儿实现上使用了很多递归的思想啊,看来递归还是很有用的哈);

具体是这样分配的,每个节点node都包括一个data键值为xxx_list,信息和上面我想的一样,只不过是在一开始还没战斗的时候,给所有的节点都配上这个xxx_list键值对应的人员信息,这样有个的好处就是立马能看出这个节点最后产生的俩个pk的人选,一定是在这个预先分配的xxx_list人员信息中产生的,这就是预分配的信息,也很好的能便于查看和调试 ,代码实现如下:

代码语言:javascript
复制
--均摊人员进入树中 
function HalveIntoBattleTree(node_id,data_list) --这里最开始传入的是root的node_id,data_list就是人员的list信息 {uid,score}
    if node_id == '' then
        return
    end

    local node = GetNodeByNodeId(node_id)
    if node == nil then
        Log.Error('has no node,id=' .. node_id)
        return
    end
    node.data = data_list

    local left_data_list = {}
    local right_data_list = {}
    local len = #data_list
    for i=1,len do
        if i<=math.floor(len/2) then
            table.insert(left_data_list,data_list[i])
        else
            table.insert(right_data_list,data_list[i])
        end
    end
    if node:GetRightNode() == '' then
        node.data = data_list or {}
    else
        HalveIntoBattleTree(node:GetRightNode(),left_data_list)
    end

    if node:GetLeftNode() == '' then
        node.data = data_list or {}
    else
        HalveIntoBattleTree(node:GetLeftNode(),right_data_list)
    end
end
调用的方式如下,mather_list就是人员信息表{uid,score}
HalveIntoBattleTree(GetRootNode():GetNodeId(),mather_list)

其实发现一开始项目的那个人也不是这么写的哈,也是后来为了完善代码的美观还有是以对象的方式调用,形成以上的代码,其实这也是做久了的程序员都会养成的习惯吧,难怪以前看段子,新手程序员一句话,老程序员各种考虑封装,接口实现。不过我现在感觉这样看其实有点跳来跳去有点累看得,不过还是得努力看下去的,毕竟这也是我以后要实现的思考方式。 贴一下最初简版的实现代码吧,这样能看出实现方式比较直接,而上面的实现就相等于面向对象些的实现啦。

代码语言:javascript
复制
--均摊人员进入树中
function HalveTree(root_node,data_list)
    if root_node == nil then
        --root_node.data = data_list
        return
    end

    root_node.data = data_list

    local left_data_list = {}
    local right_data_list = {}
    local len = #data_list
    for i=1,len do
        if i<=math.floor(len/2) then
            table.insert(left_data_list,data_list[i])
        else
            table.insert(right_data_list,data_list[i])
        end
    end
    if root_node.lchild == nil then
        root_node.data = data_list or {}
    else
        HalveTree(root_node.lchild,left_data_list)
    end

    if root_node.rchild == nil then
        root_node.data = data_list or {}
    else
        HalveTree(root_node.rchild,right_data_list)
    end
end

啊啊啊,发现被打脸,刚往后看了一些代码发现 ,的确是由我初始的low的想法那样的,只是对于树这种结构来说,想要找到最后的叶子节点来实现复制,也必须是通过递归的这种方式寻找到,只是若按照我的思想递归找到底下的叶子节点后,再随机分配,还得考虑从table移除已分配的人员,保证不重复分配到同一个人,这样也比较麻烦,而用上面的代码是一样的功能,不过实现上还是比较方便啦,代码也更好看吧,的确要多学学这种思想才会提高自己哈 贴一下后面分配完的代码就看清楚了:

代码语言:javascript
复制
    for k,v in pairs(battle_tree_list) do
        --Log.Error('node=' .. v:GetNodeNo())
        if v:IsLeafNode() then
            local u1= {uid=0,score=0}
            local u2= {uid=0,score=0}
            if v.data[1] ~= nil then u1 = v.data[1] end
            if v.data[2] ~= nil then u2 = v.data[2] end
            local p1 = player_list[u1.uid]
            local p2 = player_list[u2.uid]
            v:AddPlayer(p1)
            v:AddPlayer(p2)
        end
    end
    for k,v in pairs(battle_tree_list) do
        v.data = nil  --看这里分配完了之后data就没有啦,也就是只有16个叶子节点(拿32强举例)分别挂了俩个人员
    end

加油 !继续看 下篇再介绍吧 ,主要是项目里面看的编程的思想 语言暂时就lua啦

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档