1. 程式人生 > >UniRx精講(一):UniRx簡介&定時功能實現

UniRx精講(一):UniRx簡介&定時功能實現

# 1.UniRx 簡介 UniRx 是一個 Unity3D 的程式設計框架。它專注於解決時間上非同步的邏輯,使得非同步邏輯的實現更加簡潔和優雅。 ## 簡潔優雅如何體現? 比如,實現一個“只處理第一次滑鼠點選事件”這個功能,使用 UniRx 實現如下: ``` csharp Observable.EveryUpdate() .Where(_ => Input.GetMouseButtonUp(0)) .First() .Subscribe(_ => { // do something }); ``` 程式碼做的事情很簡單: 1. 開啟一個 Update 的事件監聽。 2. 每次 Update 事件被呼叫時,進行滑鼠是否抬起的判斷。 3. 如果判斷通過,則進行計數,並且只獲取第一次點選事件。 4. 訂閱/處理事件。 如果在 Unity 中,使用傳統的方式實現如上功能,首先要建立一個成員變數來記錄點選次數/是否點選過,然後在指令碼中建立一個 Update 方法來監聽滑鼠抬起的事件。 如果在 Update 方法中,除了實現滑鼠事件監聽這個功能之外,還要實現其他的功能。那麼 Update 裡就會充斥著大量的狀態判斷等邏輯。程式碼非常不容易閱讀。 而 UniRx 提供了一種程式設計思維,使得平時一些比較難以實現的非同步邏輯(比如以上這種),使用 UniRx 輕鬆搞定,並且不失程式碼的可讀性。 當然 UniRx 的強大不僅僅如此。 它還可以: * 優雅實現 MVP(MVC)架構模式。 * 對 UGUI/Unity API 提供了增強,很多需要寫大量程式碼的 UI 邏輯,使用 UniRx 優雅實現。 * 輕鬆完成非常複雜的非同步任務處理。 * ...... 最最重要的是,它可以提高我們的編碼效率,同時還給我們的大腦提供一個強有力的程式設計模型。而 UniRx 本身的原始碼非常值得研究學習,就連大名鼎鼎的 uFrame 框架,在 1.6 版本之後,使用 UniRx 進行了大幅重構,其事件/資料繫結層使用 UniRx 強力驅動。 筆者的 QFramework 也同樣引入了 UniRx,有一大批的框架使用者都是因為支援了 UniRx 慕名而來。 ## 為什麼要用 UniRx ? UniRx 就是 Unity 版本的 Reactive Extensions,Reactive Extensions 中文意思是:響應式擴充套件,響應式指的是觀察者和定時器,擴充套件指的是 LINQ 的操作符。Reactive Extensions 以擅長處理時間上非同步的邏輯、以及極簡的 API 風格而聞名。 我們都知道,遊戲很多的系統都是在時間上非同步的,所以 Unity 開發者所需要實現的非同步邏輯是非常多的。這也是為什麼 Unity 官方在引擎層實現了 Coroutine(協程)這樣的概念。 在遊戲中,像動畫的播放、聲音的播放、網路請求、資源載入/解除安裝、Tween 動畫、場景過渡等都是在時間上非同步的邏輯。甚至是遊戲迴圈(Every Update、OnCollisionEnter 等)、感測器資料(Kinect、Leap Motion、VR Input 等)都是時間上非同步的邏輯(事件)。 當我們在專案中實現以上的邏輯的時候,往往使用的方式是用大量的回撥實現,最終隨著專案的擴張會導致傳說中的”回撥地獄”。 相對較好的方法則是使用訊息/事件進行實現,結果導致“訊息滿天飛”,導致程式碼非常難以閱讀。 以上的任務使用 Coroutine 也是非常不錯的,但是 Coroutine 在 Unity 使用的時候,需要定義一個方法。寫起來是非常面向過程的。當邏輯稍微複雜一點,就很容易造成 Coroutine 巢狀 Coroutine,程式碼是非常不容易閱讀的(強耦合)。 而 UniRx 的出現剛好解決了這個問題,它介於回撥和事件之間。 它有事件的概念,只不過它的事件是像流水一樣流過來,而我們要做的則是簡單地對這些事件進行組織、變換、過濾、合併就可以得到我們想要的結果了。 它也用掉了回撥,只不過它的回撥是在事件經過組織之後,只需要呼叫一次就可以進行事件處理了。 它的原理和 Coroutine (迭代器模式)、LINQ 非常相似,但是比 Coroutine 強大得多。 UniRx 將時間上非同步的事件轉化為響應式的事件序列,通過 LINQ操作可以很簡單地組合起來。 為什麼要用 UniRx? 答案就是遊戲本身有大量的在時間上非同步的邏輯,而 UniRx 恰好擅長處理這類邏輯,使用 UniRx 可以節省我們的時間,同時讓程式碼更簡潔易讀。 Rx 只是一套標準,其他的語言也有實現,如果在 Unity 中熟悉了這套標準,那麼在未來,大家在做別的語言的專案的時候,很容易獲得 Rx 的能力。 ## 專欄內容: 1. 實踐並講解開發中最常用的 UniRx API。 2. 對 UniRx 進行一個全方面的簡介。 3. 在每個階段結束後就會結合所學的知識進行專案實踐。 4. UniRx 操作符大全。 5. UniRx 原始碼閱讀。 6. UniRx 背後的設計原理及設計模式學習。 7. LINQ、Coroutine 底層原理剖析。 8. BindingsRx、uFrame 原始碼閱讀。 OK,讓我們從下一篇開始,感受一下 UniRx 的魅力吧。 ## 知識地圖 ![image.png](http://file.liangxiegame.com/a3e6eb9c-4957-4a63-963f-99123b6cb3b3.png) # 2.定時功能實現 在 Unity 開發中,延時是我們經常要實現的功能,這個功能對於有點經驗的開發者來說不難。 最常見的實現方式如下: ``` csharp using UnityEngine; public class CommonDelayExample : MonoBehaviour { private float mStartTime; void Start() { mStartTime = Time.time; } void Update() { if (Time.time - mStartTime > 5) { DoSomething(); // 避免再次執行 mStartTime = float.MaxValue; } } void DoSomething() { Debug.Log("DoSomething"); } } ``` 這是很多初學者剛入門時候的實現方式,而初學者們隨著深入學習後來接觸到了 Coroutine(協程),使用 Coroutine 實現定時功能會更容易,而且也是更好的選擇,實現如下: ``` csharp using System; using System.Collections; using UnityEngine; public class CoroutineDelayExample : MonoBehaviour { void Start() { StartCoroutine(Timer(5, DoSomething)); } IEnumerator Timer(float seconds, Action callback) { yield return new WaitForSeconds(seconds); callback(); } void DoSomething() { Debug.Log("DoSomething"); } } ``` 協程已經把程式碼精簡了很多,不過接下來有更厲害的,使用 UniRx。 程式碼如下: ``` csharp Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(_ => { /* do something */ }); ``` 當然以上程式碼是沒有和 MonoBehaviour 進行生命週期繫結的,也就是說當 MonoBehaviour 銷燬了之後,這個定時邏輯可能還在執行,這樣就會有造成空指標異常的風險。 要解決也很簡單,程式碼如下: ``` csharp Observable.Timer(TimeSpan.FromSeconds(5)) .Subscribe(_ => { /* do something */ }) .AddTo(this); ``` 只要加上一個 AddTo(this) 就可以了。 這樣,當 this(MonoBehaviour) Destroy 的時候,這個延時邏輯也會銷燬掉,從而避免造成空指標異常。 三行程式碼,寫下來大約 20 秒的時間,就搞定了一個實現起來比較麻煩的邏輯。 今天的內容就這些。 ## 知識地圖 ![image.png](http://file.liangxiegame.com/6731a5bc-8176-4efe-84b1-2c987ffc653d.png) ## 更多內容 * QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework) * QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66) * 涼鞋的主頁:https://liangxiegame.com/zhuanlan * 關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。