前情提要
這篇主要介紹的是 Unity 內建的 UnityEvent,原本是打算面向比較初階的教學,後來發現有些程式碼還是太不入門了(Lambda語句、泛型等),所以如果在閱讀時遇到看不懂的部分先在這邊說聲抱歉。
藏在 Unity 裡面
如果你今天正在製作 UI 遷移,你應該對下面這個東西不陌生:
我們會把按鈕要做的功能塞到 OnClick 上面,像是頁面跳轉、彈出視窗等,但你有沒有想過這個 OnClick 到底是甚麼黑魔法?
查看
Button 可以發現
onClick 是一個 ButtonClickEvent ,它繼承了今天要講的主角 UnityEvent 。
要宣告 UnityEvent ,不要忘記將命名空間加入。
using UnityEngine.Events;
角色控制器
這裡有一個大家的好朋友,一個最基本的角色移動程式碼:
- 定義了 speed ,移動速度
- 在 Update() 內逐幀判斷鍵盤輸入
- 鍵盤輸入方向鍵時讓 transform 朝輸入方向進行位移
- 鍵盤輸入空白鍵讓 Player 執行 Attack()
這個程式碼有很多問題,像是按鍵是寫死的、沒有加速度等,除此之外,隨著遊戲開發, Update() 方法裡肯定不只是這短短的程式碼,像這樣的程式碼要怎麼用 UnityEvent 來魔改呢?
很笨的成績單
在我當兵新訓的時候,有個規定是打靶 6 發要中 4 發,滿靶的有手機玩,而沒達標的準備罰站。
於是,每次打完靶,你不只要大老遠從靶場走回來,當班長把成績掛上公告欄,你還得跟同袍們擠來擠去,看今晚究竟是吉是凶。大家同時擠在公告欄前面,人一多就吵吵鬧鬧,班長不開心了,把大家臭罵了一頓。
用 C# 寫起來就像這樣:
上述這個情況,有兩個問題點:
- 每個人只需要知道 自己的 成績
- 其實成績只跟 滿靶 和 少於4發 的人有關係
這時候如果有個人負責看完之後, 廣播 滿靶跟未達標的阿兵哥就行了。
所以我們有了會主動通知的成績單:
有甚麼不一樣?
- gradeEvent 可以讓所有阿兵哥透過 Subscribe() 訂閱
- Publish() 裡面先判斷哪些成績符合需求,透過 Invoke() 廣播
- 另外你會注意到 gradeEvent 的 UnityEvent 使用了泛型,這讓我們可以定義這個事件廣播時傳出的參數類型
- 在這個範例中傳出的類型是 號碼(int) 跟 狀態(Soldier.Status)
魔改控制器
我們不妨換個方向思考,把控制器給獨立出來!
然後就能讓 Player 來訂閱這個控制器的事件
有甚麼不一樣:
- 控制器被分離了,這意味著我們可以隨時抽換控制器,也可以讓其他物件擁有、甚至操控這個控制器
- Player 的 Update() 可以更專注於其他行為
但假設角色死了,總不能讓玩家繼續操控吧!所以有了下面的程式碼:
讓角色死亡時使用 RemoveListener() 來解除訂閱。
小結
這次大概用了兩個例子展示 UnityEvent 的使用方式:
- AddListener 訂閱
- Invoke 廣播
- 不需要時 RemoveListener 解除訂閱
上面的角色控制器也還有很多值得修正的地方,就先匆匆帶過了,如果對事件有興趣,可以往 C# 原生的事件系統研究,雖然使用上沒有 UnityEvent 那麼簡單,但效能跟擴充性都強了點。