加入顯示Snake的UI後結束此Demo
July 06, 2017
在此系列開始帶入UniRx時,有提到它主要有二個特性是開發遊戲的利器,其一就是之前一直提及的事件流(Event Stream),而另一個則是和UI做資料綁定。雖然之前有介紹是MVVM的概念,但其實是MVP(Model-View-Presenter)。但MVVM也好MVP也好,差異沒有很大,最重要的是綁定資料後,方便的將資訊呈現到UI上是最重要的。
UniRx提供了ReactiveProperty,它是結合了Subject概念的資料,這個UniRx特有的型別,在一般的Rx中是看不到的。而這個型別是針對Unity環境中,資料常有變動而制定的。不需要想的太複雜,把它當做一般的變數使用就可以了。不過它包了Stream的概念進來,並且和uGUI有密切的關聯性。
從UniRx的GitHub文件就可以看到將ReactiveProperty直接Subscribe到uGUI的Text上,就可以得到當此ReactiveProperty值改變時,Text也會跟著反應出改變後的值,這個就資料的綁定,方便了和UI的銜接。
在傳統的UI呈現上,若是某個變數的值做改變,要不就是在Update中每個Frame去檢查該變數是否有變動,有變動就重新設值。要不就是觸發事件,拿到改變事件後進行更新值的動作。而UniRx則是針對觸發事件這方式做調整,綁定資料到UI上。
在Snake中,直接加入GameManager和GameManagerUI,雖然目前GameManager是空元件,沒有任何的功能,但為了命名上的區別和完整性特別加入。實際的ReactiveProperty和uGUI都放在GameManagerUI裡,參考UniRx文件後撰寫出來的程式碼如下:
SnakeComponent元件程式碼也做些許的調整,加入了拿取GameManagerUI元件的步驟並註冊碰到水果的事件流。整個遊戲水果並沒有種類的不同,故在分數上採用統一分數計算即可。
這裡不將UI元件命名為SnakeUIComponent是因為在目前的設計上,分數是和遊戲本身有關聯,而不只Snake才擁有的特殊屬性。但如果有其它的規則加入,只限制在Snake上,那命名上就會調整,藉此反應出它的範籌。
如意料中,加入UniRx和UI綁定的部份用極短的篇幅即可完成,再來就稍微調整鏡頭的位置和方向。大致的Snake遊戲的雛形就出來了。
整個Snake的遊戲教學系列雖然沒有完全仿製傳統的規則和畫面呈現,但會在此進入系列的尾聲。就以整個系列的規劃來說已達到目標-在Unity中利用F#配Rx的概念進行Snake的開發。單從比較規則的方式來看:
- 沒有四周牆壁當做抯擋
- 沒有死亡UI提示
- 沒有音樂音效
- 沒有重新遊戲功能
這大概就是和傳統的Snake遊戲比較後明顯的差異,但這些規則和呈現一來是量化的部份,二來是額外資源的引用。都沒有和展現如何應用Rx概念搭配F#語法有任何的關聯,所以不在本系列的考量中。
但這裡有特別提出的是整個遊戲的架構以Demo來看還算好,但若是正式的以Snake遊戲專案的觀點來看,有很多地方需要重構或是需要做架構上的調整。其中最重要的部份就是在於Reference的引用(元件的引用),雖然用Unity給予的GetComponent和FindObjectOfType是決大多數的Unity開發者習慣的方法,但它不是一個很有效且觀念上不是正確的方法。若是能配合相依性注入(Dependency Injection)會更好。
另一點則是在F#裡的引用順序,若是只用元件的方式來進行,雖然在規模不大的Snake遊戲中不會察覺到任何問題,但在稍具規模的專案中,一定會出現循環相依性的狀況,也就是元件A參考到元件B,元件B也同時參考到元件A。唯一的方式就是導入Interface的概念,將相依性抽離。
再來,就功能製作上來說沒有太大的問題,但從F#的角度來看過多的變數是不良的設計,在正常的情況下應該要避免變數。但回看整個程式的撰寫時不乏直接改值再回塞到變數的情況。但用變數是有可能必要的,有可能可以提升效能,有可能可以減少垃圾回收(Garbage Collect,GC)。這是相當大的議題,而不是只用簡單的一、二句話就可以帶過的,往後必定會有相關的文章,配合Benchmark的測試來決定變數的使用。
但原則上儘可能不用變數,不得以或是評測後效能有受影響再做修正,這應該是F#裡開發的基本準則,日後的製作也會以此當準則。
此系列於此篇畫下句點,但其實就自身來說,這才是開始。正式的專案製作才正順著Snake的模式確立後展開,而相關的製作歷程也會逐步記錄下來。