整個心得分成程式 美術 音樂,三個部份來說明,該篇為程式部分。
前言
一開始做技術評估,我原先只會html跟CSS還有jquery,為了快速驗證構想加上本次開發的類型為音樂相關遊戲,透過Gemini 跟 ChatGpt 交叉比對建議,最後選擇了網頁做為載體,原因是音樂相關的處理透過網頁較容易,發發速度也較快,之前也有試著開發安卓App,並上架到google play,有興趣可以看一下我的練習作品,兩款加起來也投注了快半年的時間。

回到正題,由於之前沒有開發過網頁遊戲,我的第一個動作是快速驗證我要用到的技術框架的可行性,我快速的製作了一款測試音訊相關的應用程式,哼唱鴨鴨,花了我9天的時間,驗證 pitchy、 tone.js、 vexflow 是否符合我的需求,學習zustand 做狀態控制,並簡單了解了tailwindcss的運作。
然後,接著是惡夢的開始,理想與現實有著差距,第一個構想是透過聲音控制子彈的發射,然而,面臨兩個問題 :
1.遊戲難度過高,其實人類很難準確地發出自己想要的絕對音高。
2.音訊輸入處理的判定十分困難,因為人的聲音其實是抖動的波形,提取出麥克風輸入時需要很複雜的技術。
後來只好簡化,改為用聲音輸入來切換武器跟升級武器,不過我仍然覺得不太滿意,所以沒有繼續開發,不過在其間也算是把聲音輸入的處理給練習了,額外多學了好幾個: Web Audio API、音高偵測Pitchfinder、Howler聲音播放
然後後端的部分我摸得不太熟,但也是在模糊的狀態下把功能正常做完,用的是.NET平台 Web API,然後搭配MySQL資料庫,選擇ORM 框架 EF Core,也因為有上傳分數功能,做了一個上傳分數的簡易Api。還額外學了 Jwt token,製作google登錄,之前在Unity開發也有做,其實感覺上較簡單,網頁的第三方登錄反而麻煩了一點,因為我做前後端分離,要先處理跨域協定,然後調整Program.cs。
逃跑騎士-音樂之國的繼承者
程式-前端
延續之前練習使用的技術React + Tailwind,前端方面幾乎都是使用之前比較熟悉的,搭配學到的 eventemitter3 。
遊戲畫面與系統展示 (3 欄並排範例)
遊戲事件
這裡也採了一個坑,因為我是混合式,介面用react,遊戲運行用phaser,一開始事件用了只能在phaser起作用的自訂的GameEvents,然後用phaser內建的事件發射器,導致有些沒辦法透過zustand(zustand可以跨react跟phaser)的資訊很難傳遞,後來改用GlobalBusEventsg使用 eventemitter3 之後,才能跨react跟phaser溝通,但由於此時代碼已經非常多,重構起來非常費力,學乖了一開始就用全局事件,不要用phaser內建的事件發射器,一開始多輕鬆,後面就多痛苦。
狀態管理
Zustand做非機密的狀態控制,一開始是資料都先存localStorage,等功能確定沒問題,再把重要資訊改為上傳到後端,這樣的話還能支援本地遊玩跟登入模式,不過這裡我也是採了個坑,一開始沒有把store分得較細,導致物品,卡片,裝備等等的store都跟玩家放在一起,維護起來蠻混亂的,建議一開始就都分開會比較好,雖然到了後端我仍然將他們都轉成不同的表格,但這樣看起來就會有點前後端不一致。
遊戲邏輯
基本上都是交由AI撰寫比較多,我的目標是讓他好維護,好看懂,所以我進良遵循自己領悟的設計原則
.Net Web Api(ASP.NET Core)
我一開始覺得這個技術框架選用名稱超長,所以還得先瞭解這在幹嘛,他是
.NET: 表明這是基於 Microsoft 的 .NET 平台。
Web API: 指明是提供 HTTP 服務的 API 應用程式,而不是傳統的網頁應用程式 (MVC) 或其他類型的應用程式。
(ASP.NET Core): 強調使用的是 ASP.NET Core 這個現代、跨平台且高性能的 Web 框架,而不是舊版的 .NET Framework (例如 ASP.NET Web API 2)。
好,加起來就變超長,這邊的話我一開始都寫controller + 用剛才的 models就完事,一直到LinePay交易跟物品合成才把處理邏輯寫到service,導致前面的controller 都蠻腫的,應該要遵循 "Skinny Controller, Fat Service" (瘦控制器,胖服務) 原則才對,然後拿資料我目前也是直接寫在controller ,但應該要寫在 Repositories,這樣換資料庫才不會很痛苦。
目前就像是餐廳服務生controller 坎啜爾包辦所有工作,拿食材(Repositories),點/出菜,兼廚師(Service)>< 下個專案要改進。
Models: 給資料庫看的。
DTOs: 給前端看的。
上面兩者記得分開放,我一開始覺得他們都是資料結構就放一起,後面要全部搬。