Unity 資料(Data) 與 序列化(Serialization)

資料結構

在 Unity 中儲存資料時要選擇適合的資料結構來儲存,以下是 C# 常用的資料結構。

  1. 陣列 (Array):陣列適用於大小固定、元素類型一致的集合。例如,儲存固定數量的關卡分數或完成狀態。
    1
    2
    3
    int[] levelScores = new int[10]; // 用於存儲 10 個關卡的分數
    levelScores[0] = 100; // 第一關的分數
    levelScores[1] = 200; // 第二關的分數
  2. 列表 (List):列表是動態的,能在執行時調整大小,適合在需要新增或移除元素的情境。例如,動態管理角色的物品欄。
    1
    2
    3
    List<string> inventoryItems = new List<string>(); // 用於儲存物品清單
    inventoryItems.Add("Item1"); // 添加物品
    inventoryItems.Add("Item2"); // 添加物品
  3. 字典 (Dictionary):字典是鍵(Key)與值(Value)的儲存方式,適合需要快速查找的情況。例如,排行榜系統或配置表。
    1
    2
    3
    Dictionary<string, int> leaderboard = new Dictionary<string, int>(); // 玩家名稱對應分數
    leaderboard["Player1"] = 1000; // Player1 的分數
    leaderboard["Player2"] = 1500; // Player2 的分數
  4. 自定義資料結構:當內建資料結構無法滿足需求時,可設計自定義結構以應對特定場景。例如,設計角色屬性與技能系統。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Character
    {
    public string Name;
    public int Health;
    public int Mana;
    public List<string> Abilities;

    public Character(string name, int health, int mana)
    {
    Name = name;
    Health = health;
    Mana = mana;
    Abilities = new List<string>();
    }

    public void AddAbility(string ability)
    {
    Abilities.Add(ability);
    }
    }

資料結構對效能的影響

  1. 優化記憶體使用
    選用適當的資料結構能減少不必要的記憶體浪費。例如:若需要儲存固定數量的元素,可使用 陣列 (Array) 而非列表 (List)。陣列因固定大小而佔用較少的記憶體空間。
  2. 提升存取與檢索速度
    不同的資料結構提供不同的存取效率,選擇合適的結構能顯著提升遊戲回應速度。例如:字典 (Dictionary) 提供常數時間的查找,非常適合需要快速檢索的場景,例如排行榜的玩家數據。
  3. 高效的資料操作
    適合的資料結構能簡化資料新增、刪除等操作,讓遊戲流程更順暢。例如:列表 (List) 適合用於需要頻繁增刪元素的場景,例如動態的物品欄。
  4. 降低處理負擔
    選用適當的資料結構可減少額外處理,進一步提升遊戲效能。例如:若需要按順序遍歷元素,使用 列表 (List) 而非字典 (Dictionary) 可避免多餘的鍵值查找。

資料序列化 (Serialization)

序列化是將資料轉換為可儲存或傳輸的格式(如 JSON 或 XML)。在 Unity 中,以下是常見的序列化方法

  1. 使用 JSON 序列化,適合用於需要與網路服務或跨平台數據交換的情境。而 Unity 內建的 JsonUtility 類別,適合簡單的序列化。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    using UnityEngine;

    [System.Serializable]
    public class GameData
    {
    public int playerLevel;
    public int playerScore;
    }

    public class SerializationExample : MonoBehaviour
    {
    private void Start()
    {
    // 建立資料
    GameData data = new GameData { playerLevel = 10, playerScore = 500 };

    // 序列化
    string json = JsonUtility.ToJson(data);
    Debug.Log("Serialized JSON: " + json);

    // 反序列化
    GameData loadedData = JsonUtility.FromJson<GameData>(json);
    Debug.Log("Loaded Level: " + loadedData.playerLevel);
    Debug.Log("Loaded Score: " + loadedData.playerScore);
    }
    }
  2. 使用 XML 序列化,XML (eXtensible Markup Language) 是一種結構化的數據格式,常用於儲存遊戲設定(configuration settings)或是與舊系統的兼容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    using System.IO;
    using System.Xml.Serialization;
    using UnityEngine;

    [System.Serializable]
    public class GameData
    {
    public int playerLevel;
    public int playerScore;
    }

    public class XmlSerializationExample : MonoBehaviour
    {
    private void Start()
    {
    // 建立資料
    GameData data = new GameData { playerLevel = 10, playerScore = 500 };

    // 序列化
    XmlSerializer serializer = new XmlSerializer(typeof(GameData));
    StringWriter writer = new StringWriter();
    serializer.Serialize(writer, data);
    string xml = writer.ToString();
    Debug.Log("Serialized XML: " + xml);

    // 反序列化
    StringReader reader = new StringReader(xml);
    GameData loadedData = (GameData)serializer.Deserialize(reader);
    Debug.Log("Loaded Level: " + loadedData.playerLevel);
    Debug.Log("Loaded Score: " + loadedData.playerScore);
    }
    }
  3. 二進位序列化(Binary serialization)
    二進位序列化是一種將物件壓縮成緊湊的二進位格式的方式,適合用於需要高效儲存或讀寫數據的情境,例如保存遊戲進度或本地化配置文件。相比於 JSON 或 XML 等文本格式,二進位格式在讀取和寫入速度上具有顯著優勢,同時生成的數據也更小。
    BinaryFormatter 在 ASP.NET 應用程式中已淘汰並禁止
  4. ScriptableObject
    ScriptableObject 是 Unity 中用來存儲資料的資源(assets)類型,提供一種直觀的方式來管理設定、參數和可重複使用的組件。它們在 Unity 編輯器中以序列化的格式儲存數據。
    1. 定義 ScriptableObject
      1
      2
      3
      4
      5
      6
      7
      8
      using UnityEngine;
      [CreateAssetMenu(fileName = "NewSettings", menuName = "Game Settings")]
      public class GameSettings : ScriptableObject
      {
      public int playerHealth;
      public int enemyCount;
      public float playerSpeed;
      }
    2. ScriptableObject 的序列化與反序列化
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      using UnityEngine;
      using System.IO;

      public class SettingsManager : MonoBehaviour
      {
      public GameSettings gameSettings; // 引用 ScriptableObject

      // 保存遊戲設定到檔案
      public void SaveSettings()
      {
      string jsonSettings = JsonUtility.ToJson(gameSettings); // 序列化為 JSON
      File.WriteAllText(Application.persistentDataPath + "/settings.json", jsonSettings); // 寫入檔案
      Debug.Log("Settings saved to " + Application.persistentDataPath + "/settings.json");
      }

      // 從檔案加載遊戲設定
      public void LoadSettings()
      {
      string path = Application.persistentDataPath + "/settings.json";
      if (File.Exists(path)) // 檢查檔案是否存在
      {
      string jsonSettings = File.ReadAllText(path); // 讀取檔案
      JsonUtility.FromJsonOverwrite(jsonSettings, gameSettings); // 將 JSON 加載到現有的 ScriptableObject
      Debug.Log("Settings loaded from " + path);
      }
      else
      {
      Debug.LogWarning("Settings file not found at " + path);
      }
      }
      }

PlayerPrefs

PlayerPrefs 是 Unity 提供的內建解決方案,用於以鍵(Key)值(Value)對的形式存儲小型資料,如玩家偏好設置、基本遊戲進度或遊戲內設置資料。它易於使用且跨平臺支持,適合管理輕量級資料。

  • PlayerPrefs 僅支持基礎類型(如 int、float 和 string),
  • 如果需要存儲更複雜的資料結構,則需要進行序列化。將資料轉換為 JSON 或 XML 格式,然後以字符串形式存儲到 PlayerPrefs 中。
  • PlayerPrefs 的資料以明文形式存儲,容易受到未授權的訪問。
  • 何時不使用 PlayerPrefs,儘管 PlayerPrefs 簡單易用,但在以下情況下可能並不適合:
    • 大型資料:對於複雜或大規模資料,就不適合使用,可改使用資料庫(如 SQLite)。
    • 敏感數據:對於高度敏感的信息,應考慮使用加密文件或平台特定的安全存儲方案。
    • 網絡同步:PlayerPrefs 不適合在設備間同步資料,應使用雲存儲或服務器端資料管理。

評論