Skip to content

回歸到遊戲的開發

開發貪食蛇遊戲

July 01, 2017

貪食蛇遊戲在網路上可以找到各式各樣的語言所完成的作品,但這次要介紹的開發方式是用F#加上Unity來進行,雖然分開來看,可以找到用Unity開發的貪食蛇教學,或是也可以看到用XNA搭配F#所製作出來的貪食蛇。但這次的嘗試是用F#語法配合Reactive概念在Unity的編輯器中進行。

此遊戲是家喻戶曉的,規則部份相當單純。但在進行前,先做規則部份的温習。代表貪食蛇的圖像以一格一格的方式呈現並在畫面上自行移動,移動時會往蛇頭的部份前進,在前進的當下可以做左、右或是上、下方向的改變-端看當時的前進是水平還是垂直移動。而貪食蛇在移動時若是吃到代表蘋果的物件,則會增加一格長度,若是撞到非蘋果的物件,即便是自身的一格物件,則會導致結束。

這就是貪食蛇的基本款玩法。非常簡單明瞭不複雜。因此在Unity中利用F#的語法搭配UniRx的使用,來試著達成遊戲的製作。

首先處理的當然是移動的部份,貪食蛇的移動在網路上找可以找到很多版本。最直接的想法是貪食蛇的每一格都進行移動,並根據移動的規則來決定最後要移至哪一格。但在多個不同的版本中,最後被歸納出一個比較有效率的方式。這個方式也是有些變體,如前述的Unity貪食蛇的版本就是這個方法的變體。簡單來說,就是不需要考量每一格怎麼動,只要專注在頭尾即可。

從有格線的紙上畫一下即可看出來,由於貪食蛇的移動是一次一格,所以頭部到尾部中間這些格子基本上不會變動,只需要將尾部直接移至到頭部,則可以看到貪食蛇按照則規則在移動。也就是說只需要不停的將尾部那一格前移成新的頭部即可

找到了移動的規則後,就來展開程式面的撰寫。但不同於之前介紹直譯C#成F#的方式,這次會用F#直接撰寫,而不再以轉譯的方式進行,故會用F#的原生型別和檔案方類方式來進行。而Unity的MonoBehaviour元件只會當做殼層(Shell),實際的功能主要在函式(function)中實現,而非在以往熟悉的型別(class)中撰寫。

在正式放入Unity之前,可以先在REPL(Read-Evaluate-Print-Loop)中進行。在目前主流的函式語言中,不論是Haskell或是Swift都有提供基本的REPL。不同以往要寫完後按下編譯,只需寫下某個函式就可以看到此函式被執行後的結果。因此,於此環境下可以簡化並專注在某一個功能(函式)的實踐,快速的看到結果,驗證後再進行調整。這也是F#的開發方式,雖然它和單元測試(Unit Test)有些許不同,但可達到快速修正強化程式穩定性的主旨是類似的。

開發F#的專案可用的REPL在各主流編輯器中都可以使用,像是Visual Code裡有直接內建的,Visual Studio Code則需要配合Ionide外掛使用。而手邊常用的Project Rider,也於前幾天時加入到EAP版本中了。至於網路上的REPL,則有類似於JsFiddle的.NET Fiddle可使用。可用的環境相當多元、方便,故會先用來進行部份規則的撰寫,雖然後續仍很多地方還是要和Unity API進行接合,但在規則面不受到所使用引擎的影響下,用REPL可有效的幫助開發。

一開始先來定義貪食蛇要怎麼被表示,由於它是一格格的被接起來,所以用方格(Block)來表示,每個Block則用位置x和y來表示,並加上當下它是往哪個方向前進(只有四個方向)。利用F#特有的Record Type和Discriminated Union,可以先產生這樣的撰寫:

產生了一個佔了二格的Snake,並將頭部置放於list中的第一位,並讓它一開始往上走。

接下來就是要開始加入移動的部份,如同先前所提的,移動只需要動到頭尾即可。

在正常的情況下,函式中的參數是不需要額外加上型別的,函式語言中都有Type Inference,可以自行判定該參數的型別為何,但它終究不是萬能的,仍會有些情況下它無法判別,這時還是要將型別加上,才不會有編譯上的錯誤。

拿取OccupiedBlocks時用了Destructing Assignment(JavaScript中的稱呼),在這樣的拿取下

head::tail = OccupiedBlocks

head會賦值成list中第一格物件,而tail則會是第二格開始的sub list。這樣的用法在函式程式中是很常見的操作,藉此用來拿取list中的值。

而程式中出現的match和with這一段則是利用函式程式中常見的比對方式進行,它和if else概念相同,在一般的程式中和它很像的是switch,但不同於多數的switch,它可以比對的值遠遠超過字串和數字。

在Scala中甚至可以比對case class,比對的功能異常的強大,也是該語言的特色之一。

加入了移動後再加入測試的步驟,可以看到目前的光以移動部份是反應出之前的規則。但這畢竟只是模擬每個移動的步驟,若是要可以遊玩,基本的互動是要加進來的,最簡單的四方向控制是不可少的,而這也是帶入Rx最佳的時機點。Rx使用則會成為之後重要的銜接點,會於之後做較多的闡述。。但在那之前,可以先仔細的研究這幾短短的幾行程式碼,一方面了解它和規則之間的轉換,另一方面感激沒有多餘符號的精簡。


This is where ApprenticeGC goes.
Or whatever, you make the rules.