Calmer的文章

  • 首页
  • 文章归档
  • 关于页面

  • 搜索
体验游戏 笔记 推荐 工具链 工具使用 小游戏 插件 UI 软件 教程

红点树

发表于 2020-04-21 | 分类于 游戏开发 | 0 | 阅读次数 1033

前言

在游戏开发过程中,红点是我们非常常用的一个功能,他便于通知玩家用户去点击某些按钮,进入到策划者希望玩家看到的页面,包括游戏中的活动系统、获得新道具后等。
不过他有一个痛点就是,需要判断诸多条件,并且只要一个条件发送改变就需要对相应的红点的其他条件再进行判别。管理起来十分比较困难。
针对此痛点,完成红点树管理逻辑。

每一个逻辑功能,都是有一颗独立的红点树


分析思考

我们借鉴订阅者设计模式,来书写红点树管理的代码。
管理方案:红点状态事件和具体的物体是分离的,即你订阅了此红点状态以后,才会在UI关联,而具体的红点状态是如何变更的是关联于具体红点节点下的子事件的变化(某一判断条件就是一个子事件)


具体功能

既然红点功能可以很好的看作一个树结构。还有一个重要的特效就是父节点的红点状态不会影响子节点,但是子节点的红点状态可以影响其父节点。

  • 相比于原来红点添加方式,原来每次红点更新都需要重新对多条件进行计算,产生了很多不必要的冗余运算
  • 现在每个红点只在创建和变更的时候计算,会消耗一些空间保存,但是大大减少了红点计算次数和红点处理混乱的问题。

管理方案:红点状态与GameObject分离,即使没有Bind游戏物体,状态依旧存在。

以下列出关键函数

  • CreateNode函数
    创建一个NodeEvent,其可以供UI层进行绑定其红点状态
  • Bind函数
    将UI具体表现物件与NodeEvent状态绑定起来
  • Unbind函数
    将UI具体表现物件和NodeEvent状态解绑
  • UnbindObject函数
    通过gameObject解除其红点事件bind
  • Add函数(NodeStr,EventStr)
    给NodeEvent(结点事件)添加一个ConditionEvent(条件事件)
  • Removed函数(NodeStr,EventStr)
    去除NodeEvent(结点事件)中的一个ConditionEvent(条件事件)
  • Refresh函数(NodeStr,IsIgnoreParentList)
    当一个NodeStr的ConditionEvent或SubNodeEvent发生变化,更新其自身节点以及以上关联节点的红点状态。
  • AddParentNode函数
    将一个NodeEvent与另一个NodeEvent建立父子关系
  • RemoveParentNode函数
    将一个NodeEvent与另一个NodeEvent断开父子关系

事件说明:
_N结尾为NodeStr或者说NodeEvent 可以用于bindGameObject 或者建立父子管理
_C结尾为ConditionEvent或者EventStr,可以驱动NodeEvet的红点状态

RedPointManager.lua

RedPointManager={
    redList={},
    objMapStr={}
}

function RedPointManager:CreateNode(nodeStr)
    if not self.redList[nodeStr] then
        self.redList[nodeStr]={}
        self.redList[nodeStr].gameObjectList={}
        self.redList[nodeStr].parentList={}
        self.redList[nodeStr].eventList={}
        self.redList[nodeStr].redParams={}
    end
end

function RedPointManager:FreeNode(nodeStr)
    if self.redList[nodeStr] then
        self.redList[nodeStr].gameObjectList=nil
        self.redList[nodeStr].parentList=nil
        self.redList[nodeStr].eventList=nil
        self.redList[nodeStr].redParams=nil
        self.redList[nodeStr]=nil
    end
end

function RedPointManager:Bind(nodeStr,gameObject,offset,size)
    if not self.redList[nodeStr] then
        self:CreateNode(nodeStr)
    end
    self.redList[nodeStr].gameObjectList[gameObject]=gameObject
    self.redList[nodeStr].redParams[gameObject]={offset=offset,size=size}

    if not self.objMapStr[gameObject] then
        self.objMapStr[gameObject]={}
    end
    table.insert(self.objMapStr[gameObject],nodeStr)

    self:Refresh(nodeStr,true)
end

function RedPointManager:UnBind(nodeStr,gameObject)
    if self.redList[nodeStr] then
        if not FairyGUITools.IsNil(self.redList[nodeStr].gameObjectList[gameObject]) then
            FairyPointUtils.RemoveRed(gameObject)
        end
        self.redList[nodeStr].gameObjectList[gameObject]=nil
        self.redList[nodeStr].redParams[gameObject]=nil
        --是否还需要释放掉字符串
    end
end

function RedPointManager:UnBindAll(nodeStr)
    if self.redList[nodeStr] then
        if(TableCount(self.redList[nodeStr].gameObjectList)~=0) then
            for _,v in pairs(self.redList[nodeStr].gameObjectList) do
                if not FairyGUITools.IsNil(v) then
                    FairyPointUtils.RemoveRed(v)
                end
            end
        end
        self.redList[nodeStr].gameObjectList={}
        self.redList[nodeStr].redParams={}
        -- self:FreeNode(nodeStr)
    end
end


function RedPointManager:UnBindObject(gameObject)
    if self.objMapStr[gameObject] then
        for i=1,#self.objMapStr[gameObject] do
            RedPointManager:UnBind(self.objMapStr[gameObject][i],gameObject)
        end
        self.objMapStr[gameObject]=nil
    end
end


function RedPointManager:Add(nodeStr,eventStr)
    if not self.redList[nodeStr] then
        RedPointManager:CreateNode(nodeStr)
    end
    if not self.redList[nodeStr].eventList[eventStr] then
        self.redList[nodeStr].eventList[eventStr]=true
        self:Refresh(nodeStr,false)
    end
end

function RedPointManager:Remove(nodeStr,eventStr)
    if self.redList[nodeStr] then
        if self.redList[nodeStr].eventList[eventStr] then
            self.redList[nodeStr].eventList[eventStr]=nil
            self:Refresh(nodeStr,false)
        end
    end
end

function RedPointManager:HasEvent(nodeStr,eventStr)
    if not self.redList[nodeStr] then
        return false
    end
    if not self.redList[nodeStr].eventList[eventStr] then
        return false
    end
    return true
end

function RedPointManager:RemoveAllEvent(nodeStr)
    if self.redList[nodeStr] then
        self.redList[nodeStr].eventList={}
        self:Refresh(nodeStr,false)
    end
end

function RedPointManager:Refresh(nodeStr,isIgnoreParentList)
    if self.redList[nodeStr] then
        if TableCount(self.redList[nodeStr].gameObjectList)~=0 then
            for _,v in pairs(self.redList[nodeStr].gameObjectList) do
                if not FairyGUITools.IsNil(v) then
                    if TableCount(self.redList[nodeStr].eventList)~=0 then
                        FairyPointUtils.AddRed(v,self.redList[nodeStr].redParams[v].offset,self.redList[nodeStr].redParams[v].size)
                    else
                        FairyPointUtils.RemoveRed(v)
                    end
                end
            end
        end
        if not isIgnoreParentList then
            if TableCount(self.redList[nodeStr].parentList)~=0 then
                for _,v in pairs(self.redList[nodeStr].parentList) do
                    if TableCount(self.redList[nodeStr].eventList)~=0 then
                        self:Add(v,nodeStr)
                    else
                        self:Remove(v,nodeStr)
                    end
                end
            end
        end
    end
end

function RedPointManager:AddParentNode(nodeStr,parentNodeStr)
    if not self.redList[nodeStr] then
        RedPointManager:CreateNode(nodeStr)
    end

    if not self.redList[parentNodeStr] then
        RedPointManager:CreateNode(parentNodeStr)
    end

    if self.redList[parentNodeStr] then
        self.redList[nodeStr].parentList[parentNodeStr]=parentNodeStr
        self:Refresh(nodeStr)
    end
end

function RedPointManager:RemoveParentNode(nodeStr,parentNodeStr)
    if self.redList[nodeStr] then
        if self.redList[nodeStr].parentList[parentNodeStr] then
            self.redList[nodeStr].parentList[parentNodeStr]=nil
            if self.redList[parentNodeStr] then
                self.redList[parentNodeStr].eventList[nodeStr]=nil
                self:Refresh(parentNodeStr)
            end
        end
        self:Refresh(nodeStr)
    end
end

总结

红点树是我们常用的UI功能,几乎涉及到UI的游戏都会使用到,而如果没有管理好,在游戏开发后期他几乎可能成为你的灾难。

扩展:在游戏开发过程中,类似于常用的功能模块都可以提炼出来,成为你的工具链,即使用到其他项目中也能快速复用。

  • 本文作者: Calmer
  • 本文链接: https://mytechplayer.com/archives/红点树
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
# 工具链
游戏开发<知识体系>
SVN的使用与搭建(含Unity3D扩展SVNTools)
  • 文章目录
  • 站点概览
Calmer

Calmer

88 日志
7 分类
10 标签
RSS
Creative Commons
0%
© 2020 — 2025 Calmer
由 Halo 强力驱动
蜀ICP备20010026号-1川公网安备51019002006543
Copyright © 2020-2025 Calmer的文章