在這篇文章寫出來之前,我已經開始了五款遊戲——其中四款爛尾。 第五款終於完成了,而且真的發布出去了。這篇文章是對整個過程的記錄, 包含那些讓我真正學到東西的失敗。
我使用的引擎是 Godot 4.2,語言是 GDScript。 遊戲類型是文字冒險加上簡單的場景切換,如果你在找動作遊戲或 3D 的相關心得, 這篇文章可能只有部分適用。
為什麼前四款都沒做完
回頭看那些失敗的專案,原因其實都一樣:範圍失控。 我在還沒有確定核心玩法的情況下,就開始規劃地圖、NPC 對話、支線任務、 不同結局……每個功能都很帥,但合在一起就是做不完。
第五款遊戲之所以完成,是因為我強迫自己在開發前先回答一個問題: 「如果這個遊戲只有一個房間、一個機制,它有沒有辦法是好玩的?」 當我能夠回答「有」的時候,才開始寫第一行程式碼。
專案架構與我踩過的坑
Godot 的場景系統一開始讓我很困惑,我花了大約一個禮拜才搞清楚應該如何組織節點。 以下是我最後採用的基本架構:
# 場景樹基本結構 Game (Node) ├── GameManager (Node) # 全域狀態管理 ├── UILayer (CanvasLayer) # HUD、對話框 │ ├── DialogBox │ └── StatusBar └── World (Node2D) ├── CurrentRoom # 動態載入當前房間 └── Player (CharacterBody2D)
GameManager 是我用來管理跨場景狀態的節點, 設定為 Autoload(自動載入)之後,不管切換到哪個場景都可以存取它的變數。 這個設計救了我非常多次,特別是在處理存檔系統的時候。
# GameManager.gd — 簡化版本 extends Node var player_flags: Dictionary = {} var current_chapter: int = 0 func set_flag(key: String, value: bool) -> void: player_flags[key] = value func get_flag(key: String) -> bool: return player_flags.get(key, false) func save_game() -> void: var save_data = { "flags": player_flags, "chapter": current_chapter } var file = FileAccess.open("user://save.json", FileAccess.WRITE) file.store_string(JSON.stringify(save_data))
對話系統的設計
這款遊戲大量依賴文字和對話,所以對話系統的設計是整個專案裡花時間最多的部分。 我最後採用的方案是把所有對話內容存在 JSON 檔裡,然後用一個通用的 DialogBox 場景來渲染。
dialogue_finished
信號,讓各個場景可以自由決定後續要觸發什麼事件,而不是把邏輯寫死在對話系統裡。
發布與事後反思
遊戲最後發布在 itch.io 上,上線後的第一個禮拜沒什麼人玩, 後來在 X 上有人分享才稍微有了些流量。 最常收到的回饋是「文字太多了」——這讓我意識到, 我習慣的敘事節奏和一般玩家期待的體驗之間存在一段距離。
但最重要的收穫不是這些外部的回饋,而是:我終於做完了一款遊戲。 完成品哪怕只有六十分,也比一百個精心規劃但從未完成的企畫書更有價值。 下一款我還是會繼續用 Godot,但會更早設定 scope 的上限。