RPG遊戲《黑暗之光》流程介紹與代碼分析之(六):揹包系統的實現(下)

接着(上)部分的內容,本節關注物品欄中一些功能的實現,及
  • 拾取操作的模擬
  • 揹包的顯示與隱藏
  • 物品提示信息

5.4 拾取模擬

有了(上)部分的鋪墊,本節的目標是實現物品拾取功能。
物品拾取功能的邏輯分爲三步:
  • 查找所有物品中是否存在該物品
  • 如果存在,num+1
  • 如果不存在,查找空的網格,把新建的Inventory放入此方格中
首先,我們採用按鍵X模擬拾取動作
public GameObject InventoryItem;
void Update()
    {
        if (Input.GetKeyDown (KeyCode.X))    //每次按下X都隨機拾取一種藥品
        {
            GetId(Random.Range(1001,1004));        
        }
    }
    public void GetId(int id)
    {
        InventoryItemGrid grid = null;
        foreach (InventoryItemGrid temp in itemGridList)    //這個循環判斷temp.id是否等於當前網格的id,若是,  grid = temp,否則grid爲null
        {
            if(temp.id == id)
                grid = temp;break;
        }
        if (grid != null)    //如果存在該物品
        {
            grid.PlusNumber();
        }
        else    //不存在
        {
            foreach(InventoryItemGrid temp in itemGridList)
            {
                if(temp.id == 0)
                {
                    grid = temp;break;
                }
            }
            if(grid != null)
            {
                GameObject itemGO = NGUITools.AddChild(grid.gameObject,InventoryItem);
                itemGO.transform.localPosition = Vector3.zero;    //每個物體在網格中的相對座標都是0
                grid.SetId(id);
            }
        }
    }
運行後,即可看到結果

此時,網格中的的數字會被藥品所遮擋。需要調整一下InventoryItemGrid和NumbelLabel的depth,由於Inventory是6,修改InventoryItemGrid和NumbelLabel的depth爲7和9,即可解決。8留給新添加的物品

因此,在添加物品的時候,直接將其depth設置爲8,即
itemGO.GetComponent<UISprite>().depth = 8;    //通過訪問UISprite元素以改變depth的值

5.5 揹包的顯示與隱藏

在開始時,揹包默認爲隱藏,只有點擊揹包按鈕時,才進行顯示。因此在Inventory的Awake()中和show()中設定,隱藏則在Hide()中設定。判斷動畫播放完成後,進行隱藏
   void Awake(){    //用Awake而不用Start是因爲Awake是在腳本對象實例化時被調用,而Start是在第一幀被調用
        _instance = this;
        tween = this.GetComponent<TweenPosition> ();
        tween.AddOnFinished (this.OnTweenPlayFinished);    //通過AddOnFinished監聽動畫是否播放完成,若完成,則isShow = false,隱藏揹包欄
        this.gameObject.SetActive (false);
    }

private bool isShow = false;    //初始化isShow爲false,表示初始時不顯示

    void Show()
    {
        isShow = true;
        this.gameObject.SetActive (true);
        tween.PlayForward ();
    }
    void Hide()
    {
        isShow = false;
        tween.PlayReverse ();
    }

    void OnTweenPlayFinished()    //播放完畢後,隱藏
    {
        if (isShow == false)
        {
            this.gameObject.SetActive(false);
        }
    }

    public void TransformState()
    {
        if (isShow == false)    
        {
            Show ();
        }
        else
        {
            Hide ();
        }
    }
但這裏會出現如下的錯誤,主要原因是Inventory設置爲隱藏時,Inventory的子文件InventoryItemGrid將無法訪問。因此,Inventory不需要隱藏,只要播放tween動畫後Inventory處在Camera之外即可。

故刪除OnTweenPlayFinished() 函數即可實現功能。

5.6 揹包物品的提示信息

爲了提高遊戲性,在鼠標放在物品之上時,需要顯示物品信息。在揹包Inventory中添加一個Child Sprite,作爲信息描述界面,並在其中添加一個Child Label,如下所示

當鼠標放在物品上時,要實現的功能包括
  1. 更新DesLabel的描述
  2. 更新InventoryDes的位置
接下來實現上述兩個功能。將InventoryDes的中心點設置爲左上角,即Widget中的Pivot設置爲LeftTop

首先,DesLabel的描述如下,
public class InventoryDes : MonoBehaviour {

    public static InventoryDes _instance;    //描述設置爲實例
    private UILabel label;
    // Use this for initialization
    void Awake () {
        _instance = this;
        label = this.GetComponentInChildren<UILabel> ();
    }
    
    // Update is called once per frame
    void Update () {
    
    }

    public void Show(int id)
    {
        ObjectsInfo.ObjectInfo info = ObjectsInfo._instance.GetObjectInfoFromDict (id);    //通過Show()傳遞的id獲取info信息。
        string des = "";
        switch (info.type) {    //判斷info中的物品種類
        case ObjectsInfo.ObjectType.Drug:
            des = GetDrugDes(info);
            break;
                }
        label.text = des;
    }

    string GetDrugDes(ObjectsInfo.ObjectInfo info)    //具體描述,返回一個string
    {
        string str = "";
        str += "名稱:" + info.name + "\n";
        str += "回覆血量值:" + info.hp + "\n";
        str += "回覆魔法值:" + info.mp +"\n";
        str += "出售價:" + info.price_sell + "\n";
        str += "購買價:" +info.price_buy + "\n";

        return str;
    }

}
之後,爲了監聽鼠標是否移動到物品上方,我們在Prefabs之中的InventoryInsideItem,添加EventListener和EventTrigger,並在InventoryInsideItem腳本中新建兩個函數處理這兩個事件
    public void OnHoverOver()
    {
        print ("enter");
    }
    
    public void OnHoverOut()
    {
        print ("exit");
    }

即可在鼠標移動到物品上是顯示enter,移出時顯示exit,事件被成功監聽,可以對事件中的代碼進行操作。

爲了實現顯示提示的效果,我們需要在InventoryInsideItem中調用Show()函數時獲取當前的id,因此可以利用InventoryInsideItem中的SetIconName(string icon_name)函數,添加一個形參id,傳入id值,更新OnHoverOver()和OnHoverOut()
private int id;
    private bool isHover = false;    //isHover作爲標誌位
    public void OnHoverOver()
    {
        isHover = true;
    }
    
    public void OnHoverOut()
    {
        isHover = false;
    }
void Update()
    {
        if (isHover)
        {
            InventoryDes._instance.Show (id);    //若isHover爲true,顯示信息
        }
    }
如下所示

最後只需要實現跟隨鼠標功能即可
在每次調用InventoryDes中的Show()時,需要更改提示框的位置。在Show()中添加
this.gameObject.SetActive (true);
timer1 = 0.1f;
transform.position = UICamera.currentCamera.ScreenToWorldPoint (Input.mousePosition);
以獲取當前鼠標的位置信息,並賦值給提示框,將提示框在Awake()中進行隱藏
this.gameObject.SetActive (false);
之後,在Update()中判斷提示框是否處於隱藏來計時,並在計時結束後隱藏提示框
    void Update () {
        if (this.gameObject.activeInHierarchy == true)    //當前提示框是否處於隱藏狀態,true表示顯示
        {
            timer1 -= Time.deltaTime;    //將timer1減0.1秒
        }
        if (timer1 <= 0)    //當計時器小於0時,即鼠標離開後,隱藏提示框
        {
            this.gameObject.SetActive(false);
        }
    }

至此,就實現了提示框跟隨鼠標移動的功能。


總結:揹包系統的工程量較大,實現之前需要對整體的邏輯進行整理,否則挺容易出Bug的。。
發佈了96 篇原創文章 · 獲贊 140 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章