NGUI簡單背包系統的實現


  一、利用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     }

   至此,一個簡單但功能齊全的背包系統便做好了! 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM