一、前言:
前面幾天我們依序完成了底層的 SavePointManager JSON 序列化架構,以及透過 AutoSavePoint 實現了各關卡的自動埋點。但在玩家的視角中,不能每次都要靠猜測來載入進度。因此今天【Day 17】我們要實現前端的一大重要功能——「動態 UI 存檔選單生成與按鈕綁定」!
二、功能與重點:
今天有兩大重點:
1. 動態清單實例化與防劇透機制: 利用 ScrollView 與 Prefab,將資料自動轉化為互動按鈕。這裡的清單只會抓取玩家「實際踩點觸發過」的紀錄點,未解鎖的幕次絕不會出現,避免出現空白欄位或提早劇透。
2. 點擊事件繫結: 透過程式碼動態為每一個生成的按鈕綁定 onClick 監聽器,實現點擊即可一鍵讀檔並跳轉場景。
三、核心程式實作:存檔選單控制器(SaveSelectPanelController.cs)
我們在專案中建立並掛載了統籌面板開關與動態生成的完整控制器:
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class SaveSelectPanelController : MonoBehaviour {
[Header("UI 關聯設定")]
public Transform contentParent; // Viewport 底下的 Content
public GameObject saveItemPrefab; // 存檔按鈕預製物
/// 刷新存檔清單,自動將 SavePointManager 的紀錄生成到 Content 中
public void RefreshSaveList() {
if (contentParent == null || saveItemPrefab == null) return;
// 1. 清空舊的 UI 項目避免重複累積
foreach (Transform child in contentParent) {
Destroy(child.gameObject);
}
// 2. 從 SavePointManager 讀取清單並動態生成
// (註:這裡遍歷的是玩家實際觸發過的存檔清單,未解鎖的關卡不會存在於此)
if (SavePointManager.Instance != null && SavePointManager.Instance.currentSaveData != null) {
var saveList = SavePointManager.Instance.currentSaveData.saveList;
foreach (var item in saveList) {
GameObject newSlot = Instantiate(saveItemPrefab, contentParent);
// 設定 UI 文字 (自動相容 TMP 或傳統 Text)
TMP_Text infoText = newSlot.GetComponentInChildren<TMP_Text>();
if (infoText != null) {
infoText.text = $"{item.saveName}\n$ {item.money} | 聲譽: {item.reputation}\n{item.saveTime}";
}
else {
Text legacyText = newSlot.GetComponentInChildren<Text>();
if (legacyText != null) {
legacyText.text = $"{item.saveName}\n$ {item.money} | 聲譽: {item.reputation}\n{item.saveTime}";
}
}
// 綁定按鈕點擊事件:載入該紀錄點並跳轉場景
Button slotButton = newSlot.GetComponent<Button>();
if (slotButton != null) {
slotButton.onClick.AddListener(() => {
SavePointManager.Instance.LoadGameFromItem(item);
});
}
}
}
}
}
三、Unity 現場配置與架構重點:
1. ScrollView 與 Content 佈局配置: 在 Unity 編輯器中建立 Scroll View,並確保其底下的 Viewport -> Content 掛載了垂直佈局組件(Vertical Layout Group),讓動態生成的按鈕能自動整齊排列。
2. 動態清除與記憶體安全: 透過 foreach (Transform child in contentParent) Destroy(child.gameObject); 確保每次生成前乾淨俐落,不會讓舊按鈕殘留堆疊。
3. 多型文字支援: 同時相容 TextMeshProUGUI 與傳統 Text 元件,避免介面組件更換時引發空參報錯。
圖一、在 Unity 編輯器中配置 Scroll View 與內容容器的階層結構
四、今日成果與小結

DAY 17 的內容是實作「動態 UI 存檔選單生成與按鈕綁定」(SaveSelectPanelController.cs),用來將前面幾天建立的 JSON 存檔與自動埋點資料呈現在 ScrollView 上。因此,它依然屬於 feature/save-system 這個存讀檔與資料持久化系統的分支!
1.檢查修改狀態
git status
2.加入暫存區並提交 Commit
git add .
git commit -m "feat: 實作 SaveSelectPanelController,完成存檔選單動態生成與按鈕點擊加載事件綁定"
3.推送到遠端開發分支
git push origin feature/save-system