2026-04-19開發日誌
- 日期:2026-04-19
- 專案:Cá xấu Duckduck
今天新增了門場景與開鎖互動、event2 場景,並修了一個存檔系統的根本性 bug(重開遊戲後包包物件全部消失),最後完成 chapter1 場景 / 腳本 / 圖片的資料夾重整。
InventoryManager 重開後消失 bug
問題根源:_ready() 裡 save_checkpoint() 在 restore_inventory() 之前執行。
錯誤流程:
1. 玩家取得 key → InventoryManager = [key],save_checkpoint() 存入 inventory=[key]
2. 遊戲重開 → InventoryManager 是空的(記憶體狀態)
3. _ready() 執行 save_checkpoint() → 把空的 InventoryManager 寫進 JSON
4. inventory 欄位被覆蓋為 [] → key 消失修正:所有有 BagUI 的場景,_ready() 都要先 restore_inventory() 再 save_checkpoint():
func _ready() -> void:
SaveManager.restore_inventory() # 先還原
SaveManager.save_checkpoint(...) # 再存檔影響範圍:chapter1_background.gd、chapter1_cabinet_inside.gd、chapter1_door.gd。
key_state 三態追蹤
原本 key 加入包包後只寫入 InventoryManager(記憶體),沒有任何 prop 記錄狀態,重開後無從還原。
新增 key_state prop:
| 值 | 意義 |
|---|---|
0 | key 還在糖罐裡(預設) |
1 | key 在包包裡 |
2 | key 已使用 |
在 _play_key_animation() 的 callback 裡,key 加入 inventory 後立刻:
SaveManager.set_prop("key_state", 1)SaveManager.save_checkpoint("res://Scene/chapter1/event1/chapter1_cabinet_inside.tscn")— 確保 inventory 陣列也同步更新
門場景(chapter1_door)
新建 chapter1_door.tscn + chapter1_door.gd,背景為 door_background.png,有返回按鈕、包包 UI、淡入動畫。
在 chapter1_background 加上 DoorBtn,按下後跳到門場景。
開鎖互動
節點:
DoorDropZone:flat Button,蓋住門的位置,接受 key 拖拉SubtitleLabel:字幕,顯示「門打不開」與「門打開了」ContinueOverlay:全螢幕透明 Button,開門後出現,點擊進入 event2
行為:
| 情境 | 結果 |
|---|---|
| 直接點門(未開鎖) | 顯示「門打不開」字幕 → 1.5 秒後淡出 |
| 拖 key 到門上 | 消耗 key、設 key_state=2、設 door_unlocked=1、「門打開了」字幕淡入後消失、ContinueOverlay 出現 |
| 點擊 ContinueOverlay | 進入 chapter1_event2.tscn |
| 重開遊戲(已開鎖) | 直接顯示 ContinueOverlay,等待點擊 |
door_unlocked prop(0 = 未開,1 = 已開)寫入 JSON 存檔。
字幕時序:「門打開了」淡入(0.4s)→ 停 1.5 秒 → 淡出(0.5s);ContinueOverlay 立刻可點擊,不需等字幕消失。
OvenCabinetBtn overlay 狀態
按下烤箱旁的櫃子按鈕後,在 chapter1_background 上顯示 oven_cabinet.png overlay,表示櫃子已打開。用 oven_cabinet_open prop 記錄(0 = 未開,1 = 已開)。
最終互動設計(兩段式):
- 第一次按:overlay 淡入,停在原場景
- 再按一次:overlay 已顯示,進入
chapter1_cabinet_inside - 重開遊戲:
_ready()讀到oven_cabinet_open == 1,直接顯示 overlay(無動畫)
曾試過「淡入後直接進場景」與「直接進場景再看結果」,前者有卡頓感,後者缺少打開的儀式感,最終改為兩段式。
chapter1_event2 場景
新建 chapter1_event2.tscn + chapter1_event2.gd:
- 背景:
chap1_event2_background.png(室內視角,有樓梯、廚房) - 有包包 UI、淡入動畫
_ready()立刻呼叫save_checkpoint("res://Scene/chapter1/event2/chapter1_event2.tscn"),確保重開從此場景繼續
專案架構重組
將 chapter1 所有場景、腳本、圖片整理到子資料夾並依事件分層:
Scene/chapter1/
event1/ ← chapter1_background、cabinet_inside、door、intro、sugar_prop
event2/ ← chapter1_event2
Scripts/chapter1/
event1/ ← 對應 .gd + .gd.uid
event2/ ← chapter1_event2.gd + .gd.uid
Images/chapter1/
event1/
chap1_background.png
chap1_background_sugerless.png
door_background.png
cabinet_inside/
cabinet_inside.png
cabinet_after.png
cabinet_inside_after_key_out.png
event2/
chap1_event2_background.png
open_action/ ← 維持原位
puzzle/ ← 維持原位
intro.png ← 維持原位同步更新所有引用路徑:
.tscn內的 script 路徑與圖片路徑- 所有
change_scene_to_file()呼叫 - 所有
save_checkpoint()路徑 cutscene.gd→chapter1_intro的路徑
規範更新
- 每個有 BagUI 的場景,
_ready()必須先restore_inventory()再做任何save_checkpoint(),否則重開遊戲會把空包包存進存檔 - 新增物件進包包後,要立刻呼叫
save_checkpoint(),不能等到玩家回到主場景才存,否則中途重開會遺失 - 物件狀態一律用 prop 追蹤(
sugar_state、key_state),不依賴 InventoryManager 的記憶體狀態判斷
