# RedDotManager
**Repository Path**: southbegonia/RedDotManager
## Basic Information
- **Project Name**: RedDotManager
- **Description**: Unity中实现的红点管理器
- **Primary Language**: C#
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 2
- **Created**: 2021-12-13
- **Last Updated**: 2024-11-13
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# RedDotManager
Unity中实现的各类红点管理器,暂分为C#实现和Lua实现
# C# 实现
## 版本A
### 简述
> 核心是从 [Unity手游实战:从0开始SLG——独立功能扩展(三)用树实现客户端红点系统](https://zhuanlan.zhihu.com/p/85978429) 搬的,此处做了部分封装及备注说明,最后可以直接导包到其他项目使用

项目地址:*Assets/RedDotTutorial_1*
项目用法:运行 *Assets/RedDotTutorial_1/Scenes/RedDotTutorial_1* 场景即可查看
### 设计思路
系统分为3层:**结构层、驱动层、表现层**
#### 结构层
因为红点的特性(多层级、多深度),因此一种做法是采用树来构造:

> 备注:Mail节点指向Root节点采用虚线,是因为该例的所有红点的路径都是以Root为起点的(例如Root/Mail/Sysytem),但在业务开发上,基本不涉及Root节点(初始化和红点路径校验时用得到),而是更关心第二层及其之后的节点
#### 驱动层
即如何驱动这个树结构产生状态变化,以及状态变化之后如何将变化的行为通知到指定的表现层,在一定的程度上将数据和表现分离开。
可简单理解为:此红点信息变化->其RedDotNode信息变化->通知其订阅者->检查父红点RedDotNode信息变化->父红点信息变化->...

#### 表现层
在收到红点变动的通知后,进行显示变化处理(红点样式、红点显隐、红点数、特效等),这层很独立,看各自业务需求了

### 用法示例
有个红点需求:主页内有个邮箱按钮(可显示红点),打开邮箱内又分为系统邮箱和队伍邮箱(都可以显示红点)
首先配置红点管理器`RedDotSystem`初始化的地方,正常业务应当放在游戏初始化入口内,本demo就用到再初始化:
```c#
///
/// 红点管理器
///
private static RedDotSystem m_RedDotManager;
public static RedDotSystem RedDotManager
{
get
{
//通常放在项目的初始化逻辑中,此处只是demo临时写法
if (m_RedDotManager == null)
m_RedDotManager = new RedDotSystem();
return m_RedDotManager;
}
}
```
根据业务需求,添加3个红点路径到 `E_RedDotDefine` 和 `RedDotSystem.lstRedDotTreeList`:
```c#
///
/// 红点路径定义
///
public static class E_RedDotDefine
{
///
/// 红点树的根节点
///
public const string rdRoot = "Root";
// ---------- 业务红点 ----------
public const string MailBox = "Root/Mail";
public const string MailBox_System = "Root/Mail/System";
public const string MailBox_Team = "Root/Mail/Team";
}
///
/// 红点系统
///
public class RedDotSystem
{
///
/// 红点路径的表(每次 E_RedDotDefine 添加完后此处也必须添加)
///
private static List lstRedDotTreeList = new List
{
E_RedDotDefine.rdRoot,
E_RedDotDefine.MailBox,
E_RedDotDefine.MailBox_System,
E_RedDotDefine.MailBox_Team,
};
}
```
后就在业务逻辑内监听红点,本demo就用RedDotTutorial_1场景下的UI_xxx:
```c#
public class UI_xxx : MonoBehaviour
{
public RedDotItem MailDot;
void Start()
{
//注册监听红点,正常业务应当放在 UI.OnInit 或 UI.OnOpen 中。记得在UI.OnClose 或 UI.OnDestroy时监听置null
ManagerComponent.RedDotManager.SetRedDotNodeCallBack(E_RedDotDefine.MailBox, MailCallBack);
ManagerComponent.RedDotManager.SetRedDotNodeCallBack(E_RedDotDefine.MailBox_System, MailSystemCallBack);
ManagerComponent.RedDotManager.SetRedDotNodeCallBack(E_RedDotDefine.MailBox_Team, MailTeamCallBack);
}
// 邮箱 红点数变化回调处理函数
void MailCallBack(RedDotNode node)
{
MailDot.SetDotState(node.rdCount > 0, node.rdCount); //通知表现层
}
}
```
最后就设定某红点数的变化了:
```c#
//邮箱->系统 红点计时+1 按钮点击事件
public void OnAddRdSystemBtnClick()
{
int count = ManagerComponent.RedDotManager.GetRedDotCount(E_RedDotDefine.MailBox_System);
ManagerComponent.RedDotManager.Set(E_RedDotDefine.MailBox_System, count + 1);
}
```
总结流程:
1. 配置红点系统初始化入口
2. 添加红点路径信息
3. 业务模块监听红点变化 / 业务逻辑触发红点变化
### 优劣分析
- 优势:
- 新加红点不会引入新脚本或配置文件,配置方法简单
- 整体实现思路较为清晰简洁(结构层、驱动层、表现层)
- 劣势:
- 性能问题(基于string的红点路径在各方法内频繁执行`String.Split()`
- 该结构相当于单一树,在游戏初始化时刻即构造完毕,但要是遇到需要动态添加红点的需求呢?(再次重构红点树不大现实...)
### 参考
- [Unity手游实战:从0开始SLG——独立功能扩展(三)用树实现客户端红点系统](https://zhuanlan.zhihu.com/p/85978429)