基於樹結構實現的Unity紅點管理器
簡述
基於 樹結構 實現的簡單紅點管理器,採用Unity+C#實現
核心邏輯是從 Unity手遊實戰:從0開始SLG——獨立功能擴充套件(三)用樹實現客戶端紅點系統 搬的,此demo做了部分封裝及備註說明,並詳細梳理了設計思路(紅點入坑√)
(其實目前網上大部分搜到的也是基於這篇,只不過除了作者外的文章都只是貼程式碼沒說明...)
專案地址:基於樹結構實現的Unity紅點管理器 - SouthBegonia
專案結構:
- Assets/RedDotTutorial_1 // demo路徑
- Prefabs // 演示demo的預製體
- Scenes
- RedDotTutorial_1.unity // 演示demo的場景
- Scripts
- RedDotCore // 紅點系統核心指令碼資料夾
- ... // 演示demo的臨時業務指令碼
設計思路
將紅點管理器系統分為3層:結構層、驅動層、表現層
結構層
因為紅點的特性(多層級、多深度),因此一種做法是採用 樹 來構造:
核心是通過紅點資料節點RedDotNode
的 parent 和 rdChildrenDic 成員,實現樹結構關聯
備註:Mail節點指向Root節點採用虛線,是因為該例的所有紅點的路徑都是以Root為起點的(例如Root/Mail/System),但在業務開發上,基本不涉及Root節點(初始化和紅點路徑校驗時用得到),我們更關心的是第二層及其之後的節點
驅動層
即 如何驅動這個樹結構產生狀態變化,以及狀態變化之後如何將變化的行為通知到指定的表現層,在一定的程度上將資料和表現分離開
該過程的簡單理解:此紅點資訊變化->其RedDotNode資訊變化->通知其訂閱者->檢查父紅點RedDotNode資訊變化->父紅點資訊變化->...
SetRedDotNodeCallBack()
和Set()
方法就不詳細貼了,請檢視專案原始碼
表現層
在收到紅點變動的通知後,進行顯示變化處理(紅點樣式、紅點顯隱、紅點數、特效等),這層很獨立,看各自業務需求了
用法示例
比如有個紅點需求:主頁內有個郵箱按鈕(可顯示紅點),郵箱內又分為系統郵箱和隊伍郵箱(都可以顯示紅點)
首先配置紅點管理器RedDotSystem
初始化的地方,正常業務應當放在遊戲初始化入口內,本demo就用到再初始化:
public static class ManagerComponent
{
/// <summary>
/// 紅點管理器
/// </summary>
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
:
/// <summary>
/// 紅點路徑定義
/// </summary>
public static class E_RedDotDefine
{
/// <summary>
/// 紅點樹的根節點
/// </summary>
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";
}
/// <summary>
/// 紅點系統
/// </summary>
public class RedDotSystem
{
/// <summary>
/// 紅點路徑的表(每次 E_RedDotDefine 新增完後此處也必須新增)
/// </summary>
private static List<string> lstRedDotTreeList = new List<string>
{
E_RedDotDefine.rdRoot,
E_RedDotDefine.MailBox,
E_RedDotDefine.MailBox_System,
E_RedDotDefine.MailBox_Team,
};
}
後就在業務邏輯內監聽紅點,本demo就用RedDotTutorial_1場景下的UI_xxx:
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); //通知表現層
}
}
最後就設定某紅點數的變化了:
//郵箱->系統 的紅點計數+1 按鈕點選事件
public void OnAddRdSystemBtnClick()
{
int count = ManagerComponent.RedDotManager.GetRedDotCount(E_RedDotDefine.MailBox_System);
ManagerComponent.RedDotManager.Set(E_RedDotDefine.MailBox_System, count + 1);
}
流程總結:
-
配置紅點系統初始化入口
-
新增紅點路徑資訊
-
業務模組監聽紅點變化 / 業務邏輯觸發紅點變化
優劣分析
- 優勢:
- 新加紅點不會引入新指令碼或配置檔案,配置方法簡單
- 整體實現思路較為清晰簡潔(結構層、驅動層、表現層)
- 劣勢:
- 效能問題(基於string的紅點路徑在各方法內會頻繁執行
String.Split()
) - 該結構相當於單一樹,在遊戲初始化時刻即構造完畢,但要是遇到需要動態新增紅點的需求呢?(再次重構紅點樹不大現實...)
- 效能問題(基於string的紅點路徑在各方法內會頻繁執行