[游戏开发]Unity红点系统

红点系统设计到的内容有哪些

UI界面(例如主界面)、UI上的按钮红点(例如主界面上面有各种玩法的入口)、玩法数据(例如活动玩法的完成比例,它是驱动红点是否显示的关键要素)、红点管理器(修改红点状态,注册红点物体)、树形数据结构。

红点系统的特点

  1. 数据驱动
  2. 树形结构,且数据是从下向上修改的

提问:红点UI何时会亮起

答:当这个UI打开时,树形结构这个节点是亮起状态。

提问:树形结构这个节点如何判断亮起还是熄灭?

红点是显示还是隐藏是由数据驱动的,所以这个问题就是何时会修改数据

答:有3种情况,1、登录时拉取所有功能数据,2、服务器主动推送刷新功能数据(有部分功能在服务器不断Tick计算状态)3、用户操作后刷新功能数据(比如领取邮件奖励)

红点树型脑图

玩法数据是如何与红点显示状态关联的?

以邮件系统举例,

  1. 项目启动时,拉取服务器邮件数据,客户端的邮件管理器判断邮件列表1和2是可领取状态,向红点管理器设置邮件红点的状态为亮起(true)
  2. 进入主城并显示主城UI后,主城UI调用红点管理器的注册红点方法,此方法会拿到邮件对应的红点状态并设置红点UI是否显示。此时邮件按钮亮起
  3. 当用户点击领取邮件,前后端通信一次,服务器推送最新的邮件数据,客户端邮件管理器再次判断是否有可领取邮件,此时列表里还有一个未领取邮件,并再次设置邮件红点的状态为亮起(true)。
  4. 用户再次领取邮件,服务器推送最新的邮件数据,此时邮件已全部领取完毕,设置邮件红点的状态为熄灭(false)。

树形结构的难点在哪里

以脑图为例,夏季活动有两个分支(夏令营和运动),且都是红点亮起状态

当红色链条夏令营篝火晚会完成时,我们既要设置篝火晚会、夏令营的红点状态为熄灭,还不能影响蓝色链条的红点显示状态。因为这两个链条的数据是独立的

我是如何解决这两个链条互不影响的?

--[[
    遍历tab并查找目标
    找到目标后按深度加入列表
]]
local function travTab(tab, target,path)
    local find = false
    for key, subTable in pairs(tab) do
        if type(subTable) == "table" then
            if subTable == target then
                table.insert(path,target)
                return true
            else
                find = travTab(subTable,target,path)
                if find == true then
                    table.insert(path,subTable)
                    return true
                end
            end
        end
    end
    return false
end

核心就是这个深度递归获取路径的方法,

tab是活动的根、target是篝火晚会,通过这个递归可以返回一个(1篝火晚会、2夏令营、3夏季活动、4活动)的列表。

拿到列表后for循环每一个元素的父节点是否有子物体是亮起红点的。当循环到父节点是夏季活动这个节点时,检查到夏季活动的子节点运动是红点亮起状态,那么夏季活动这个节点就不会被夏令营节点的改变而影响,实现了红色链条和蓝色链条的互不影响。

--[[
    检查父节点的所有子节点是否亮起
]]
local function CheckSubRedDot(parent)
    for index, subTab in pairs(parent) do
        if type(subTab) == "table" then
            if subTab.value == true then
                return true
            end
        end
    end
    return false
end

Lua版本红点系统实现

现在的UI业务大多数都是用Lua开发的,那我就写个Lua版本的红点系统

当我们require RedDotDefine.lua文件时,RedDot_Activity全局存在,可直接使用

制作好demo需要的UI,冬季活动的分支没做,夏季的足够演示


 

 下面是RedDotManager的源码

require 'Framework/RedDot/RedDotDefine'

--UI音频管理类--
RedDotManager = {
	IsRootLoaded = false
}
local this = RedDotManager

local RedDotDatas = {}

--[[
    遍历tab并查找目标
    找到目标后按深度加入列表
]]
local function travTab(tab, target,path)
    local find = false
    for key, subTable in pairs(tab) do
        if type(subTable) == "table" then
            if subTable == target then
                table.insert(path,target)
                return true
            else
                find = travTab(subTable,target,path)
                if find == true then
                    table.insert(path,subTable)
                    return true
                end
            end
        end
    end
    return false
end

--[[
    注册红点UI
]]
function RedDotManager.RegisterRedDotUI(target,redDotUI)
	target.RedDotUI = redDotUI
    redDotUI:SetActive(target.value == true)
end

function RedDotManager.UnRegisterRedDot() end

--[[
    检查父节点的所有子节点是否亮起
]]
local function CheckSubRedDot(parent)
    for index, subTab in pairs(parent) do
        if type(subTab) == "table" then
            if subTab.value == true then
                return true
            end
        end
    end
    return false
end

--[[
    设置红点状态
]]
function RedDotManager.SetRedDotState(tab,target,value)
    target.value = value
    if target.RedDotUI ~= nil then
        target.RedDotUI:SetActive(value)
    end

    --[[
        获取目标到根的深度路径
        tab是根,target是最深的节点
    ]]
    local path = {}
    travTab(tab,target,path)
    table.insert(path,tab)

    for index = 1, #path do--body 
        if index == #path then
            return
        end
        local parent = path[index + 1]
        parent.value = CheckSubRedDot(parent)
        if parent.RedDotUI ~= nil then
            parent.RedDotUI:SetActive(parent.value)
        end
    end
end

function RedDotManager.GetRedDotState(target)
    return target.value == true
end

 项目启动后,设置脑图中的篝火晚会和游泳节点设置为亮起

当主界面显示时,注册主界面的红点,其他所有界面启动后,注册红点都相同,就不挨个展示了

 
这个Demo中实现的玩法和上面的脑图保持一致,但只做了活动玩法的红点展示

红点系统其他实现方式

除了用Table来存储树形结构关系外,还有很多方式可以实现红点系统,例如直接用int值来存储,子节点都用根节点的值做加法,或者是乘法。所以说,只要你能找到一个方式能实现从下到上的节点索引,即可解决自下而上驱动树型结构数据的问题。

猜你喜欢

转载自blog.csdn.net/liuyongjie1992/article/details/135221832