Unity3D遊戲開發之C#程式設計中常見資料結構的比較
一.前言
Unity3D是如今最火爆的遊戲開發引擎,它可以讓我們能輕鬆建立諸如三維視訊遊戲、建築視覺化、實時三維動畫等型別的互動內容。它支援2D/3D遊戲開發,據不完全統計,目前國內80%的手機遊戲都是用Unity3D開發。
由於Unity3D在開發過程中使用最多的是C# 語言,所以就要合理的使用C#提供的一些資料結構是非常有必要的,合理的選擇資料結構可以加快開發速度,提高遊戲執行效能,不合理的使用資料結構則會導致遊戲執行效能降低,加大開發複雜程度!
先通過表格看看常用的資料結構:
C#常用資料結構 |
中文名 |
Array |
普通陣列 |
ArrayList |
陣列集合 |
List<T> |
泛型陣列 |
LinkList<T> |
泛型連結串列 |
Stack |
棧 |
Queue |
佇列 |
HashTable |
雜湊表 |
Dictionary<K,T> |
字典 |
然後先大概瞭解這些資料結構的用法。
二.資料結構之間比較和部分使用案列
1.陣列(Array)在一般的程式設計中較為常見,是最簡單的資料結構之一,具有三個特點:陣列儲存的資料都是在連續的記憶體單元上,陣列中的元素都是同一型別,陣列可通過下標直接訪問。缺點是陣列是連續儲存,在兩個元素之間插入新的元素時很不方便,在建立陣列時必須指定長度或初始化元素,就會面臨溢位或記憶體浪費的問題。2.ArrayList就可以解決Array帶來的一些缺點:無需指定大小或初始化元素。可以動態的插入資料元素,無需考慮溢位或浪費記憶體的事。ArrayList可以儲存不同資料型別的原因是由於把所有型別都當作Object型別來處理,使用時很有可能會發生型別不匹配的問題,這也就說明ArrayList是型別不安全的資料結構,在頻繁的進行讀寫(裝箱拆箱)操作ArrayList的過程中會產生額外的開銷,導致效能下降,所以在開發過程中使用ArrayList較少!
3.為了解決ArrayList不安全型別與裝箱拆箱的缺點,List<T>作為一種新的陣列型別引入,繼承了ArrayList的一些優點,且確保了型別的安全,因無需進行裝箱拆箱操作,因此List<T>是高效能的,所以List<T>在遊戲開發過程中經常用到的陣列型別。以下是List<T>的簡單操作:
List<string> Lstr=new List<string>();
Lstr.Add(“元素一”); // 插入資料元素
Lstr[0]=“元素二”; // 修改資料元素
Lstr.RemoveAt(0); // 移除資料元素
在Unity3D遊戲開發中,我們可以使用List<GameObject>來儲存遊戲物件,比如在射擊遊戲中的子彈,或角色扮演遊戲中的NPC,都可以使用List<GameObject>進行儲存。
4.LinkList<T>的特點是鏈中的每一個元素都指向下一個元素,這樣救構成了一條鏈。在插入和刪除某個資料元素時時間複雜度都為O(1)。
5.Stack(棧)的特點是先進後出。
6.Queue(佇列)的特點是先進先出。
7.我通過遊戲開發中的用法來介紹雜湊表的使用和它的一些特點。在遊戲開發過程中,我們通常會涉及到通過遊戲角色的ID來正確匹配英雄角色,所以每個英雄角色都要有自己唯一的ID,每個英雄角色的ID和他們的角色名進行一一對應,那麼,我們就可以使用雜湊表進行儲存這種資料,假設有如下資訊:
序號 |
ID |
角色名稱 |
1 |
2059 |
亞瑟 |
2 |
“2060” |
妲己 |
3 |
“ABC” |
后羿 |
4 |
2061.5 |
宮本武藏 |
使用雜湊表儲存的程式碼如下:
Hashtable Hero = new Hashtable ();
// Hero.Add (key,value);
Hero.Add (2059,"亞瑟"); //插入第1個元素
Hero.Add (“2060”,"妲己"); //插入第2個元素
Hero.Add (“ABC”,"后羿"); //插入第3個元素
Hero.Add (2061.5,"宮本武藏"); //插入第4個元素
// 通過key訪問value
if (Hero.ContainsKey (“2060”)) {
Debug.Log ("該隊伍中包含妲己");
} else {
Debug.Log ("該隊伍中不包含妲己");
}
通過以上的程式碼可以發現雜湊表可以接收任意型別值作為key(key和value的型別都為object型別),其實這就體現出雜湊表型別不安全。
8.為了解決雜湊表型別不安全,我們可以使用Dictionary<K,T>來儲存資料,可以將上面的程式碼改寫成下面程式碼:
Dictionary<int ,string> Hero = new Dictionary<int, string> ();
// Hero.Add (int key,string value);
Hero.Add (2059,"亞瑟"); //插入第1個元素
Hero.Add (2060,"妲己"); //插入第2個元素
Hero.Add (2061,"后羿"); //插入第3個元素
Hero.Add (2062,"宮本武藏"); //插入第4個元素
// 通過 key(int)訪問value(string)
if (Hero.ContainsKey (2061)) {
Debug.Log ("該隊伍中包含后羿");
} else {
Debug.Log ("該隊伍中不包含后羿");
}
對比雜湊表,字典保證了型別的安全,但世界上並不存在十全十美的東西,程式碼也是如此,字典通過空間換時間,通過更多的記憶體開銷來滿足對速度的追求。在建立字典時,可以傳入一個字典容量值,但在實際使用時並非該值,而是使用不小於該值的最小質數最為它的實際容量,所以字典容量的最小值是3。且當有了實際容量後,並非直接實現索引,而是通過建立了兩個額外的Array陣列來實現間接的索引。面臨的情況就是,即便建立了一個空的字典,伴隨而來的是兩個長度為3的陣列。所以當處理的資料不多時,慎重使用字典。
三.總結
在遊戲開發過程中,很多情況下使用普通陣列也是可以的,資料結構的選取需要考慮資料的大小和使用場景才能合理的儲存和處理該資料。優秀的程式設計師需要考慮機器執行的效能,合理的選擇一些資料結構可以提高程式執行效能和降低開發複雜