close
為什麼要用事件機制,主要是為了降低程式之間的耦合度(Coupling),日後維護起來就方便許多。
例如 : 以背包系統來說,主遊戲流程開啟背包,背包內點選物品,就單純的寫法是背包的class有主遊戲流程的參考(reference),來通知玩家點到哪個物品,這樣就大大增加了耦合度。
public class MainApp : MonoBehaviour
{
[SerializeField]
ItemBag itemBag = null;
public void OnItemSelected(Item item)
{
this.itemBag.Hide();
// TODO: Item
}
void Update()
{
if (this.openItemBag)
{
this.itemBag.Show(this);
}
}
}
public class ItemBag : MonoBehaviour
{
MainApp callee;
public void Show(MainApp app)
{
this.callee = app;
// TODO: 開啟道具選單
}
public void Hide()
{
// TODO: 關閉道具選單
}
// 此函數假設由 UI 按鈕呼叫
void OnItemSelected(Item item)
{
if (this.callee != null)
{
callee.OnItemSelected(item);
}
}
}
但如果改用unity event傳遞訊息,由主遊戲流程自行向背包class註冊點選道具的事件,而背包則是發生該事件時負責通知所有註冊者,這樣的機制使得背包class不用再依賴於主遊戲流程,降低背包class的依賴性。
public class MainApp : MonoBehaviour
{
[SerializeField]
ItemBag itemBag = null;
void Start()
{
itemBag.ItemSelected += this.OnItemSelected;
}
void OnItemSelected(object obj, ItemEventArgs args)
{
(obj as ItemBag).Hide();
// TODO: args.Item
}
void Update()
{
if (this.openItemBag)
{
this.itemBag.Show();
}
}
}
public class ItemBag : MonoBehaviour
{
public event EventHandler<ItemEventArgs> ItemSelected;
public void Show()
{
// TODO: 開啟道具選單
}
public void Hide()
{
// TODO: 關閉道具選單
}
// 此函數由UI呼叫
void OnItemSelected(Item item)
{
if (this.ItemSelected != null)
{
this.ItemSelected(this, new ItemEventArgs(item));
}
}
}
UnityEvent
UnityEvent的用法,他與一般的Delegate其實是一樣的東西,只不過Unity幫你做好了一些介面規劃,可以讓你很輕易的上手。
不管是Delegate還是UnityEvent都一樣,他們的用途主要都是減少腳本之間依賴,在需要同時操作多個物件的控制就不用在編輯器中的主腳本上關聯一大堆的物件。
目前UnityEvent最多可支援帶入四個參數(UnityEvent<T0, T1, T2, T3>),實作可參考官方範例。
public class ExampleClass : MonoBehaviour
{
UnityEvent m_MyEvent;
void Start()
{
if (m_MyEvent == null)
m_MyEvent = new UnityEvent();
m_MyEvent.AddListener(Test); //註冊事件
}
void Update()
{
if (Input.anyKeyDown && m_MyEvent != null)
{
m_MyEvent.Invoke(); //處發事件時,需要呼叫的函式
}
}
void Test()
{
Debug.Log("Test");
}
}
文章標籤
全站熱搜