参考大佬的lua 版本【游戏开发实战】手把手教你在Unity中使用lua实现红点系统(前缀树 | 数据结构 | 设计模式 | 算法 | 含工程源码)_unity红点系统_林新发的博客-CSDN博客
修改为c#版本,本人的仓库地址:
https://github.com/Zhou04191919/RedPointSystem.git
核心脚本:
RedPointNode.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RedPointNode
{/// <summary>/// 节点名/// </summary>public string name;/// <summary>/// 节点被经过的次数/// </summary>public int passCnt=0;/// <summary>/// 节点作为尾节点的次数/// </summary>public int endCnt = 0;/// <summary>/// /// </summary>public int redpointCnt = 0;public Dictionary<string, RedPointNode> children = new Dictionary<string, RedPointNode>();public Dictionary<string, Action<int>> updateCb = new Dictionary<string, Action<int>>();public RedPointNode(string name){this.name = name;this.passCnt = 0;this.endCnt = 0;this.redpointCnt = 0;this.children = new Dictionary<string, RedPointNode>();this.updateCb = new Dictionary<string, Action<int>>();}public static RedPointNode New(string name){return new RedPointNode(name);}
}
RedpointTree.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Xml.Linq;
using Unity.VisualScripting;
using UnityEngine;public class RedpointTree
{private RedPointNode root;public Dictionary<string, string> NodeNames = new Dictionary<string, string>{{ "Root","Root"},{ "ModelA","Root|ModelA"},{ "ModelA_Sub_1 ","Root|ModelA|ModelA_Sub_1"},{ "ModelA_Sub_2 ","Root|ModelA|ModelA_Sub_2"},{ "ModelB ", "Root|ModelB"},{ "ModelB_Sub_1 ","Root|ModelB|ModelB_Sub_1"},{ "ModelB_Sub_2 ","Root|ModelB|ModelB_Sub_2"}};public RedpointTree(){root = new RedPointNode("Root");}public void Init(){this.root =new RedPointNode("Root");构建前缀树foreach (var name in NodeNames.Values){this.InsertNode(name);}ChangeRedPointCnt(NodeNames["ModelA_Sub_1"], 1);ChangeRedPointCnt(NodeNames["ModelA_Sub_2"], 1);ChangeRedPointCnt(NodeNames["ModelB_Sub_1"], 1);ChangeRedPointCnt(NodeNames["ModelB_Sub_2"], 1);}public void InsertNode(string name){if (string.IsNullOrEmpty(name)){return;}if (SearchNode(name) != null){Debug.Log("你已经插入了此节点" + name);return;}RedPointNode node = root;node.passCnt += 1;string[] pathList = name.Split("|");foreach (string path in pathList){if (!node.children.ContainsKey(path)){node.children.Add(path, RedPointNode.New(path));}node = node.children[path];node.passCnt = node.passCnt + 1;}node.endCnt = node.endCnt + 1;}/// <summary>/// 查询节点是否在树中并返回节点/// </summary>/// <param name="name"></param>/// <returns></returns>public RedPointNode SearchNode(string name){if (string.IsNullOrEmpty(name)){return null;}RedPointNode node = this.root;string[] pathList = name.Split("|");foreach (string path in pathList){if (!node.children.ContainsKey(path)){return null;}node = node.children[path];}if (node.endCnt > 0){return node;}return null;}/// <summary>/// 删除某个节点/// </summary>/// <param name="name"></param>public void DeleteNode(string name){if (SearchNode(name) == null){return;}RedPointNode node = this.root;node.passCnt = node.passCnt - 1;string[] pathList = name.Split("|");foreach (string path in pathList){RedPointNode childNode = node.children[path];childNode.passCnt = childNode.passCnt - 1;if (childNode.passCnt == 0){// 如果该节点没有任何孩子,则直接删除node.children.Remove(path);return;}node = childNode;}node.endCnt = node.endCnt - 1;}/// <summary>/// 修改节点的红点数/// </summary>/// <param name="name"></param>/// <param name="delta"></param>public void ChangeRedPointCnt(string name,int delta){RedPointNode targetNode = SearchNode(name);if(targetNode==null){return;}if(delta<0&& targetNode.redpointCnt+delta<0){delta = -targetNode.redpointCnt;}RedPointNode node = this.root;string[] pathList = name.Split("|");foreach (string path in pathList){RedPointNode childNode = node.children[path];childNode.redpointCnt = childNode.redpointCnt + delta;node = childNode;foreach (Action<int> cb in node.updateCb.Values){cb?.Invoke(node.redpointCnt);}}}/// <summary>/// 设置红点更新回调函数/// </summary>/// <param name="name"></param>/// <param name="key"></param>/// <param name="cb"></param>public void SetCallBack(string name,string key,Action<int>cb){RedPointNode node = SearchNode(name);if (node == null){return;}node.updateCb.Add(key, cb);}/// <summary>/// 查询节点的红点数/// </summary>/// <param name="name"></param>/// <returns></returns>public int GetRedPointCnt(string name){RedPointNode node = SearchNode(name);if (node == null){return 0;}return node.redpointCnt;}
}public class NodeNames
{public const string Root = "Root";public const string ModelA = "Root|ModelA";public const string ModelA_Sub_1 = "Root|ModelA|ModelA_Sub_1";public const string ModelA_Sub_2 = "Root|ModelA|ModelA_Sub_2";public const string ModelB = "Root|ModelB";public const string ModelB_Sub_1 = "Root|ModelB|ModelB_Sub_1";public const string ModelB_Sub_2 = "Root|ModelB|ModelB_Sub_2";public static List<string> NodeList = new List<string>() {Root,ModelA,ModelA_Sub_1,ModelA_Sub_2,ModelB,ModelB_Sub_1,ModelB_Sub_2};
}
应用:
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;public class GameHallPanel : MonoBehaviour
{[SerializeField] Text txtRoot;[SerializeField] Text txtModelA;[SerializeField] Text txtModelA_1;[SerializeField] Text txtModelA_2;[SerializeField] Text txtModelB;[SerializeField] Text txtModelB_1;[SerializeField] Text txtModelB_2;[SerializeField] Button txtRootBtn;[SerializeField] Button txtModelABtn;[SerializeField] Button txtModelA_1Btn;[SerializeField] Button txtModelA_2Btn;[SerializeField] Button txtModelBBtn;[SerializeField] Button txtModelB_1Btn;[SerializeField] Button txtModelB_2Btn;[SerializeField] Button ReBtn;[SerializeField] GameObject op;[SerializeField] GameObject tp;[SerializeField] GameObject ap;[SerializeField] GameObject bp;RedpointTree redpointTree;void Start(){//redpointTree= new RedpointTree();//redpointTree.Init();//redpointTree.SetCallBack(redpointTree.NodeNames["Root"], "Root", redpointCnt =>//{// UpdateRedPoint(redpointCnt);//});op.SetActive(true);tp.SetActive(false);RegisterClickEvents();CreateTree();SetCallBack();AddDate();}private void CreateTree(){redpointTree = new RedpointTree();for (int i = 0; i < NodeNames.NodeList.Count; i++){redpointTree.InsertNode(NodeNames.NodeList[i]);}}private void RegisterClickEvents(){txtRootBtn.onClick.AddListener(()=> { op.SetActive(false);tp.SetActive(true); }); ;ReBtn.onClick.AddListener(() => { op.SetActive(true); tp.SetActive(false); });txtModelABtn.onClick.AddListener(() => { bp.SetActive(false); ap.SetActive(true); }) ;txtModelA_1Btn.onClick.AddListener(()=> { redpointTree.ChangeRedPointCnt(NodeNames.ModelA_Sub_1, -1); });txtModelA_2Btn.onClick.AddListener(() => { redpointTree.ChangeRedPointCnt(NodeNames.ModelA_Sub_2, -1); });txtModelBBtn.onClick.AddListener(() => { bp.SetActive(true); ap.SetActive(false); }) ;txtModelB_1Btn.onClick.AddListener(() => { redpointTree.ChangeRedPointCnt(NodeNames.ModelB_Sub_1, -1); });txtModelB_2Btn.onClick.AddListener(() => { redpointTree.ChangeRedPointCnt(NodeNames.ModelB_Sub_2, -1); });}private void SetCallBack(){redpointTree.SetCallBack(NodeNames.Root, "Root", (redpointCnt) =>{ShowText(txtRoot, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelA, "ModelA", (redpointCnt) =>{ShowText(txtModelA, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelA_Sub_1, "ModelA_Sub_1", (redpointCnt) =>{ShowText(txtModelA_1, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelA_Sub_2, "ModelA_Sub_2", (redpointCnt) =>{ShowText(txtModelA_2, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelB, "ModelB", (redpointCnt) =>{ShowText(txtModelB, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelB_Sub_1, "ModelB_Sub_1", (redpointCnt) =>{ShowText(txtModelB_1, redpointCnt);});redpointTree.SetCallBack(NodeNames.ModelB_Sub_2, "ModelB_Sub_2", (redpointCnt) =>{ShowText(txtModelB_2, redpointCnt);});} private void ShowText( Text text, int redpointCnt){text.text = redpointCnt.ToString();text.transform.parent.gameObject.SetActive(redpointCnt > 0);}private void AddDate(){redpointTree.ChangeRedPointCnt(NodeNames.ModelA_Sub_1, 1);redpointTree.ChangeRedPointCnt(NodeNames.ModelA_Sub_2, 1);redpointTree.ChangeRedPointCnt(NodeNames.ModelB_Sub_1, 1);redpointTree.ChangeRedPointCnt(NodeNames.ModelB_Sub_2, 1);}
}