1. 程式人生 > >Unity3D UniRx ReactiveX響應式程式設計初探1 雙擊的檢測

Unity3D UniRx ReactiveX響應式程式設計初探1 雙擊的檢測

版本:unity 5.6  語言:C#

UniRx版本:5.5

總起:

ReactiveX並不是個新技術,百度上一搜就有很多中文的資料,但唯獨沒有針對Unity的UniRx資料,我這邊就開個坑進行介紹。

Rx由微軟公司進行開發,並於2012年開源,現在支援的語言平臺有20多種。所以什麼是ReactiveX呢?

根據我個人的理解:ReactiveX主要處理時間上非同步的各種操作,使用簡潔的編碼實現需要各種計時器才能完成的功能。

讓我們來結合一個簡單的例子來說一下。

一個例子:

實現的功能是程式能判斷當前的點選是單擊還是雙擊?

在拿到Unity的第一天開始,我就想著Unity本身也沒有提供雙擊,如果想要做一個類似Window雙擊執行檔案的效果該怎麼做呢?後來有過一些思路,不過專案上不需要用到,所以沒實際寫下來。

這次我們來看看我的實現:

// 當前統計到的點選數量
int clickCount = 0;
float dTime = 0;
float maxDTime = 0.25f;
 
// Update中的實現,所以需要用到dTime來記錄時間
void Update ()
{
    if (clickCount > 0)
    {
        // 記錄到第一次點選後,開始記錄時間
        dTime += Time.deltaTime;
 
        // 時間超過了最大時間,列印結果,並重置
        if(dTime > maxDTime)
        {
            if (clickCount == 1)
                Debug.Log("單擊");
            else
                Debug.Log("雙擊");
            clickCount = 0;
        }
        else
        {
            // 沒有超過時間的情況下,又發生了一次點選,增加計數器
            if (Input.GetMouseButtonDown(0))
            {
                dTime = 0f;
                ++clickCount;
            }
        }
    }
    else
    {
        // 監聽第一次點選
        dTime = 0f;
        if(Input.GetMouseButtonDown(0))
            clickCount = 1;
    }
}

其實實現過程並不複雜。我自己寫了非常多和以上實現類似的程式,心情好用個協程,但是協程也有不方便的地方:無法處理異常、沒有返回值。

回到雙擊功能的實現上來,那麼Rx會怎麼做呢?

請看以下程式碼:

void Start()
{
    // 每一幀執行,點選滑鼠左鍵的時候觸發
    var clickStream = Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0));
    var obser = clickStream.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)));   //不多說,原理我沒研究,但效果跟我上面的實現一樣
    obser.Where(xs => xs.Count >= 2)
        .Subscribe(xs => Debug.Log("DoubleClick Detected ! Count:" + xs.Count));
    obser.Where(xs => xs.Count == 1)
        .Subscribe(_ => Debug.Log("Once Click"));
}

一共6行程式碼,看看結果:


就像執行一個方法一樣,在初始化的時候設定些引數就能完成Update每幀都需要執行的方法。理解上可能有些困難,但他相對我的實現有什麼好處呢?

第一,非常重要,可以非常方便的封裝,寫個工具類放Rx的程式碼放進去,需要的一呼叫就行。不然每次都要去Update中複製貼上程式碼,而且還要考慮到其他在Update中執行的程式碼;

第二,使用Dispose()方法可以隨時取消監聽,不然你還要設定個flag,在Update中每幀判斷flag是否已經為false,然後跳過檢測的程式碼;

第三,程式碼簡潔精悍,我在學C++的時候,有一句話我印象深刻:簡潔是一種美德。嗯,所以我這邊黑一下Java。

以上的三點足以讓我對這個框架心馳神往,我每次在Update中碼上三、四百行程式碼時,我就想著就沒有更加簡潔的實現嗎?直到我現在遇到了UniRx。

當然學習難度比較高,需要一定時間的積累才能寫出類似上面的程式碼。

這個例子先介紹到這,我繼續研究這個UniRx。

個人:

ECS的下一個例子等到我實際用過該框架後,再來帶著實際經驗來講解,有關注的同學需要等一等。然後UniRx又是個大坑(已經開了不知道多少個坑,不過都會填的放心,我會一直做遊戲的),響應式程式設計我也是第一次接觸,Linq我都沒咋寫過,所以理解的障礙又增加了一層。

ECS和UniRx現在都要實際用到,不學做不了功能,只能說是硬著頭皮上。說起來IT技術真正用起來的時候都是一些沒有接觸過的技術,臨時學習整理,儘量去克服,擴充套件知識面的同時,也鍛鍊自己快速掌握新技術的能力。

最近Unity官方說要本地化在徵求大家的意見,我個人反對本地化,因為你看我最近研究的ECS和UniRx都沒有中文,Unity本地化了你去學了,那下一個新的技術難道也要等到本地化了再學?恕我不能苟同,IT技術畢竟主導的是美利堅,學好英語、多看英文資料才是王道。

不過看樣子Unity的官方文件是會第一個本地化的,我最近也有文章在做翻譯工作,主要提高自己的英語閱讀水平和了解Unity各方面的細節,即使Unity官方文件出了,我還是會做下去。