一、利用txt文件存儲游戲物品信息
首先在asset下創建一個txt文件,這里我們命名為objectsInfoList.txt,並將其拖放到unity Project視圖中。
其中txt中我們先存放一些物品信息,每行存儲一種物品信息,分別為編號、名稱、物品對應的圖片名、種類、回血值、回藍值、出售價和購買價。
其中物品圖片要先用NGUI做成圖集,種類中的Drug為葯品類,以后在代碼中我們會定義一個枚舉用於存儲物品種類。

接下來我們創建一個空物體叫做GameSetting,上面掛一個腳本ObjectsInfo,我們把txt文件讀取到一個string中,根據'\n'及','分割字符串,取得對應的物品信息,然后存儲到Dictionary中,以后需要物品信息時便可以從dictionary中取出來了。
代碼如下,就不做具體解釋了。。。雖然注釋少點,但還是挺簡單的
1 using UnityEngine; 2 using System.Collections; 3 using System.Collections.Generic; 4 5 public class ObjectsInfo : MonoBehaviour 6 { 7 8 public static ObjectsInfo _instance; 9 public TextAsset objectsInfoListText; 10 11 private Dictionary<int, ObjectInfo> objectInfoDictionary = 12 new Dictionary<int, ObjectInfo>(); 13 14 void Awake() 15 { 16 _instance = this; 17 ReadInfo(); 18 } 19 20 public ObjectInfo GetObjectInfoById(int key) 21 { 22 ObjectInfo info = new ObjectInfo(); 23 objectInfoDictionary.TryGetValue(key, out info); 24 return info; 25 } 26 private void ReadInfo() 27 { 28 string text = objectsInfoListText.text; 29 string[] strArray = text.Split('\n'); 30 foreach (string str in strArray) 31 { 32 string[] proArray = str.Split(','); 33 34 ObjectInfo info = new ObjectInfo(); 35 36 int id = int.Parse(proArray[0]); 37 string name = proArray[1]; 38 string iconName = proArray[2]; 39 string typeStr = proArray[3]; 40 41 info.id=id; 42 info.name=name; 43 info.iconName=iconName; 44 ObjectType type = ObjectType.Drug; 45 switch (typeStr) 46 { 47 case "Drug": 48 type = ObjectType.Drug; 49 break; 50 case "Equip": 51 type = ObjectType.Equip; 52 break; 53 case "Mat": 54 type = ObjectType.Mat; 55 break; 56 } 57 info.type=type; 58 if (type == ObjectType.Drug) 59 { 60 int hp = int.Parse(proArray[4]); 61 int mp = int.Parse(proArray[5]); 62 int priceSell = int.Parse(proArray[6]); 63 int priceBuy = int.Parse(proArray[7]); 64 65 info.hp = hp; 66 info.mp = mp; 67 info.priceBuy = priceBuy; 68 info.priceSell = priceSell; 69 } 70 71 //添加到字典上,id為key,方便根據id查找 72 objectInfoDictionary.Add(id, info); 73 } 74 } 75 } 76 77 public enum ObjectType 78 { 79 Drug, 80 Equip, 81 Mat 82 } 83 84 //id,名稱,icon名稱,類型,加血值,加藍值,賣出價,買入價 85 public class ObjectInfo 86 { 87 public int id; 88 public string name; 89 public string iconName; 90 public ObjectType type; 91 public int hp; 92 public int mp; 93 public int priceSell; 94 public int priceBuy; 95 }
二、背包系統
1、設計背包系統的UI界面
主界面背景:新建一個sprite,選擇相應圖片,命名為Inventory
格子:在Inventory下創建sprite,並在下面創建一個label用來顯示物品數量,命名為NumLabel,然后做成prefab並復制多個
其他:整理背包按鈕、金錢圖標及顯示金幣數量的label
做出來的界面如下

2、控制背包物品的管理
我們給Inventory添加一個腳本命名為Inventory,給格子添加一個腳本命名為InventoryItemGrid方便對格子的管理
在Inventory腳本中,定義一個List<InventoryItemGrid> itemGridList用於存放背包的所有格子,並在unity界面中將所有格子拖過去賦值(注意要按照格子的順序賦值,所以格子創建完后,最好給格子分別命名一下如gide00,grid01.....,也方便以后的測試),並定義好金錢數目等變量;我們給背包添加一個tween動畫,控制背包的顯示與隱藏,並在腳本中提供相應方法,具體代碼如下
1 using UnityEngine; 2 using System.Collections; 3 using System.Collections.Generic; 4 5 public class Inventory : MonoBehaviour { 6 7 public static Inventory _instance; 8 private TweenPosition tweenPosition; 9 10 private int coinCount = 1000; 11 public UILabel coinCountLabel; 12 13 public List<InventoryItemGrid> itemGridList = new List<InventoryItemGrid>(); 14 15 // Use this for initialization 16 void Awake () { 17 _instance = this; 18 tweenPosition = GetComponent<TweenPosition>(); 19 } 20 21 private bool isShow = false; 22 private void Show() 23 { 24 isShow = true; 25 tweenPosition.PlayForward(); 26 } 27 28 private void Hide() 29 { 30 isShow = false; 31 tweenPosition.PlayReverse(); 32 } 33 34 35 public void TransformState() 36 { 37 if (!isShow) 38 { 39 Show(); 40 isShow = true; 41 } 42 else 43 { 44 Hide(); 45 isShow = false; 46 } 47 } 48 }
3、背包方格物品的prefab制作
在格子下創建一個sprite,可以隨便選一張圖片,調整大小使之適應格子大小,將其做成prefab,添加一個腳本命名為InventoryItem
由於我們的物品應該是可以拖動的,所以應attach一個Box Collider,腳本InventoryItem讓其繼承於UIDragDropItem 便可以實現拖拽功能了。定義一個int id用於設置要顯示物品的id,並提供一個SetId方法控制對應圖片的顯示。代碼如下:
using UnityEngine; using System.Collections; public class InventoryItem : UIDragDropItem { private UISprite sprite; private int id; void Awake() { base.Awake(); sprite = this.gameObject.GetComponent<UISprite>(); } public void SetId(int id) { ObjectInfo info = ObjectsInfo._instance.GetObjectInfoById(id); sprite.spriteName = info.iconName; this.id = id; } }
4、控制方格對下面物品的管理
InventoryItemGrid腳本中定義變量id為物品的編號,num為物品的數量,以及UILabel控制物品數量的顯示,並獲取格子下面物品上的腳本InventoryItem調用上面的SetId方法,設置物品相應的圖片。代碼很簡單。。。
1 using UnityEngine; 2 using System.Collections; 3 4 public class InventoryItemGrid : MonoBehaviour { 5 6 public int id = 0; 7 public int num = 0; 8 private ObjectInfo info = null; 9 private UILabel numLabel; 10 11 void Start() 12 { 13 numLabel = this.GetComponentInChildren<UILabel>(); 14 } 15 16 public void SetId(int id, int num = 1) 17 { 18 this.id = id; 19 info = ObjectsInfo._instance.GetObjectInfoById(id); 20 InventoryItem item = this.GetComponentInChildren<InventoryItem>(); 21 this.num = num; 22 numLabel.text = this.num.ToString(); 23 numLabel.enabled = true; 24 25 item.SetId(id); 26 } 27 28 public void PlusNum(int num = 1) 29 { 30 this.num += num; 31 numLabel.text = this.num.ToString(); 32 } 33 public void ClearInfo() 34 { 35 id = 0; 36 num = 0; 37 info = null; 38 numLabel.enabled = false; 39 } 40 }
5、背包物品的拾取功能
由於我們txt文件中只存儲了3種物品,這里我們使用隨機數模擬一下拾取功能,每次按下x鍵隨機一個數,並根據id取得該物品其他信息,實例化該物體並調整坐標及parent
1 void Update () { 2 if (Input.GetKeyDown(KeyCode.X)) 3 { 4 GetSomething(Random.Range(1001, 1004)); 5 } 6 } 7 8 private void GetSomething(int id) 9 { 10 InventoryItemGrid grid = null; 11 //檢測grid中有沒有當前物體 12 foreach (InventoryItemGrid temp in itemGridList) 13 { 14 if (temp.id == id) 15 { 16 grid = temp; 17 break; 18 } 19 } 20 if (grid != null)//有當前物體 num加1 21 { 22 grid.PlusNum(1); 23 } 24 else//沒有當前物體 查找是否有空格 根據id是否為0判斷 25 { 26 foreach (InventoryItemGrid temp in itemGridList) 27 { 28 if (temp.id == 0) 29 { 30 grid = temp; 31 break; 32 } 33 } 34 35 if (grid != null)//有空格 36 { 37 //在當前格實例化物體 38 GameObject go = NGUITools.AddChild(grid.gameObject, inventoryItemGameobject); 39 go.transform.localPosition = Vector3.zero; 40 go.GetComponent<UISprite>().depth = 8; 41 grid.SetId(id); 42 43 } 44 else//沒有空格 45 { 46 print("背包滿了"); 47 } 48 49 } 50 }
6、實現背包物品的拖拽功能
物品的拖拽有幾種情況需要分別實現:物品拖到一個空格,物品拖到有物品的格子、兩物品應交換位置信息,物品拖到背包界面外等應還在當前格子
拖拽功能的實現應在protected override void OnDragDropRelease(GameObject surface) 這個函數中實現,判斷拖放結束時停留的物體為surface,要區分surface的類別,應根據tag來實現,因此我們給所有的格子添加Tag InventoryItemGrid,給物品添加Tag InventoryItem,為了方便tag管理我們添加一個Tags腳本,其中存儲各種Tags信息
1 using UnityEngine; 2 using System.Collections; 3 4 public class Tags : MonoBehaviour { 5 6 public const string GROUND = "Ground"; 7 public const string PLAYER = "Player"; 8 public const string INVENTORY_ITEM = "InventoryItem"; 9 public const string INVENTORY_ITEM_GRID = "InventoryItemGrid"; 10 }
物品拖拽功能的實現代碼如下
1 protected override void OnDragDropRelease(GameObject surface) 2 { 3 base.OnDragDropRelease(surface); 4 5 if (surface != null) 6 { 7 //拖放到一個有物體的格子 8 if (surface.tag == Tags.INVENTORY_ITEM) 9 { 10 InventoryItemGrid oldGrid = this.transform.parent.GetComponent<InventoryItemGrid>(); 11 int id = oldGrid.id; 12 int num = oldGrid.num; 13 InventoryItemGrid newGrid = surface.transform.parent.GetComponent<InventoryItemGrid>(); 14 15 //交換數據 16 oldGrid.SetId(newGrid.id, newGrid.num); 17 newGrid.SetId(id, num); 18 19 ResetPosition(); 20 } 21 //拖放到一個空格子 22 else if (surface.tag == Tags.INVENTORY_ITEM_GRID) 23 { 24 //拖放到自己的格子 25 if (surface.transform.parent == this.transform.parent) 26 { 27 ResetPosition(); 28 } 29 else//其他空格子 30 { 31 InventoryItemGrid oldGrid = this.transform.parent.GetComponent<InventoryItemGrid>(); 32 33 InventoryItemGrid nowGrid = surface.GetComponent<InventoryItemGrid>(); 34 this.transform.parent = surface.transform; 35 ResetPosition(); 36 nowGrid.SetId(oldGrid.id, oldGrid.num); 37 oldGrid.ClearInfo(); 38 } 39 40 } 41 else 42 { 43 ResetPosition(); 44 } 45 } 46 else 47 { 48 ResetPosition(); 49 } 50 } 51 52 private void ResetPosition() 53 { 54 transform.localPosition = Vector3.zero; 55 }
7、背包物品的信息提示
在unity背包下面添加一個sprite作為提示信息的背景,背景下面添加一個label顯示提示信息。
我們應在鼠標放在物品上時顯示該物品的詳細信息,鼠標移出時提示信息框則應消失。要實現這種效果,我們可以在物品prefab上添加一個NGUI提供的UI Event Trigger組件,On Hover Over和On Hover Out分別綁定InventoryItem中的兩個函數
public void OnHoverOver() { InventoryDes._instance.Show(id,this.transform.position); } public void OnHoverOut() { InventoryDes._instance.Hide(); }
在界面上提示信息的sprite上面掛一個腳本命名為InventoryDes,該腳本控制提示信息的顯示隱藏等功能
1 using UnityEngine; 2 using System.Collections; 3 4 public class InventoryDes : MonoBehaviour { 5 6 public static InventoryDes _instance; 7 8 private UILabel label; 9 void Awake() 10 { 11 _instance = this; 12 label = this.GetComponentInChildren<UILabel>(); 13 this.gameObject.SetActive(false); 14 } 15 16 public void Show(int id,Vector3 pos) 17 { 18 this.gameObject.SetActive(true); 19 this.transform.position = pos; 20 ObjectInfo info = ObjectsInfo._instance.GetObjectInfoById(id); 21 string des = ""; 22 switch (info.type) 23 { 24 case ObjectType.Drug: 25 des = GetDrugDes(info); 26 break; 27 case ObjectType.Equip: 28 break; 29 case ObjectType.Mat: 30 break; 31 } 32 label.text = des; 33 } 34 35 public void Hide() 36 { 37 this.gameObject.SetActive(false); 38 } 39 private string GetDrugDes(ObjectInfo info) 40 { 41 string s = ""; 42 s += "名稱:" + info.name + "\n"; 43 s += "回復Hp:" + info.hp + "\n"; 44 s += "回復Mp:" + info.mp + "\n"; 45 s += "出售價:" + info.priceSell + "\n"; 46 s += "購買價:" + info.priceBuy + "\n"; 47 return s; 48 } 49 }
8、背包物品的整理功能
當我們背包中的物品排列很散亂是,點擊整理按鈕,所有的物品應有序的從前到后排列整齊,中間應該沒有空格,這個功能該如何實現呢?這里提供一種方法,可能效率不是最高的(沒有想到更好的實現方法,有更好方法的朋友請告訴我一下,謝謝),但可以實現基本要求:


例如上面的圖,有紅圈的地方代表有物體,其余為空格,我們怎樣將物品排列好使之沒有空格呢?我們可以先將所有格子遍歷一變,記下空格的索引;然后從最小的索引
開始向后循環,將所有格子從后向前遍歷,如果格子中有物體則將其移動到該空格索引對應的格子中,然后繼續...
下面是代碼:
1 //整理背包物品 2 public void OnArrangeInventory() 3 { 4 List<int> nullGridIndexList = new List<int>(); 5 for (int i = 0; i < itemGridList.Count; i++) 6 { 7 if (itemGridList[i].id == 0) 8 { 9 nullGridIndexList.Add(i); 10 } 11 } 12 //背包滿了不整理 13 if (nullGridIndexList.Count != 0) 14 { 15 16 foreach (int index in nullGridIndexList) 17 { 18 19 for (int i = itemGridList.Count - 1; i > index; i--) 20 { 21 if (itemGridList[i].id != 0) 22 { 23 if (i > index) 24 { 25 ExchangeItemToANullGrid(index, i); 26 break; 27 } 28 else 29 break; 30 } 31 } 32 } 33 } 34 } 35 36 //index為空格子索引, i為有物品的格子 37 private void ExchangeItemToANullGrid(int index, int i) 38 { 39 40 Transform transform = itemGridList[i].GetComponentInChildren<InventoryItem>().gameObject.transform; 41 transform.parent 42 = itemGridList[index].transform; 43 transform.localPosition = Vector3.zero; 44 itemGridList[index].SetId(itemGridList[i].id, itemGridList[i].num); 45 itemGridList[i].ClearInfo(); 46 }
至此,一個簡單但功能齊全的背包系統便做好了!
