# 穩定敏捷的遊戲開發方式 2021 TGDF 台北遊戲開發者論壇 [共筆筆記索引](/HksczuLpu) [官網連結](https://2021.tgdf.tw/speakers/1) [簡報連結](https://pse.is/3j2fxm) 講者:蘇禧鑫 # 目標對象與預期收穫 - Unity或任何可以單元測試的遊戲引擎 - 非短期專案 - 多一種開發時可以與設計師互動的方式 # 講者介紹 - FB page : [阿星的Unity](https://www.facebook.com/%E9%98%BF%E6%98%9F%E7%9A%84Unity-862647600520479/) - Blog : [阿星的遊戲開發](https://rstargames.com/) - YT : [rStar](https://www.youtube.com/user/1247starlove/playlists) - [Hollow Knight 直播實作系列](https://www.youtube.com/watch?v=668AVd3xBQU&list=PLGkS8CzB8N0G4qLLuBnRtmW4hYAvtznmm) - 鐵兀鷹主程式 # 大綱 * 軟體/遊戲開發的困難 * DDD * 扁平化架構 * 解耦合 * 事件驅動 * 單元測試 * DBC # 軟體/遊戲開發的困難 - 遊戲/軟體開發沒有對錯,只有適不適合 - 遊戲開發不簡單:要顧及機制、美術、程式、測試、發行、行銷、賣得好不好... - 思考:以下事物隨時間變化的趨勢 - 人工測試的難度 - 開發難度 - 軟體/遊戲開發的複雜度 - 尋找與修復問題的難度 - 思考:人擅長處理簡單還是複雜的事? - 功能隨著時間越來越難新增,也越來越難測試 - 手動測試的成本越來越高 - 若開發者可以自己快速的處理容易發現的問題,QA team 可以處理那些難以自動化測試的項目 -> 降低成本 # DDD: Domain-Driven Design 領域驅動設計 - 「程式即設計、設計即程式」 - 大型企業如 Microsoft, Facebook 等,提供多種功能時,發現這種設計模式特別適合 - 講者發現 DDD 也適合套用於遊戲開發上 ## 名詞們 - 領域 Domain: 協作的對象要找對領域的人 - 例如找擅長「遊戲開發」領域的程式,而非只是會寫程式 - 共用語言 Ubiquitous Language - 與不同領域的人建立共用語言 - 舉例:「角色」英文? Player? Character? 大家一起定義 ## 執行 DDD ![Why you need DDD](https://miro.medium.com/max/576/1*PBUyXR28FfwetXbUT47EFA.png) - 黃金圈理論: Know why, 而非 Know how ## 向上 Pair - 看板(Kanban)上越上面的 Task 價值越高,這些 Task 可以先一起做完 - 舉例:如果美術生成素材比程式處理素材速度快,那美術可以多花點時間協助測試素材 - 提早進入協作 - 建立各領域的流程 - 釐清工作責任與負責項目 ## 每個功能有自己的 Prototyping 階段 - 先用最快速度一起做出 Prototype, 提早驗證與發現問題 - 驗證完確認可用之後,再來考慮如何重構 - 先求有,也要求好! - Prototype 的美術醜、程式糟?沒關係,之後來修 # 扁平化架構 - 對於專案與功能的 Debug Panel / In Game Tools - 「測試選單」:針對每一個常用功能,做成按鈕以便快速觸發 - 可以省下手動走一遍流程的時間 - e.g. 角色扣血、生成物件、角色死亡 - 驗證過後,封裝成完整的流程 - e.g. Battle flow: 生成角色->設定位置->設定技能->設定狀態 # 解耦合 / 弱耦合 - 不好的例子 - 內部系統互相參照 - UI 個別依賴於各個內部系統的邏輯 - 三種分類 - Domain 跟 View 耦合 - Domain 跟 引擎 耦合 - Domain 跟 Domain 耦合 ## Domain 跟 View 耦合 UI 有需要 Domain 的 reference 才能實現功能嗎? - e.g. 按鈕按下後觸發 Player.DealDamage (按鈕直接依賴腳本) - 如果忘記在 inspector 裡面設定物件就會無法作用 - e.g. model(Player) 需要讀取 View(button input field) 的值,而 input field 的值也會修改到 model -> 相互參照(耦合) ## Domain 跟 引擎 耦合 思考:有些功能其實根本不需要引擎支援 - e.g. 明明只是一個扣血,有需要用 `MonoBehavior` 來實作嗎? - **與引擎解耦合的腳本更容易進行單元測試** ## Domain 跟 Domain 耦合 不同領域的設計卻互相參照了。 - 例如角色的死亡、輸入、移動控制互相參照 - 雖然拆成不同 class,卻彼此耦合 ## 設計模式: MVP Model-View-Presenter - Presenter 會實作 View 的操作 - Model 進行 Presenter 的呼叫 - 這樣 Model 跟 View 就能解耦合了 ## 設計模式: MCP Model-Component-Presenter - Model -> Domain Object - Component -> Unity Component - Presenter - 管理 component 流程 - 讀取 / 監聽 model 事件,去處理視覺邏輯 - 透過 controller 呼叫對應方法 # 事件驅動 最小可行的事件驅動架構圖 ![](https://i.imgur.com/yqc5I0j.png) 講者團隊所定義的最小驅動架構。 - 透過 DomainEventHandler 來通知 Domain - Domain 可以生出 DomainEvent - 透過 ViewEventHandler 可以通知 Presenter - Presenter 更新 component 與 Controller - component 可以生成各種 Event: GameEvent, InputEvent, ViewEvent, ComponentEvent, ... - Controller 通知 (I)Repository - 所有 Event 會透過 EventBus 來推播 實際上完整的事件驅動架構圖 ![](https://i.imgur.com/IP6ye0r.png) :flushed: ... :::info 事件開發另外有[一篇文章](https://rstargames.com/2021/04/19/unity-%e8%a7%a3%e8%80%a6%e5%90%88%e8%a8%ad%e8%a8%88-%e4%ba%8b%e4%bb%b6%e9%a9%85%e5%8b%95%e6%9e%b6%e6%a7%8b/)可以參考。 ::: # 單元測試 為什麼要寫單元測試? - 手動測試過程久 / 流程多 - 將功能與其他不可控因素(流程 / 框架 / 資料庫 / 網路)隔離 - 單獨驗證功能的完整性 # DBC: Design By Contract - 確保輸入輸出是正確的,非預期時都會出 exception - 但無法取代 unit test,DBC 比較偏 runtime 使用 # 結論 * 多寫單元測試、DBC * 善用DI framework * 使用通用性高的插件: Zenject、UniRx、DoTween等 * 相依於介面(interface),而非相依於實作 * 盡早的確認遊戲設計 (Know Why) * 不直接使用實作代替遊戲設計 * 建立團隊的「共用語言」 ###### tags: `2021TGDF` `台北遊戲開發者論壇` `共筆筆記`