Skip to content

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()

gdscript
func _ready() -> void:
    SaveManager.restore_inventory()  # 先還原
    SaveManager.save_checkpoint(...)  # 再存檔

影響範圍:chapter1_background.gdchapter1_cabinet_inside.gdchapter1_door.gd


key_state 三態追蹤

原本 key 加入包包後只寫入 InventoryManager(記憶體),沒有任何 prop 記錄狀態,重開後無從還原。

新增 key_state prop:

意義
0key 還在糖罐裡(預設)
1key 在包包裡
2key 已使用

_play_key_animation() 的 callback 裡,key 加入 inventory 後立刻:

  1. SaveManager.set_prop("key_state", 1)
  2. 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.gdchapter1_intro 的路徑

規範更新

  1. 每個有 BagUI 的場景,_ready() 必須先 restore_inventory() 再做任何 save_checkpoint(),否則重開遊戲會把空包包存進存檔
  2. 新增物件進包包後,要立刻呼叫 save_checkpoint(),不能等到玩家回到主場景才存,否則中途重開會遺失
  3. 物件狀態一律用 prop 追蹤sugar_statekey_state),不依賴 InventoryManager 的記憶體狀態判斷