【UGUI-个人记录】红点系统

准备阶段

基础知识

前缀树

节点的数据结构RedPointNode

节点名称name、节点作为中间节点的次数passCount、节点作为结束节点的次数endCount、当前对应红点的总数redPointCount 、子节点children、红点更新时回调updateCB。 接收一个string参数的构造函数。

红点树的行为RedPointTree

1.定义根节点root,在Init函数中创建根节点。 2.使用辅助类RedPointsNodeNames,注册节点名。根据基础知识,自定义常量、结构为类似“Root|A|Achild“。存放当前树中所有节点的List。 3.插入节点,封装InsertNode,接收一个string参数。 详解: 判断节点name是否为空以及是否已经加入; 获取根节点的引用node,所有新插入的节点必定经过根节点所以passCount++,按照”|“切割传入的name; 循环遍历切割后的字符串,将未加入的新节点加入当前node的子节点集合,然后更新node为当前路径对应的子节点,对应passCount++; 遍历完path后,node更新到最后一个节点,将其endCount++;

4.查询节点,SearchNode,接收一个string参数。 详解:传入一个路径后存在两种返回null的情况,1.路径不存在2.路径存在但是以最后一个节点为结尾的次数为0 name判空; 获取根节点root引用并切割name; 遍历pathList,若当前node的子节点不包含path则返回null; 遍历结束后node为最后一个节点(即我们需要查询的节点),node.endCount<=0说明不存在以该节点为结尾的值节点,返回null;

5.删除节点,DeleteNode,接收一个string参数 详解:什么是删除?将对应路径经过的节点passCOunt--,对应节点endCount--,并移除passCount==0的子节点。

6.修改节点的红点数,ChangeRedPointCnt,接收一个stirng参数和一个int参数delta 详解:使用增量的方式修改 先查询节点是否存在; 如果增量delta为负值且绝对值大于该节点的红点数,则进行修正; 遍历路径上的所有节点,并将它们的红点数依次变化delta,然后执行各自的回调函数

7.设置红点更新回调函数,SetCallBack,接收一个string参数和回调Action 8.查询节点红点数,GetRedPointCnt,接收一个string参数

红点管理器RedPointManager

添加对应控件包括但不限于Button和Text。 1.创建红点树,CreateTree 2.注册按钮点击事件,RegisterClickEvents 3.设置对应节点回调函数,SetCallBack 4.添加数据,AddData(考虑开放一个外部接口以供调用)

完整代码

第一部分

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MyRedPoint
{
    public class RedPointsNodeNames
    {
        public const string Root = "Root";
        public const string AModel = "Root|btnAModel";
        public const string AModelSub1 = "Root|btnAModel|btnSubA1";
        public const string AModelSub2 = "Root|btnAModel|btnSubA2";

        public static List<string> NodeList = new List<string>()
        {
            Root,AModel,AModelSub1,AModelSub2//,ModelB,ModelB_Sub_1,ModelB_Sub_2
        };
    }

    public class MyRedPointNode
    {
        public string name;
        public int passCount;
        public int endCount;
        public int redPointCount;
        public Dictionary<string, MyRedPointNode> children;
        public Dictionary<string, Action<int>> updateCB;

        public MyRedPointNode(string str)
        {
            name = str;
            passCount = 0;
            endCount = 0;
            redPointCount = 0;
            children = new Dictionary<string, MyRedPointNode>();
            updateCB = new Dictionary<string, Action<int>>();
        }
    }

    public class MyRedPointTree
    {
        private MyRedPointNode root;
        public MyRedPointTree()
        {
            root = new MyRedPointNode(RedPointsNodeNames.Root);
        }
        /// <summary>
        /// 待定的有参构造
        /// </summary>
        /// <param name="name"></param>
        public MyRedPointTree(string name)
        {
            
        }
        #region 增删查改
        public void InsertNode(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                Debug.LogError("name不能为空!");
                return;
            }
            if (SearchNode(name) != null)
            {
                Debug.LogError("节点已经加入!");
                return;
            }

            var node = root;
            node.passCount++;

            var pathList = name.Split('|');

            foreach (var path in pathList)
            {
                if (!node.children.ContainsKey(path))
                {
                    node.children.Add(path, new MyRedPointNode(path));
                }
                node = node.children[path];
                node.passCount++;
            }
            node.endCount++;
        }

        public MyRedPointNode SearchNode(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                Debug.LogError("name不能为空!");
                return null;
            }
            var node = root;
            var pathList = name.Split('|');
            foreach (var path in pathList)
            {
                if (!node.children.ContainsKey(path)) return null;
                node = node.children[path];
            }
            return node.endCount > 0 ? node : null;
        }

        public void DeleteNode(string name)
        {
            if (SearchNode(name) == null)
            {
                return;
            }
            var node = root;
            node.passCount --;
            string[] pathList = name.Split('|');
            foreach (var path in pathList)
            {
                var childNode = node.children[path];
                childNode.passCount -= 1;
                if (childNode.passCount == 0)
                {
                    node.children.Remove(path);
                }
                node = childNode;
            }
            node.endCount -= 1;
        }
        #endregion

        public void ChangeRedPointCnt(string name,int delta)
        {
            var targetNode = SearchNode(name);
            if (targetNode == null) return;

            if (delta < 0 && delta + targetNode.redPointCount < 0) delta = -targetNode.redPointCount;

            var node = root;
            var pathList = name.Split('|');
            foreach (var path in pathList)
            {
                var childNode = node.children[path];
                childNode.redPointCount += delta;
                node = childNode;
                foreach (var cb in childNode.updateCB.Values)
                {
                    cb(node.redPointCount);
                }
            }
        }

        public void SetCallBack(string name, Action<int> cb)
        {
            var node = SearchNode(name);
            if (node == null) return;
            node.updateCB.Add(name,cb);
        }

        public int GetRedPointCnt(string name)
        {
            var node = SearchNode(name);
            if (node == null) return 0;
            return node.redPointCount;
        }
    }
}

第二部分

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyRedPoint;
using TMPro;
using UnityEngine.UI;
public class MyRedPointManager : MonoBehaviour
{
    public TMP_Text rootText;
    public TMP_Text btnAModelText;
    public TMP_Text sub1Text;
    public TMP_Text sub2Text;

    public Button sub1Btn;
    public Button sub2Btn;

    public Button add1Btn;

    private MyRedPointTree redTree;
    private void Start()
    {
        RegisterClickEvents();
        CreateTree();
        SetCallBack();
        AddData();
    }

    private void AddData()
    {
        redTree.ChangeRedPointCnt(RedPointsNodeNames.AModelSub1, 2);
        redTree.ChangeRedPointCnt(RedPointsNodeNames.AModelSub2, 3);

    }

    private void SetCallBack()
    {
        redTree.SetCallBack(RedPointsNodeNames.Root, UpdateRoot);
        redTree.SetCallBack(RedPointsNodeNames.AModel, UpdateModelA);
        redTree.SetCallBack(RedPointsNodeNames.AModelSub1, UpdateModelA_1);
        redTree.SetCallBack(RedPointsNodeNames.AModelSub2, UpdateModelA_2);

    }
    #region 回调相关
    private void UpdateRoot(int redCount)
    {
        ShowText(rootText, redCount);
    }
    private void UpdateModelA(int redCount)
    {
        ShowText(btnAModelText, redCount);
    }
    private void UpdateModelA_1(int redCount)
    {
        ShowText(sub1Text, redCount);
    }
    private void UpdateModelA_2(int redCount)
    {
        ShowText(sub2Text, redCount);
    }

    private void ShowText(TMP_Text txt, int count)
    {
        txt.text = count.ToString();
    }

    #endregion
    private void CreateTree()
    {
        redTree = new MyRedPointTree();
        foreach (var nodeName in RedPointsNodeNames.NodeList)
        {
            redTree.InsertNode(nodeName);
        }
    }

    private void RegisterClickEvents()
    {
        sub1Btn.onClick.AddListener(A_1Click);
        sub2Btn.onClick.AddListener(A_2Click);
        add1Btn.onClick.AddListener(Add1Click);
    }

    #region 点击事件
    private void A_1Click()
    {
        redTree.ChangeRedPointCnt(RedPointsNodeNames.AModelSub1, -1);
    }

    private void A_2Click()
    {
        redTree.ChangeRedPointCnt(RedPointsNodeNames.AModelSub2, -1);
    }
    private void Add1Click()
    {
        redTree.ChangeRedPointCnt(RedPointsNodeNames.AModelSub1, 1);
    }
    #endregion
}

参考资料

【游戏开发实战】手把手教你在Unity中使用lua实现红点系统(前缀树 | 数据结构 | 设计模式 | 算法 | 含工程源码)

对应评论区老哥的项目

后记

有待完善

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值