前幾天,我參加了為期9天的 Bevy Game Jam 4,要求使用 Bevy 遊戲引擎開發,最後完成提交了一個鴨子滑冰吃麵包的解謎遊戲。在這次 Game Jam 的過程中,我從零開始上手這個以 Rust 作為編程語言的數據驅動遊戲引擎,單人開發負責了遊戲所有的遊戲設計、編程、美術,對我來說是一個非常有趣的體驗,因此想記錄一下,並且也能給希望嘗試 Bevy 引擎作為開發工具的遊戲開發者一些參考。
遊戲鏈接:QUACK!!! on ICE
對於想了解 Bevy 的可以看一看官網的介紹,我在這裡就不多贅述了: Bevy Engine
背景
在做完我的第一個正式上架的獨立遊戲《小石頭人踏上旅程》之後,我在做遊戲這件事上處於一個停滯的狀態。一方面是感覺長時間沒有足夠有趣的新點子想出來,另一方面是對一直使用同一樣工具進行遊戲開發有點厭倦(說的就是你, Unity)。在經過一段時間的停滯期之後,我決定要做點什麼東西,不論想法好壞先試試再說。那天正好通過某個遊戲開發直播得知 Bevy Jam 4 要開始了,自己也一直想嘗試一下看上去很特殊的開源遊戲引擎以及想體驗下用 Rust 語言寫遊戲代碼的感受。既能強迫自己想新點子還能上手新工具,這不是雙贏的事情,於是我就很愉快地決定參加 Bevy Jam 玩一下了。
開發流程
頭腦風暴階段
既然已經決定要參加 Game Jam 了,剩下的事就是說幹就幹了。這次 Bevy Jam 4 的主題是 “That's a LOT of entities”,我要的第一件事就是根據這個主題來想一個遊戲玩法出來。“Entities”是一個比較模糊寬泛的概念,可以指代:玩家操縱角色,敵人,阻擋物(地形)等等,至於如何表現“多”,可以是某個東西靜態數量上的多,也可以讓某樣東西的數量動態增加。這個時候突然想到可以做一個同時餵飽很多鴨子的遊戲。
好,現在至少有個初步的想法,就是做一個“同時餵飽很多鴨子”的遊戲,然後我應該會做一個解謎。加上冬天的現實生活背景和我曾經餵過鴨子麵包的經歷,想到可以把“冰面滑行”作為一個主要遊戲機制。於是,我在 Notion 裡記錄下了對這個遊戲的初步想法草稿,並且取了一個看上去挺樂的遊戲標題:
第一天的想法草稿
由於很多東西只在腦子裡過一遍很難想象玩法是否好玩,以及要如何對這個粗糙的想法填充具體細節(比如鴨子吃麵包數量有限定嗎,吃完麵包還能繼續移動嗎等等),最好能做一個簡單的可以實際上手的東西試一下想法。我第一反應是在用 Bevy 正式開始做遊戲前先用 PuzzleScript 這個解謎遊戲原型工具來嘗試一下,畢竟後者實現一個簡單的遊戲機制幾乎不用花什麼時間。嘗試過後,雖然我在 PuzzleScript 裡做的東西沒法實現點擊選擇功能還有一些邏輯上的問題,不過已經能看出遊戲設計的一些雛形了,比如可以用鴨子卡位的技巧來進行解謎之類的。對這個想法有了一定信心以後覺得是時候開始使用 Bevy 做一點東西了。
上手 Bevy 遊戲引擎
在官網上,對 Bevy 是這麼介紹的:“A refreshingly simple data-driven game engine built in Rust. Free and Open Source Forever!”,翻譯過來就是:“Bevy遊戲引擎是一款令人耳目一新的簡單的數據驅動遊戲引擎,用Rust語言構建而成。永久免費且開源!”。幸運的是,我之前一段時間正好在出於興趣地學習 Rust,雖然不夠熟練,但至少不用花大量時間入門學習該遊戲引擎使用的編程語言。接下來的關鍵就是理解 Bevy 裡的 ECS(實體組件系統),這也是這整個遊戲引擎所圍繞的思想。官網上提供了一個入門指南“The Bevy Book”,我很快就看完了(不是我看得快,是真的寫得很短)。
Bevy 官網截圖
把官網的入門指南看完以後,我也只是對整個遊戲引擎有最基礎的認知,可是對做一個遊戲出來還是無從入手。我覺得是時候試試例子驅動的學習方式了。除了官方提供了很多實現基礎功能的例子以外,我找到了 Bevy Jam 3 的第一名的開源代碼來參考。在實現某個功能沒有思路的時候我就搜索例子看看別人是怎麼實現的。
開發的每個階段都有肉眼可見的里程碑會比較有開發動力,因此我做的第一件事就是在屏幕上顯示一個鴨子並且能用方向鍵移動,並且以格子為移動最小單位。這時是 Game Jam 的第二天。
實現基本功能
接下來要做的事是能夠進行關卡/場景的讀取,這件事我本來想用如 LDTK 之類的插件來做,後來發現由於我用的 Bevy 版本太新了但是插件沒有及時更新,所以我用不了那些插件了。於是想著乾脆仿照 PuzzleScript 裡面用字符表示關卡的方式,從 .txt 裡讀取關卡,編輯關卡也是編輯 .txt 文件。雖然這個方法看上去很原始人也不方便,但是就一個 Game Jam 來說應該可以一試,實在不行之後再改進唄。於是我寫了一個從 .txt 裡讀取關卡再存到數組裡去的功能,遊戲中的關卡實際上在加載進去之前是被這樣表示的,不同的字符表示不同的物體:
用字符的方式存儲關卡
這下老師傅手打關卡了,不過重要的是能快速地實現這個功能,我對自己的做法還挺滿意的,接下來就是遊戲邏輯代碼。由於關卡被讀到數組裡去了,所以邏輯也都可以在數組裡計算,這算是一個比較方便的地方。有了之前那些使用經驗以後,鼠標點擊選中鴨子的功能也做得較為順暢,現在終於有一個雖然沒有什麼關卡設計但是能玩的場景了,鼓掌。
完善遊戲機制
之前寫的有關遊戲機制的想法畢竟只是一個草稿,現在有能夠親自上手擺弄的場景以後,終於可以把之前懸而未決的一些事情決定一下。冰面滑行只有碰到障礙物才會停下這個是一開始就決定好的,不過在玩法的其他方面還有一些模糊的地方。很顯然如果一隻鴨子能無限制吃麵包的話,遊戲會變得過於簡單,多隻鴨子的設定也會沒有必要,所以一隻鴨子應該最多隻能吃一個麵包。這樣鴨子就被區分為“飽”和“不飽”兩個狀態,為了能讓鴨子之間能互相合作解謎,所以吃完麵包之後應該還是可移動的狀態。另外每關的目標被定為所有面包被吃完。
這裡就不按照時間順序,順便提一句在開發後期加入“破冰”機制的事。在 Game Jam 的第七天左右,走在回宿舍的路上突然想到可以做一個破冰的機制,第二天醒來想到如果只有吃飽的鴨子在碎裂冰面上才會破冰會格外有趣,不僅符合邏輯也在遊戲玩法上更有深度(這樣就對鴨子兩種狀態從特性上做出區分)。所以我就緊急加了這個破冰的機制,確實帶給了我關卡設計方面的新點子,讓遊戲變得更加有趣了。
改善美術
我從來不是很擅長做遊戲美術,不過倒是積累了不少偷懶取巧的方法。比如在《小石頭人踏上旅程》裡用 MagicaVoxel 做體素模型,還有用後處理效果啥的增加畫面質感之類的。不過這次我主要是想到了可以在配色方面下功夫,想辦法改善之前幾分鐘做完的臨時的簡陋的像素美術和遊戲界面。從身邊一些做過設計的人那裡經常會發現在做界面設計的時候會先定下主題色,於是我如法炮製,先從鴨子身上選取了標誌性的顏色,還有冰面和麵包的顏色,然後按照感覺選了一個看上去舒服的主題色板:
主題色
選完顏色後,我按照選出來的主題顏色用 Aseprite 重新畫了一些美術素材,不過因為嚴謹的像素美術畫起來比較麻煩而我實際上也不是很會像素畫,所以我對自己的要求就是類似 Baba Is You 裡面的簡單的畫法就行。改進前後的效果還是很可觀的,算是用最少的時間成本大大改善了遊戲觀感。這些工作是在 Game Jam 的第7天左右完成的。
改前:
改後:
夜間模式背景的效果(Dark Mode? Duck Mode!):
順帶一提,你可能會在之前的一些截圖裡發現我把鴨子叫的擬聲詞“quack”錯誤地寫成“quark”(夸克)了,後面發現了就改過來了。
遇到的坑
Bevy 還是一個處於頻繁更新的開發中的遊戲引擎,因此得自己想辦法解決遇到的各種奇怪問題,也有的問題是我不熟悉新的工具導致的,總之是踩了一些坑。首先是由於 Bevy 的 API 變化頻繁,看別人代碼裡使用的方法自己這裡不一定能用,需要多查文檔和官方例子。然後我在 Build 到不同平臺也出現了一些問題,比如導出 WASM 版本的時候需要清理代碼裡用到 std 標準庫的地方,比如不能使用 std::fs 裡的方法來讀取文件,而是要換成用 include_str! 這個宏。但是成功生成 WASM 遊戲版本以後,發現在網頁上還是不能正常運行,查了半天發現這原來是 Bevy 引擎在 0.12 版本新引入的問題,需要手動禁止使用 .meta 文件才能解決。以前我用 Unity 的時候幾乎沒有這樣的體驗(指翻找 Github 上的 issue)。
完成提交
在技術問題被解決得差不多之後,我開始設計關卡了,由於還沒做關卡編輯器,所以就手動在文本文件裡編輯關卡,不過好在字符串看上去還是相對直觀,做關卡的過程還算順暢,一共整了 13 關。不過遺憾的是因為沒有關卡編輯器,所以做不了比較複雜的關卡,整體難度上比較簡單,但我相信還是保留了一些趣味的。在最後一天前有群友建議我可以加一個 undo 撤回的功能,我之前覺得做這個太花時間就一直沒做(畢竟我上一個遊戲的撤回做了挺久),後來想了下其實由於關卡都存在數組裡了,所以應該不難做撤回。所以在提交前我緊急實現了一個撤回的功能,事實證明這是一個正確的決定。
在提交前,我也讓認識的人試玩了一下。有人反饋一開始的鼠標點擊鴨子操作不夠直觀,他沒反應過來要鼠標點擊,於是我在第一關額外加了點擊的提示。破冰操作那裡有人反饋缺少直觀的引入機制關卡,於是一個更加直觀的引入關被加入到遊戲中。除此之外,在提交前我還刪掉和改了一點作用不大的關卡。
接下來就是提交和試玩了,Bevy 社區裡的大家還是挺熱心的,留了不少評論和誇獎,我也試玩了一些 Bevy Jam 裡別的作品。
總結
這次參加 Bevy Jam 對我來說是一個挺愉快的體驗,不僅做了一個自己覺得比較有趣的遊戲,還上手了新工具。Bevy 這個遊戲引擎的使用體驗上和我以往用過的遊戲引擎很不同。首先是目前它沒有圖形界面,所以一切基本都在代碼裡完成。寫代碼的時候感覺自己在做完整的遊戲而不是在 Unity 裡東一塊西一塊寫東西和妥妥拽拽(樂)。至於 Bevy 特色的數據驅動的 ECS 實體組件系統用起來其實開發效率挺高,用 Rust 來寫遊戲開發代碼也是頗為有趣的體驗。不過功能的全面性和穩定性自然是不比目前成熟的遊戲引擎,不少問題也得自己想辦法解決和搜索。我當時和別人說了一個有點誇張的比喻,用成熟商業遊戲引擎做遊戲就像用打火機點火,雖然方便但是沒成就感,用 Bevy 就像鑽木取火。
不過要問我之後是否會繼續用 Bevy 做遊戲,我的回答大概率是 yes。雖然如果做中長期作品可能還是會偏向其他成熟的遊戲引擎,不過至少這次用 Bevy 打 Game Jam 的體驗還是不錯的,期待 Bevy 之後的更新和進步吧。另外我在考慮整理下代碼,給這個遊戲搓一個自己用的關卡編輯器啥的,這都是後話了。
以及歡迎試玩鴨子游戲 :)