34

用树实现客户端红点系统

 4 years ago
source link: https://www.tuicool.com/articles/i6nIVfB
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

红点大家一定不陌生,不管是游戏还是软件,甚至是手机系统都通过红点的直观方式来告知用户或者玩家“你有新的消息,请注意查收”。

红点系统是一个比较让人讨厌的系统,至少对于游戏开发人员来说是的。因为涉及的地方多,层次深,逻辑判定复杂,表现多样,有的需要服务器判定,有的需要客户端判定,所以处理起来十分麻烦。

经历过的几个项目,都因为前期没有针对红点系统做整体规划,所以后期就栽在红点的需求和表现上,有3-4套红点系统并行,重构了1次仍然不能从根本上解决,但总的来说已经好很多了,那么红点系统的方法在这里跟大家分享一下。

红点系统总览

3ayeumz.png!web

如上图所示,规划红点系统的时候,我们将整个系统分为独立的三个部分:结构层、驱动层和表现层。

结构层用来部署红点的层级结构,做过红点系统的都知道,很多时候红点系统的层级都很深,所以我们要用一个结构来描述层级,这个就是我们今天的主题——树结构。

驱动层是指如何驱动这个树结构产生状态变化,以及状态变化之后如何将变化的行为通知到指定的表现层,在一定的程度上将数据和表现分离开。

表现层就专门承担表现的职责,比如:有的红点就是一个单纯的红点,有的需要显示数字,有的可能是图标晃动,有的是显示new标签,有的是播放特效等等。这些都可以归属在表现层统一去管控。

结构设计

我们先来看一个示例,示例是我用UGUI摆的,大家将就看下吧。

nENfQjn.png!web

我们可以看到主界面有三个主要入口,分别是:公会、任务、邮件。邮件界面里,又分为三个标签:系统、队伍、公会。

那么如果按照树的结构去分析,树结构大概如下图:

IrUfIvy.png!web

以主界面为根节点,其它节点都为树的各个子节点或者叶子节点。这里只对邮件一个模块做了规划,所以邮件下面还有3个子节点,本章节也是基于这个规划去设计的Demo和代码。

代码设计

既然是树结构,那么我们首先看看树结构怎么规划。如下:

qeAnQnm.png!web

定一个const类,按照系统来划分树的各个节点,比如:上面展示的红点树结构,代码可以使用string来完成。这个定义不仅仅是用来规划结构,也会为后面事件驱动的时候提供key。

有了树结构的表示之后,再看看节点怎么表示:

A3UnmyU.png!web

几个字段的意义注释比较清楚,就不多做讲解。节点也定义清楚了之后,看看RedPointSystem要做哪些事情。

eqqIFju.png!web

第一个是定义一个事件驱动的Delegate类型,第二个是要持有红点树的Root节点,第三个是将需要关心的红点树加入到List中方便启动时候进行初始化。

接下来就是初始化了:

qAR3Y3M.png!web

代码很简单,就是把每一个string都切割成数组,然后把数组处理成树的结构。

现在树结构有了,那么我们要对树结构设置事件驱动,其实就是给这棵树绑定一个事件回调:

y2UbQfe.png!web

这里要注意的是,因为传进来的是string,所以必须要处理到最后一个节点才是真正需要绑定回调的节点。

到这里,树结构也好了,事件监听也好了,那么驱动层呢?如下:

2aUR323.png!web

这个函数和上面那个设置Callback的非常像,实际项目需要考虑将2个公有部分抽出来做公共函数,我这里为了快速展示,代码写的不简洁。总的来说,其实就是找到对应的节点,给它设置具体的红点数量。

也就是说红点的数量其实跟整套红点系统无关,它可以是来自服务器的协议通知,也可以是客户端自己传递的数据,或者从文件里读取出来的。总之,红点系统本身只关注红点的产生和管理以及表现,不关心数据的来源。

上面的代码里关联了一个SetRedPointNum的函数,这个是写在RedPointNode解构里的。看看这个函数:

r2mENzN.png!web

这里需要特别注意,我们的红点树是有严格层级界定的,也就是说所有非叶子节点的红点都应该是来自于它孩子节点的统计,比如:主界面上邮件显示的数量,是邮件界面里面3个标签的数量之和,不允许直接对非叶子节点直接设置红点数量,如果非要有相关逻辑,比较建议在表现层做独立表现(每个节点都是可以独立绑定回调事件的)。

这里又涉及了两个自己内部的函数,一并贴出来:

Bfy6zmn.png!web

整个红点系统到这里就设计完成了。

实际展示

来看看实际表现吧!

Demo代码:

MbeUBfn.png!web

事件处理函数:

BvUrYne.png!web

界面表现:

JniI3u7.png!web

日志输出:

nuMfaeA.png!web

符合预期了!

后话

开头我们说了,红点系统有三个模块,目前Demo只实现了结构层和驱动层,表现层没有做统一规划,不过这个没有难度,在所有的监听函数里都导向到一个统一的处理类,通过传入样式进行分类处理就好了。

因为是Demo演示,只展示了思想和效果,代码不是很简洁,性能也不是最好,所以如果大家取用需要再斟酌数据结构和性能。

另外,这只是红点系统的一种实现方式,并不能解决所有情况,但是目前来说,绝大多数的红点需求都可以通过这个方案解决了。

这是侑虎科技第630篇文章,感谢作者放牛的星星供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)

作者主页: https://www.zhihu.com/people/niuxingxing ,作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK