👨?💻個人主頁:@元宇宙-秩沅
👨?💻 hallo 歡迎 點贊👍 收藏? 留言📝 加關注?!
👨?💻 本文由 秩沅 原創
👨?💻 收錄于專欄:Unity基礎實戰
?🅰??
文章目錄
- ?🅰??
- ?前言?
- 🎶(==1==) 常用設計模式
- 1.單例模式
- 2.對象池模式
- 3.享元模式(緩存池)
- 4.觀察者模式
- 5.代理模式
- 6.外觀模式
- 6.工廠模式
- 7.命令模式
- 🎶(==2==) 設計模式Unity模板
- 1.單例模式
- 2.對象池模式
- 3.享元模式(緩存池)
- 4.觀察者模式(事件中心)
- 5.代理模式(Mediator中介)
- 6.外觀模式
- 🎶(==3==) 程序框架
- 1. UIManager
- 2.UIManager中的面板基類BasePanel
- ?🅰??
?前言?
🎶(1) 常用設計模式
1.單例模式
-
單例模式就像是一個特殊的工廠,它確保一個類只能創建一個對象,就像是工廠只生產一種特定的產品。這種模式有助于確保在整個程序中,某個類的實例只有一個,避免了不必要的資源浪費和數據混亂。
-
單例模式也可以類比為一個全局的管理員。它確保了在整個應用程序中只有一個實例存在,因此可以用來管理全局狀態、資源、配置等,確保這些全局數據在程序中的一致性和唯一性。
2.對象池模式
-
是創建型設計模式的一種,將對象預先創建并初始化后放入對象池中,對象提供者就能利用已有的對象來處理請求,減少頻繁創建對象所占用的內存空間和初始化時間。
-
對象池模式(Object Pool Pattern):重點在于管理可重用對象的集合,以避免頻繁創建和銷毀對象帶來的性能開銷。對象池會預先創建一定數量的對象,并在需要時將它們分配給客戶端,客戶端使用完畢后將對象歸還給池而不是銷毀。這樣可以避免頻繁地創建和銷毀對象,提高了性能和資源利用率。
3.享元模式(緩存池)
享元模式(Flyweight Pattern):主要關注的是共享對象以減少內存占用和提高性能。它通過共享盡可能多的相似對象來減少內存使用,特別是當對象具有大量相似的狀態時。它通常通過將對象的共享狀態(內在狀態)與對象的特定狀態(外在狀態)相分離來實現。
4.觀察者模式
在Unity中,觀察者模式是一種設計模式,用于實現對象之間的一對多依賴關系。它允許一個對象(稱為主題或被觀察者)將其狀態的改變通知給一組依賴于該對象的其他對象(稱為觀察者),使得這些觀察者能夠自動更新。
在Unity中,觀察者模式通常使用事件(Event)來實現。被觀察者對象定義一個事件,并在適當的時候觸發該事件。觀察者對象通過訂閱(Subscribe)這個事件來注冊自己,一旦事件被觸發,觀察者對象會收到通知并執行相應的操作。
觀察者模式在游戲開發中經常使用,例如在實現游戲中的事件系統、UI更新等方面。它提供了一種松耦合的方式,使得對象之間的通信更加靈活和可維護。
5.代理模式
在Unity中,代理模式是一種設計模式,用于通過創建一個代理類來控制對另一個對象的訪問。代理類充當了被代理對象的中介,可以在訪問被代理對象之前或之后執行一些額外的操作。
在游戲開發中,代理模式常用于以下情況:
- 遠程代理:在網絡游戲中,代理模式可以用于處理客戶端和服務器之間的通信。客戶端通過代理類與服務器進行通信,代理類負責將請求轉發給服務器并返回響應。
- 虛擬代理:當處理大量資源時,可以使用代理模式來延遲創建或加載這些資源。代理類可以在需要時才實例化或加載資源,以提高程序的性能。
- 安全代理:代理模式可以用于實現訪問控制。代理類可以根據用戶的權限來控制對某些功能的訪問,從而增強系統的安全性。
在Unity中,代理模式可以通過創建一個繼承自某個接口的代理類來實現。代理類可以與被代理對象實現相同的接口,并在必要時調用被代理對象的方法或屬性。這樣,代理類就可以代替被代理對象與其他對象進行交互。
6.外觀模式
在Unity中,外觀模式是一種設計模式,用于提供一個統一的接口,封裝了一組復雜的接口或子系統,并使其更容易使用。外觀模式的目的是簡化客戶端與接口之間的交互,通過隱藏復雜的實現細節,提供一個簡單的接口給客戶端使用。
-
在Unity中,外觀模式通常用于簡化復雜的系統或子系統的使用。例如,當使用Unity的物理引擎時,可以使用Rigidbody外觀來處理物體的物理行為。這樣,開發者可以使用簡單的方法,如AddForce和Rotate,來控制物體的運動和旋轉,而不必關心底層的物理計算和碰撞檢測。
-
另一個常見的使用外觀模式的地方是在游戲開發中的音頻管理中。通過創建一個AudioManager外觀,開發者可以使用簡單的方法,如PlaySound和StopSound,來控制游戲中的音頻播放,而不必直接訪問底層的音頻引擎。
使用外觀模式可以提高代碼的可讀性和可維護性,簡化客戶端代碼,并且使系統更加靈活和可擴展。
6.工廠模式
在Unity中,工廠模式是一種創建型設計模式,用于封裝對象的實例化過程。工廠模式將對象的創建委托給一個工廠類,該工廠類負責根據不同的條件或參數返回適當的對象實例。
-
工廠模式的主要目的是隱藏對象的創建細節,并提供一種統一的方式來創建對象,使代碼更加靈活和可維護。通過使用工廠模式,可以降低代碼的耦合性,使得代碼的擴展更加容易。
-
在Unity中,工廠模式常用于創建游戲對象的實例。通過使用工廠模式,可以根據不同的需求和場景,以一種統一的方式來創建游戲對象,并在需要時對其進行初始化和配置。工廠模式可以幫助我們簡化游戲對象的創建過程,提高代碼的可讀性和可維護性。
在Unity中,工廠模式可以通過自定義腳本和組件來實現。通過編寫工廠類,可以根據不同的條件或參數來創建不同類型的游戲對象,并將其添加到場景中或作為其他對象的子對象。同時,還可以通過工廠類的接口來控制對象的創建和初始化過程,以及處理對象的銷毀和回收。
7.命令模式
在Unity中,命令模式是一種設計模式,用于解耦游戲對象的行為和輸入命令之間的關系。該模式通過將命令封裝成對象,使得游戲對象不需要直接處理輸入命令,而是通過調用命令對象來執行相應的操作。
在命令模式中,通常有四個主要的角色:
-
命令(Command):定義了需要執行的操作接口,通常包含一個執行方法(Execute)和一個撤銷方法(Undo)。
-
具體命令(Concrete Command):實現了命令接口的具體類,包含了具體的操作邏輯。
-
命令調用者(Invoker):負責調用具體命令的對象,通常包含一個命令對象的引用。
-
接收者(Receiver):真正執行命令的對象,通常是游戲對象或者組件。
在Unity中,可以將輸入命令封裝成具體的命令對象。當玩家觸發某個操作時,比如按下按鈕或者觸摸屏幕,命令調用者會創建相應的命令對象,并調用其執行方法。命令對象會將具體的操作邏輯委托給接收者來執行。
通過使用命令模式,可以實現游戲對象的行為和輸入命令之間的解耦,提高代碼的可維護性和擴展性。
🎶(2) 設計模式Unity模板
1.單例模式
- SingleManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//不繼承Mono的泛型模板
public class SingleManager<T> where T:new()
{private static T instance;public static T GetInstance(){if (instance == null)instance = new T();return instance;}
}
- SingletonMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//繼承了 Mono的泛型模板 --激活只能拖拽或者AddComponent
public class SingletonMono<T> : MonoBehaviour where T: MonoBehaviour
{private static T instance;public static T GetInstance(){ return instance;}protected virtual void Awake(){instance = this as T;}}
- SingletonAutoMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//激活--不需要拖拽或者AddComponent--直接在面板中創建
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance;public static T GetInstance(){if( instance == null ){GameObject obj = new GameObject();obj.name = typeof(T).ToString(); //設置對象的名字為腳本名DontDestroyOnLoad(obj); //過場景 不移除instance = obj.AddComponent<T>();}return instance;}}
2.對象池模式
//音符塊(棧)聲明private Stack<NoteObject> noteObjectPool = new Stack<NoteObject>();/// <summary>/// 對象池有關/// </summary>/// <returns></returns>public NoteObject GetFreshNoteObject() // 從對象池中取音符對象{NoteObject retObj;if (noteObjectPool.Count>0){retObj = noteObjectPool.Pop();}else{//資源源//retObj = Instantiate(noteObject);retObj = Instantiate(noteObject);}retObj.transform.position = Vector3.one*2;retObj.gameObject.SetActive(true);//retObj.SetActive(true);retObj.enabled = true;return retObj;}public void ReturnNoteObjectToPool(NoteObject obj) //將音符對象放入對象池{if (obj!=null){obj.enabled = false;obj.gameObject.SetActive(false);noteObjectPool.Push(obj);}}/// <summary>/// 從特效對象池中取對象/// </summary>/// <param name="stack"></param>/// <param name="effectObject"></param>public GameObject GetFreshEffectObject(Stack<GameObject> stack,GameObject effectObject){GameObject effectGo;if (stack.Count>0){effectGo=stack.Pop();}else{effectGo = Instantiate(effectObject);}effectGo.SetActive(true); //確保特效對象是激活狀態return effectGo;}
3.享元模式(緩存池)
- PoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;// 抽屜數據 public class PoolData
{public GameObject fatherObj;public List<GameObject> poolList;public PoolData(GameObject obj, GameObject poolObj){fatherObj = new GameObject(obj.name);fatherObj.transform.parent = poolObj.transform;poolList = new List<GameObject>() {};PushObj(obj);}//存public void PushObj(GameObject obj){obj.SetActive(false);poolList.Add(obj);obj.transform.parent = fatherObj.transform;}//取public GameObject GetObj(){GameObject obj = null; obj = poolList[0]; //取第一個poolList.RemoveAt(0); //然后容器中移除obj.SetActive(true);obj.transform.parent = null; //斷開了父子關系return obj;}
}//緩存池管理器
public class PoolManager : SingleManager<PoolManager>
{//存儲衣柜public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();private GameObject poolObj;//衣柜里面拿東西public void GetObj(string name, UnityAction<GameObject> callBack){//有抽屜 并且抽屜里有東西if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0){callBack(poolDic[name].GetObj());}else{//通過異步加載資源 創建對象給外部用ResourceManager .GetInstance().LoadAsync<GameObject>(name, (obj2) =>{obj2.name = name;callBack(obj2); //異步加載出的資源不能直接給外部使用所以需要委托});}}//放東西進衣柜public void PushObj(string name, GameObject obj){if (poolObj == null) //防止報錯poolObj = new GameObject("Pool");//里面有抽屜if (poolDic.ContainsKey(name)){poolDic[name].PushObj(obj);}else{poolDic.Add(name, new PoolData(obj, poolObj));}}//清空緩存池——在場景切換時public void Clear(){poolDic.Clear();poolObj = null;}
}
4.觀察者模式(事件中心)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public interface IEventInfo
{}public class EventInfo<T> : IEventInfo
{public UnityAction<T> actions;public EventInfo( UnityAction<T> action){actions += action;}
}public class EventInfo : IEventInfo
{public UnityAction actions;public EventInfo(UnityAction action){actions += action;}
}/// <summary>
/// 事件中心 單例模式對象
/// 1.Dictionary
/// 2.委托
/// 3.觀察者設計模式
/// 4.泛型
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{//key —— 事件的名字(比如:怪物死亡,玩家死亡,通關 等等)//value —— 對應的是 監聽這個事件 對應的委托函數們private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();/// <summary>/// 添加事件監聽/// </summary>/// <param name="name">事件的名字</param>/// <param name="action">準備用來處理事件 的委托函數</param>public void AddEventListener<T>(string name, UnityAction<T> action){//有沒有對應的事件監聽//有的情況if( eventDic.ContainsKey(name) ){(eventDic[name] as EventInfo<T>).actions += action;}//沒有的情況else{eventDic.Add(name, new EventInfo<T>( action ));}}/// <summary>/// 監聽不需要參數傳遞的事件/// </summary>/// <param name="name"></param>/// <param name="action"></param>public void AddEventListener(string name, UnityAction action){//有沒有對應的事件監聽//有的情況if (eventDic.ContainsKey(name)){(eventDic[name] as EventInfo).actions += action;}//沒有的情況else{eventDic.Add(name, new EventInfo(action));}}/// <summary>/// 移除對應的事件監聽/// </summary>/// <param name="name">事件的名字</param>/// <param name="action">對應之前添加的委托函數</param>public void RemoveEventListener<T>(string name, UnityAction<T> action){if (eventDic.ContainsKey(name))(eventDic[name] as EventInfo<T>).actions -= action;}/// <summary>/// 移除不需要參數的事件/// </summary>/// <param name="name"></param>/// <param name="action"></param>public void RemoveEventListener(string name, UnityAction action){if (eventDic.ContainsKey(name))(eventDic[name] as EventInfo).actions -= action;}/// <summary>/// 事件觸發/// </summary>/// <param name="name">哪一個名字的事件觸發了</param>public void EventTrigger<T>(string name, T info){//有沒有對應的事件監聽//有的情況if (eventDic.ContainsKey(name)){//eventDic[name]();if((eventDic[name] as EventInfo<T>).actions != null)(eventDic[name] as EventInfo<T>).actions.Invoke(info);//eventDic[name].Invoke(info);}}/// <summary>/// 事件觸發(不需要參數的)/// </summary>/// <param name="name"></param>public void EventTrigger(string name){//有沒有對應的事件監聽//有的情況if (eventDic.ContainsKey(name)){//eventDic[name]();if ((eventDic[name] as EventInfo).actions != null)(eventDic[name] as EventInfo).actions.Invoke();//eventDic[name].Invoke(info);}}/// <summary>/// 清空事件中心/// 主要用在 場景切換時/// </summary>public void Clear(){eventDic.Clear();}
}
5.代理模式(Mediator中介)
using PureMVC.Interfaces;
using PureMVC.Patterns.Mediator;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//-------------------------------
//-------功能: 角色面板視圖中介
//-------創建者: -------
//------------------------------/// <summary>
/// 角色面板視圖中介
/// 固定:
/// 1.繼承PureMVC的Mediator腳本
/// 2.寫構造函數
/// 3.重寫監聽通知的方法
/// 4.重寫處理通知的方法
/// 5.可選:重寫注冊時的方法
/// </summary>
public class RoleViewMediator : Mediator
{//銘牌名public static string NAME = "RoleViewMediator";/// <summary>/// 構造函數/// </summary>public RoleViewMediator( ) : base(NAME){//可以去寫創捷面板預設體的邏輯等}/// <summary>/// 重寫監聽通知的方法,返回需要的監聽(通知)/// </summary>/// <returns>返回你需要監聽的通知的名字數組</returns>public override string[] ListNotificationInterests(){return new string[] { PureNotification.UPDATA_ROLE_INFO,PureNotification.ROLE_PANEL };}/// <summary>/// 重寫處理通知的方法,處理通知/// </summary>/// <param name="notification">通知</param>public override void HandleNotification(INotification notification){switch (notification.Name){case PureNotification.UPDATA_ROLE_INFO:(ViewComponent as RoleView).UpdateView(notification.Body as PlayerDataObj); break;}}/// <summary>/// 可選:重寫注冊方法(他們需要到Facde中注冊)/// </summary>public override void OnRegister(){base.OnRegister();}}
6.外觀模式
🎶(3) 程序框架
1. UIManager
其中的異步加載方法,緩沖時間很有可能會影響參數的及時傳遞
采用單例模式構造的UIManager腳本,對所有面板類Panel進行管理,在UIManager中
- ①加載預制體。Canvas和所有面板都以預制體的方式進行異步加載
- ②構建層級。并構建顯示層級(Bot,Mid,Top,System) ,方便面板之間的顯隱
- ③提供面板顯示、隱藏、移除和 自定義事件添加的方法
2.UIManager中的面板基類BasePanel
面板基類作為,所需面板的繼承源,為其子類提供了很多便利,如下:
- ①激活查詢控件。內部構建了找尋面板中所有UI控件的方法,一激活就尋找并將其存儲到字典當中
- ②精準獲取控件。可通過UI控件名字和類型,來精確得到對應UI控件(在字典中遍歷)
?🅰??
?【Unityc#專題篇】之c#進階篇】
?【Unityc#專題篇】之c#核心篇】
?【Unityc#專題篇】之c#基礎篇】
?【Unity-c#專題篇】之c#入門篇】
?【Unityc#專題篇】—進階章題單實踐練習
?【Unityc#專題篇】—基礎章題單實踐練習
?【Unityc#專題篇】—核心章題單實踐練習
你們的點贊👍 收藏? 留言📝 關注?是我持續創作,輸出優質內容的最大動力!、