【游戏客户端】浅谈红点系统
大家好,我是Lampard~~
最近一直在忙活数据结构和算法的东西,很久没和大家分享一下游戏逻辑了。
之前的博客中,我和大家分享了如何做商业化的充值活动,抽卡系统,装备系统。今天和大家分享一波红点系统。
根据一般的需求思路,几个小红点一般都会影响整个模块外面的总小红点,所以这些红点应该有一个数据结构去存储管理。看上图,那么结构就呼之欲出了:没错就是树!
整个红点管理机制由是三个部分组成:
- 红点管理类(redpt_mgr)
- 红点逻辑类(redpt_logic_node)
- 红点UI类(redpt_draw_node)
(1)红点管理类(redpt_mgr)
红点管理类是一个管理所有红点树的接口,方便客户端和服务端进行对红点的管理。其重要实现的功能是以下几个
function gRedPtMgr.regRedPt(id, parentNode, offsetX, offsetY, scale)
--把红点与UI控件绑定起来,offsetX, offsetY红点的偏移
end
function gRedPtMgr.unRegRedPt(id)
--解除绑定
end
function gRedPtMgr.updateRedInfo(id, num)
--给一个红点注入数据
end
local function createLogicTree()
--创建红点逻辑树
end
首先是创建红点逻辑树,其实现方式是读表,然后递归生成一个个红点逻辑类,然后把存在父子关系的红点逻辑类关联起来。然后当我们需要绑定红点的时候提供接口把红点与UI控件绑定,同时提供接口解绑和更新红点的数量。
(2)红点逻辑类(redpt_logic_node)
(1)结构
红点逻辑类主要是控制某一个红点的逻辑,记录其父子结点以及当前显示红点的状态,把自己与红点UI类给绑定起来,然后根据自身的状态控制红点UI类的显示。
其主要的数据结构如下:
function LogicNode:ctor(id)
self._id = id --红点ID
self._curSt --当前的状态
self._num --子树红点的总数
self._children = {} --子节点
self._parent = nil --父节点
self._redPtDrawNode = nil --红点UI
end
我们用self._curSt来记录当前状态,一般情况来说有一些系统需要具体显示有多少事情代办,有一些只是单纯提醒玩家点进去,那么我们的状态就分成三种:1.显示数字,2.纯红点,3.隐藏状态。很明显1和2的状态是互斥的,由红点管理类的gRedPtMgr.updateRedInfo(id, num),num参数来进行控制是否显示数字。若由于写代码的疏忽同时写入了两种状态,那么我们就优先显示数字态即可。
(2)更新
当红点数量发生变化的时候,红点管理类会调用updateRedInfo刷新,此时我们应该从叶子到树根来进行数量的更新,对于叶子结点来说,直接更新红点的数量,而非叶子结点则遍历自己的子节点,把子节点当前的红点数量相加然后对self._num字段进行更新,再对控制UI红点类的显示。无论是叶子还是非叶子结点,当self._num减到0时则更改为隐藏状态。
function LogicNode:update()
if self:isLeafNode() then
--是叶子节点,则状态由协议数据来决定
end
self._num = 0
for _, node in ipairs(self._children) do
self._num = node:getNum() + self._num
end
if self._num == 0 then
self._curSt = HIDE_ST --隐藏状态
end
end
(3)红点UI类(redpt_draw_node)
emm,这个就比较简单啦,只是一个普通的UI控件,一个红点图中间有一个label显示数字。然后由红点逻辑类来设置大小,偏移,是否显示数字,是否隐藏等属性
function DrawNode:ctor(id)
self._bg = ImageView:create()
self._bg:loadTexture("xxx/redpoint.png")
self:addChild(self._bg)
self._numLab = Label:create()
self:addChild(self._numLab)
end
(4)小结与思考
至此我们的红点系统已经完成啦。简单来说就是红点管理类(redpt_mgr)提供对外接口,管理各个红点逻辑类(redpt_logic_node)。各个红点逻辑类记录着自己的父亲,孩子结点,红点数量显示状态等信息,由此来控制着红点UI类的显示。
但是万恶的策划大大这时候提出一个要求:外部的红点点击进去的时候就消失,而最底层的结点,则根据某一些事件实现了才消失。举个例子,我们之前做了装备系统,如果某一个栏位是空的,那么会触发红点,从下而上(具体空的栏位->栏位所在的页签->背包->外部点击图标)。策划要求点击进去的时候,后三个的红点消失,而具体某个栏位的红点要上阵了装备才消失。也就是说父亲消失了,孩子还在。这和我们self._num是根据孩子结点红点数量相加是违背的。那么如何做呢?
此时我们就应该把这个深度为四的树拆成两部分,后三者为一个树,而具体某栏位的红点手动生成一个红点UI类。也就是我们不依赖红点管理类和红点逻辑类,我们自己判断更新状态的时机然后手动销毁这个节点。这样就可以实现功能了。在浏览其他博客的时候还看到一种思路,就是给红点绑定回调事件,然后根据事件监听来更改红点数量,这也是一种思路~
好的,今天的分享就到这里,谢谢大家~