在Unity游戲開發中,Dictionary
和List
是最核心的兩種數據結構,它們各自有優勢和應用場景。以下是介紹:
🧠 數據結構本質對比
特性 | Dictionary<TKey, TValue> | List |
---|---|---|
底層結構 | 哈希表(Hash Table) | 動態數組(Dynamic Array) |
查找效率 | O(1) 按鍵查找 | O(n) 遍歷查找 |
插入/刪除效率 | O(1) ~ O(n) (哈希沖突時) | O(n) (需移位) |
內存占用 | 較高(存儲哈希桶和指針) | 較低(連續內存) |
數據順序 | 無序 | 嚴格順序 |
核心優勢 | 鍵值配對 + 高速查找 | 順序訪問 + 隨機索引 |
各自擅長領域
**Dictionary **
// 典型案例:用ID快速定位游戲對象
Dictionary<int, Enemy> _enemyDict = new Dictionary<int, Enemy>();void SpawnEnemy(int id) {Enemy prefab = Resources.Load<Enemy>($"Enemies/{id}");Enemy enemy = Instantiate(prefab);_enemyDict.Add(id, enemy); // O(1)插入
}Enemy GetEnemy(int id) {return _enemyDict.TryGetValue(id, out Enemy e) ? e : null; // O(1)查找
}
適用場景:
? 通過唯一ID查找對象(玩家/敵人/NPC)
? 建立資源路徑與實例映射(如:“Weapons/Sword” → 預制體)
? 實時數據索引(成就ID → 完成狀態)
? 避免重復添加(用ContainsKey
檢查存在性)
📜 **List **
// 典型案例:游戲對象批量處理
List<Bullet> _activeBullets = new List<Bullet>();void UpdateBullets() {for(int i = 0; i < _activeBullets.Count; ) {if(_activeBullets[i].IsExpired) {_activeBullets.RemoveAt(i); // 移除時需小心索引變化} else {_activeBullets[i++].Update();}}
}// 添加新子彈
void FireBullet() {Bullet b = _bulletPool.Get();_activeBullets.Add(b); // O(1)尾部添加
}
適用場景:
? 需要嚴格順序的數據(對話文本序列)
? 需高頻遍歷的集合(每幀更新所有子彈)
? 動態增減的集合(背包物品、技能冷卻隊列)
? 需要排序操作的場景(玩家積分排行榜)
經典組合應用
1. 背包系統(高性能實現)
Dictionary<int, ItemData> _itemDB; // 靜態數據表:ID->屬性
Dictionary<int, ItemInstance> _inventoryDict; // 庫存實例:ID->實例
List<ItemInstance> _inventoryList; // 顯示用有序列表void AddItem(int itemId, int count) {// 1. 從字典快速檢查存在性if(_inventoryDict.TryGetValue(itemId, out ItemInstance instance)) {instance.count += count; // 堆疊} else {// 2. 創建新實例ItemData data = _itemDB[itemId]; // 從靜態字典取數據instance = new ItemInstance(data, count);// 3. 同步雙結構_inventoryDict.Add(itemId, instance);_inventoryList.Add(instance); }// 4. 列表排序(List專長)_inventoryList.Sort(SortByRarity);
}// 排序邏輯(List專屬操作)
int SortByRarity(ItemInstance a, ItemInstance b) {return b.data.rarity.CompareTo(a.data.rarity);
}
?? 2. 對象池系統(高效復用)
Dictionary<GameObject, List<GameObject>> _pool = new Dictionary<GameObject, List<GameObject>>();GameObject Spawn(GameObject prefab) {// 1. 字典查找對應對象池if(!_pool.TryGetValue(prefab, out List<GameObject> list)) {list = new List<GameObject>();_pool.Add(prefab, list);}// 2. 列表查找可用對象foreach(GameObject obj in list) {if(!obj.activeInHierarchy) return obj;}// 3. 列表無可用則創建新對象GameObject newObj = Instantiate(prefab);list.Add(newObj); // 加入Listreturn newObj;
}
🛡? 3. 技能管理系統
Dictionary<string, SkillData> _skillDB; // ID->技能配置
List<ActiveSkill> _activeSkills; // 激活中技能列表void CastSkill(string skillId) {// 1. 從字典讀取基礎數據(O(1))SkillData data = _skillDB[skillId];// 2. 創建技能實例ActiveSkill skill = new ActiveSkill(data);// 3. 加入List進行更新_activeSkills.Add(skill);
}void Update() {// 4. 遍歷List更新技能(順序重要!)for(int i=0; i<_activeSkills.Count; i++) {_activeSkills[i].Update();}
}
?? 避坑指南
-
字典遍歷陷阱
// 錯誤!修改集合時不能遍歷 foreach(var key in _dict.Keys) {if(condition) _dict.Remove(key); // 拋出InvalidOperationException }// 正確做法 List<TKey> keysToRemove = new List<TKey>(); foreach(var key in _dict.Keys) {if(condition) keysToRemove.Add(key); } foreach(var key in keysToRemove) {_dict.Remove(key); }
-
列表刪除優化
// 正序刪除導致索引錯亂 for(int i=0; i<list.Count; i++) {if(condition) list.RemoveAt(i--); // 需手動調整索引 }// 倒序刪除更安全 for(int i=list.Count-1; i>=0; i--) {if(condition) list.RemoveAt(i); }
-
空值防御
// 字典安全訪問 if(_dict.TryGetValue(key, out var value)) {// 安全操作value }// 列表邊界檢查 if(index >= 0 && index < list.Count) {var item = list[index]; }
如何選擇 
!:
- 頻繁查找 + 無序數據 → Dictionary
- 順序訪問/修改 → List
- 需要兩者特性 → Dictionary與List聯動
在Unity 2023+版本中,可考慮HashSet
(無值字典)或LinkedList
(高效增刪),但Dictionary+List組合仍是90%游戲系統的首選,尤其在需要高性能查詢和靈活排序的場景中。