Unity开发——红点系统设计

Wesley13
• 阅读 1253

在开发途中,因为红点的逻辑比较宏观,所以很容易养成开发完功能,到处补红点逻辑的坏习惯,也因此踩过不少坑,这两天撸了下项目的红点系统,顺便自己也写了另一版。

也分享下红点的思路。

Unity开发——红点系统设计

首先红点系统的基础机制基本为上图关系

所以是刚好满足多叉树的结构关系,因此大部分红点设计逻辑都是用多叉树来做的

下面是用多叉树实现的红点关系管理树

树的外部接口:

绑定红点数据变更后的代理事件

提供根据Key查询红点状态的功能

使用这种方式,开发的时候可以很宏观的理清楚红点的父子逻辑,做配置项的时候红点的层级关系就会非常清晰明了了

--配置项 ===>
redTree = {
    ["RedRoot"] = {
       ["ModuleRed"] = {
           ["Tab1"]={
                ["业务1"] = {},
                ["业务2"] = {},   
                ["业务3"] = {},  
           },
           ["Tab2"] = {
                ["业务4"] = {},
           },
           ["Tab3"] = {
               ["业务5"] = {},
               ["业务6"] = {},     
           },
       }
    }
})module("RedTree", package.seeall);

RedTree =  class("RedTree")  --class为项目封装的一层面向对象的实现,可不做深究。
RED_NODE_TYPE = {
 ROOT = 1, --根节点
 FORK = 2, --分叉节点
 LEAF = 3 --叶节点
}
--创建一颗红点树
--如果有原来红点协议的key,绑上去,给根节点显示
function RedTree:ctor(key,serverRedkey)
  
    self.serverRedkey = serverRedkey
    self.redNodeDic = {}
    self.cachaKey = {}  --防止创建的时候,父节点比子节点还要晚创建,如果出现这种情况,缓存一份关联数据,当父节点key被创建时再简历父子联系
    self.nodeTree = {}
    local treeConfig = redTree 
    self:creatTree(treeConfig[key],key)
end


--创建树
 function RedTree:creatTree(config,rootKey)
    --根节点
    self.nodeTree = self:getChild(config,rootKey,nil,true)
end 
--递归节点
 function RedTree:getChild(cfg,key,parentNode,isRoot)
   
    if  next(cfg) == nil then
        local mNode =  RedNode.new(parentNode,nil,key)
        self.redNodeDic[key] = mNode
        return  mNode
    end
    local curNode = {}
    if isRoot then
            curNode =   RedNode.new(nil,RED_NODE_TYPE.ROOT,key)
            self.root = curNode
    else
            curNode =   RedNode.new(parentNode,nil,key)
    end
    self.redNodeDic[key] = curNode
    for _key,tab  in pairs(cfg) do
        curNode:addChild(self:getChild(tab,_key,curNode,false)) 
    end
    return curNode
end



--绑定外层红点开关显示方法
--可不绑,自己找红点显示的时机
function  RedTree:bindRedDelegate(key,delegate)
    self.redNodeDic[key].changeCallBack = delegate
end



--获取某个节点的红点状态
function RedTree:getRedStateByKey(key)
    if self.redNodeDic[key].type == RED_NODE_TYPE.ROOT then

    else
        return self.redNodeDic[key]:getRedNum()
    end
end


--设置某个Key的红点状态
function RedTree:setRedNumByKey(key,num)
    self.redNodeDic[key]:setSelfRedNum(num)
end


RedNode =  class("redNode")
function RedNode:ctor(parentNode,nodeType,key,changeCallBack)
    self.key = key
    self.childList = {}
    self.parentNode = parentNode
    self.nodeType = nodeType
    self.selfRedNum = 0
    self.redState = false
    self.changeCallBack = function(num)
      
        if changeCallBack~= nil  then
            changeCallBack(num)
        end
    end 
end


--计算子节点的红点
function RedNode:getRedNum()
    local mNum = 0 
    --遍历下层子节点的红点数量
    for i,redNode  in ipairs(self.childList) do
        local num =   redNode.selfRedNum
        mNum  =  mNum + num
    end
    mNum  = mNum + self.selfRedNum
    return mNum
end

function RedNode:addChild(node)
   table.insert(self.childList,node)
end

--设置自身红点数量
function RedNode:setSelfRedNum(num,state)
    --有变化才通知,无变化不做更新
    if self.selfRedNum ~=  num then 
        self.selfRedNum =  num  
        if self.changeCallBack ~= nil then       
            self.changeCallBack(self.selfRedNum)
        end
        --通知父层
        self:sendRed(self.parentNode)
    end
end


--父层检查红点状态
--父层红点数量以父层
function RedNode:sendRed(node)
  
    if node.nodeType == RED_NODE_TYPE.ROOT then
        return
    end
    node.selfRedNum = node:getRedNum()
    if node.changeCallBack ~= nil then
        node.changeCallBack(node.selfRedNum)
    end
    if  node.parentNode == nil then
     error(“父节点为空”)end

    self:sendRed(node.parentNode)

end

另外一种方式是项目目前使用的,不用树来实现层级关系,每个需要红点的游戏实例对象都绑定N个key

父层:绑定  业务1  业务2  业务3  3个key,每次变更,通过或的关系来处理父层自己的红点状态

子层:业务1绑定业务1key,业务2绑定业务2key,业务3绑定业务3key

这样的结构捋下来其实也是一个多叉树。只是没有内聚业务逻辑而已

在开发功能模块的时候由于都是分布依赖在各个实例对象上的,所以整个红点的“网”非常散,导致后续红点逻辑维护比较困难。

不过这个两者的设计初衷都是规避大量遍历红点对象造成的性能问题,目前使用起来也都能符合需求。

至于哪种好,要看具体的业务需求吧~

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
JS 苹果手机日期显示NaN问题
问题描述newDate("2019122910:30:00")在IOS下显示为NaN原因分析带的日期IOS下存在兼容问题解决方法字符串替换letdateStr"2019122910:30:00";datedateStr.repl
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这