红点系统

  • 之前我接触的系统都是耦合性比较高的,一旦 UI 表现修改,或者层级有修改,代码改动非常大,于是老大让我参考前缀树和链表重写一个红点系统。
  • 新写的红点系统比较抽象,第一次看可能都不是很好理解,在看的时候一定要明确将数据层和逻辑层分开抽象,这两个层级有关联,但是不完全相同。所以抽象完之后有一个好处就是,我用一个字典来代替了层级逻辑,这样即使 UI 怎么改我都只用改一下逻辑字典和 UI 表现上的字典,代码不用变化。

结构

  • 如图,一个简单的红点结构如下,每一个 Item 都有一个对应的层级和 ID,可以根据层级和 ID 确定任意一个子节点。
    红点Inspector面板截图
  • 这里值得注意的是,这个层级是逻辑上的层级,是数据层面的,表现层面用的时候不要这么死板,比如主页里面嵌套了一个 UI,这里的 UI 和主页都显示同一个逻辑红点,那么在上面的序列化填写的时候,这两个其实是一模一样的,不需要写两个数据。

逻辑

  • 红点的刷新逻辑是,如果我更新了 【“4”,0】对应的子节点时,需要沿着当前路径更新他之前的每一个父节点 【“3”,1】、【“2”,1】【“1”,0】【“0”,0】。
  • 这里的逻辑有点类似于链表,我用一个类 RedPointNode 来表示每个节点,当然每个节点下面不止一个节点,所以每个节点都有一个层级和该层级下的 Uid 来查找。
  • 在游戏中有许多不同的模块,所以如果用 Manager 来管理红点肯定是先按照模块类型的枚举 (EGameModule) 建立字典,然后每个模块又有不同的红点逻辑。
  • 一个红点的路径就可以用一个 Dictionary<string,string> 来表示,或者你用一个 List<KeyValuePair<string,string>> 也是一样的。

代码细节

  • 红点的刷新用消息通知出去,然后在表现层监听就行了。
  • 不需要刷新红点状态的地方不要及时刷新,在底层设置数据为 “Dirty”,然后在下次获取红点状态的时候根据这个 “Dirty” 状态来判断是否需要重新读取红点。
  • 有的时候获取红点状态不仅仅是数据层面上的依赖,还需要临时数据,比如有一个红点每次上线都有,但是玩家只要打开过一次这个界面就不显示红点了,这个时候就在获取红点状态的时候增加了一个 Func orState 的参数,这样红点的状态就会同时依赖两个数据的 or 值。
1
2
/// Func<bool> orState 的回调默认是没有的,只有在需要的时候传进去
public bool GetRedPoint(EGameModule type, Dictionary<string, long> affixPair, Func<bool> orState = null){...}