[先说个前提哈,以上所说的都是在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啦