前言
注意,本文是本人的学习笔记记录,这里先记录基本的代码,后面用到了再回来进行实现和整理
素材
https://assetstore.unity.com/packages/2d/gui/icons/2d-simple-ui-pack-218050
框架:
RedPointSystem.cs
using System.Collections.Generic;
using UnityEngine;
namespace RedpointSystem
{
public class RedPointNode
{
public int redNum; // 红点数量
public string strKey; // 节点关键字
public Dictionary<string, RedPointNode> children; // 子节点字典
public delegate void RedPointChangeDelegate(int redNum); // 红点变化委托
public RedPointChangeDelegate OnRedPointChange; // 红点变化事件
public RedPointNode(string key)
{
strKey = key;
children = new Dictionary<string, RedPointNode>();
}
}
public class RedPointSystem
{
private static RedPointSystem instance = new RedPointSystem(); // 单例实例
public static RedPointSystem Instance // 单例访问属性
{
get { return instance; }
}
public RedPointNode root; // 根节点
private RedPointSystem()
{
this.root = new RedPointNode(RedPointKey.Root); // 根节点初始化
}
// 添加节点
public RedPointNode AddNode(string key)
{
if (FindNode(key) != null)
{
return null; // 如果节点已存在,则返回空
}
string[] keys = key.Split('|'); // 按'|'分割关键字
RedPointNode curNode = root;
curNode.redNum += 1; // 根节点红点数量加一
curNode.OnRedPointChange?.Invoke(curNode.redNum); // 触发红点变化事件
foreach (string k in keys)
{
if (!curNode.children.ContainsKey(k))
{
curNode.children.Add(k, new RedPointNode(k)); // 如果子节点不包含该关键字,则添加新节点
}
curNode = curNode.children[k];
curNode.redNum += 1; // 子节点红点数量加一
curNode.OnRedPointChange?.Invoke(curNode.redNum); // 触发红点变化事件
}
return curNode;
}
// 查找节点
public RedPointNode FindNode(string key)
{
string[] keys = key.Split('|'); // 按'|'分割关键字
RedPointNode curNode = root;
foreach (string k in keys)
{
if (!curNode.children.ContainsKey(k))
{
return null; // 如果子节点不包含该关键字,则返回空
}
curNode = curNode.children[k];
}
return curNode;
}
// 删除节点
public void DeleteNode(string key)
{
if (FindNode(key) == null)
{
return; // 如果节点不存在,则返回
}
DeleteNode(key, root);
}
// 递归删除节点
private RedPointNode DeleteNode(string key, RedPointNode node)
{
string[] keys = key.Split('|'); // 按'|'分割关键字
if (key == "" || keys.Length == 0)
{
node.redNum = Mathf.Clamp(node.redNum - 1, 0, node.redNum); // 调整节点红点数量
node.OnRedPointChange?.Invoke(node.redNum); // 触发红点变化事件
return node;
}
string newKey = string.Join("|", keys, 1, keys.Length - 1); // 获取新的关键字
RedPointNode curNode = DeleteNode(newKey, node.children[keys[0]]); // 递归删除子节点
node.redNum = Mathf.Clamp(node.redNum - 1, 0, node.redNum); // 调整节点红点数量
node.OnRedPointChange?.Invoke(node.redNum); // 触发红点变化事件
// 移除红点数量为零的子节点
if (curNode.children.Count > 0)
{
foreach (RedPointNode child in curNode.children.Values)
{
if (child.redNum == 0)
{
child.children.Remove(child.strKey);
}
}
}
return node;
}
// 设置回调函数
public void SetCallBack(string key, RedPointNode.RedPointChangeDelegate cb)
{
RedPointNode node = FindNode(key);
if (node == null)
{
return; // 如果节点不存在,则返回
}
node.OnRedPointChange += cb; // 设置红点变化事件的回调函数
}
// 获取红点数量
public int GetRedpointNum(string key)
{
RedPointNode node = FindNode(key);
if (node == null)
{
return 0; // 如果节点不存在,则返回0
}
return node.redNum; // 返回节点的红点数量
}
}
public class RedPointKey
{
// 根节点关键字
public const string Root = "Root";
// Play节点及其子节点关键字
public const string Play = "Play";
public const string Play_LEVEL1 = "Play|Level1"; // Play节点下的Level1节点
public const string Play_LEVEL1_HOME = "Play|Level1|HOME"; // Level1节点下的HOME子节点
public const string Play_LEVEL1_SHOP = "Play|Level1|SHOP"; // Level1节点下的SHOP子节点
public const string Play_LEVEL2 = "Play|Level2"; // Play节点下的Level2节点
public const string Play_LEVEL2_HOME = "Play|Level2|HOME"; // Level2节点下的HOME子节点
public const string Play_LEVEL2_SHOP = "Play|Level2|SHOP"; // Level2节点下的SHOP子节点
}
}
使用案例
RootPanel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RedpointSystem;
public class RootPanel : MonoBehaviour
{
public GameObject Canvas; // UI画布对象
public MenuPanel menuPanel; // 菜单面板对象
public LevelPanel levelPanel; // 关卡面板对象
private void Awake()
{
// 在Awake方法中初始化红点节点,表示需要显示红点的条件
// 示例:如果跨过每月最后一天的0点,则显示Play|Level1|HOME节点的红点
RedPointSystem.Instance.AddNode(RedPointKey.Play_LEVEL1_HOME);
// 示例:如果任务完成,可以领奖,则显示Play|Level1|SHOP节点的红点
RedPointSystem.Instance.AddNode(RedPointKey.Play_LEVEL1_SHOP);
// 其他条件类似,根据具体逻辑添加不同的红点节点
RedPointSystem.Instance.AddNode(RedPointKey.Play_LEVEL2_HOME);
RedPointSystem.Instance.AddNode(RedPointKey.Play_LEVEL2_SHOP);
}
private void Start() {
// 在Start方法中设置菜单面板可见,关卡面板不可见
menuPanel.gameObject.SetActive(true);
levelPanel.gameObject.SetActive(false);
}
}
MenuPanel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using RedpointSystem;
public class MenuPanel : MonoBehaviour
{
public GameObject playBtn; // 播放按钮对象
public GameObject continueBtn; // 继续按钮对象
public GameObject optionsBtn; // 选项按钮对象
public GameObject QuitBtn; // 退出按钮对象
public LevelPanel LevelPanel; // 关卡面板对象
void Start()
{
// 在Start方法中为播放按钮添加点击事件监听器,绑定到OnPlay方法
playBtn.GetComponent<Button>().onClick.AddListener(OnPlay);
// 初始化红点状态
InitRedPointState();
}
void OnPlay()
{
// 点击播放按钮后,隐藏菜单面板,显示关卡面板
this.gameObject.SetActive(false);
LevelPanel.gameObject.SetActive(true);
}
void InitRedPointState()
{
// 获取Play节点的红点数量
int redNum = RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play);
// 根据红点数量更新红点状态
RefreshRedPointState(redNum);
// 设置回调函数,当Play节点的红点数量发生变化时刷新红点状态
RedPointSystem.Instance.SetCallBack(RedPointKey.Play, RefreshRedPointState);
}
void RefreshRedPointState(int redNum)
{
// 查找播放按钮下的红点和数字对象
Transform redPoint = playBtn.transform.Find("RedPoint");
Transform redNumText = redPoint.transform.Find("Num");
// 根据红点数量决定是否显示红点
if (redNum <= 0)
{
redPoint.gameObject.SetActive(false);
}
else
{
redPoint.gameObject.SetActive(true);
redNumText.GetComponent<Text>().text = redNum.ToString(); // 更新红点数字文本
}
}
}
LevelPanel.cs
using RedpointSystem;
using UnityEngine;
using UnityEngine.UI;
public class LevelPanel : MonoBehaviour
{
// UI元素引用
public GameObject Back1Btn; // 返回按钮
public MenuPanel menuPanel; // 菜单面板引用
public GameObject Level1Btn; // 关卡1按钮
public GameObject Level1Container; // 关卡1容器
public GameObject Level1HomeBtn; // 关卡1的主页按钮
public GameObject Level1ShopBtn; // 关卡1的商店按钮
public GameObject Level2Btn; // 关卡2按钮
public GameObject Level2Container; // 关卡2容器
public GameObject Level2HomeBtn; // 关卡2的主页按钮
public GameObject Level2ShopBtn; // 关卡2的商店按钮
void Start()
{
// 初始时隐藏关卡容器
Level1Container.SetActive(false);
Level2Container.SetActive(false);
// 给返回按钮添加点击事件监听器
Back1Btn.GetComponent<Button>().onClick.AddListener(OnBackClick);
// 给关卡1按钮添加点击事件监听器
Level1Btn.GetComponent<Button>().onClick.AddListener(OnLevel1Click);
// 给关卡2按钮添加点击事件监听器
Level2Btn.GetComponent<Button>().onClick.AddListener(OnLevel2Click);
// 给关卡1主页按钮添加点击事件监听器
Level1HomeBtn.GetComponent<Button>().onClick.AddListener(OnLevel1HomeBtn);
// 给关卡1商店按钮添加点击事件监听器
Level1ShopBtn.GetComponent<Button>().onClick.AddListener(OnLevel1ShopBtn);
// 给关卡2主页按钮添加点击事件监听器
Level2HomeBtn.GetComponent<Button>().onClick.AddListener(OnLevel2HomeBtn);
// 给关卡2商店按钮添加点击事件监听器
Level2ShopBtn.GetComponent<Button>().onClick.AddListener(OnLevel2ShopBtn);
// 初始化红点状态
InitRedPointState();
}
// 返回按钮点击事件处理
void OnBackClick()
{
// 隐藏当前关卡面板,显示菜单面板
this.gameObject.SetActive(false);
menuPanel.gameObject.SetActive(true);
}
// 关卡1按钮点击事件处理
void OnLevel1Click()
{
// 切换显示关卡1容器的可见性
Level1Container.gameObject.SetActive(!Level1Container.gameObject.activeSelf);
}
// 关卡2按钮点击事件处理
void OnLevel2Click()
{
// 切换显示关卡2容器的可见性
Level2Container.gameObject.SetActive(!Level2Container.gameObject.activeSelf);
}
// 关卡1主页按钮点击事件处理
void OnLevel1HomeBtn()
{
// 删除关卡1主页红点
RedPointSystem.Instance.DeleteNode(RedPointKey.Play_LEVEL1_HOME);
}
// 关卡1商店按钮点击事件处理
void OnLevel1ShopBtn()
{
// 删除关卡1商店红点
RedPointSystem.Instance.DeleteNode(RedPointKey.Play_LEVEL1_SHOP);
}
// 关卡2主页按钮点击事件处理
void OnLevel2HomeBtn()
{
// 删除关卡2主页红点
RedPointSystem.Instance.DeleteNode(RedPointKey.Play_LEVEL2_HOME);
}
// 关卡2商店按钮点击事件处理
void OnLevel2ShopBtn()
{
// 删除关卡2商店红点
RedPointSystem.Instance.DeleteNode(RedPointKey.Play_LEVEL2_SHOP);
}
void InitRedPointState()
{
// 初始化关卡1按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL1),
Level1Btn.transform.Find("RedPoint")
);
// 设置关卡1红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL1, (int redNum) =>
{
RefreshRedPointState(redNum, Level1Btn.transform.Find("RedPoint"));
});
// 初始化关卡2按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL2),
Level2Btn.transform.Find("RedPoint")
);
// 设置关卡2红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL2, (int redNum) =>
{
RefreshRedPointState(redNum, Level2Btn.transform.Find("RedPoint"));
});
// 初始化关卡1主页按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL1_HOME),
Level1HomeBtn.transform.Find("RedPoint")
);
// 设置关卡1主页红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL1_HOME, (int redNum) =>
{
RefreshRedPointState(redNum, Level1HomeBtn.transform.Find("RedPoint"));
});
// 初始化关卡1商店按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL1_SHOP),
Level1ShopBtn.transform.Find("RedPoint")
);
// 设置关卡1商店红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL1_SHOP, (int redNum) =>
{
RefreshRedPointState(redNum, Level1ShopBtn.transform.Find("RedPoint"));
});
// 初始化关卡2主页按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL2_HOME),
Level2HomeBtn.transform.Find("RedPoint")
);
// 设置关卡2主页红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL2_HOME, (int redNum) =>
{
RefreshRedPointState(redNum, Level2HomeBtn.transform.Find("RedPoint"));
});
// 初始化关卡2商店按钮的红点状态
RefreshRedPointState(
RedPointSystem.Instance.GetRedpointNum(RedPointKey.Play_LEVEL2_SHOP),
Level2ShopBtn.transform.Find("RedPoint")
);
// 设置关卡2商店红点回调
RedPointSystem.Instance.SetCallBack(RedPointKey.Play_LEVEL2_SHOP, (int redNum) =>
{
RefreshRedPointState(redNum, Level2ShopBtn.transform.Find("RedPoint"));
});
}
void RefreshRedPointState(int redNum, Transform redPoint)
{
Transform redNumText = redPoint.transform.Find("Num");
// 如果红点数小于等于0,隐藏红点图标
if (redNum <= 0)
{
redPoint.gameObject.SetActive(false);
}
else
{
// 否则显示红点图标,并更新红点数显示
redPoint.gameObject.SetActive(true);
redNumText.GetComponent<Text>().text = redNum.ToString();
}
}
}
源码
整理好了会放上来
参考
https://www.bilibili.com/video/BV1jx4y1t7Uz/?spm_id_from=333.999.0.0&vd_source=2526a18398a079ddb95468a0c73f126e
https://www.bilibili.com/read/cv35873128/
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~