5-18 Forge Panel
本章要來教大家製作鍛造系統,首先,我們要有一個儲存鍛造公式的Json文件,分別紀錄材料ID跟數量,以及鍛造結果的ID,範例如下:
記得要將Json文件儲存在Resources資料夾底下,我們會用Resource.Load讀取。
接著,因為目前的介面已經滿了,所以我將商店的介面藏起來,如下圖。
隱藏的方式,請在Vendor Panel的Inspector內設定Panel的Panel Alpha為0,Canvas Group的Alpha為0即可,如下圖。
接著我們複製一下Vendor Panel重複利用。
取名為Forge Panel,我們的鍛造介面只需要兩個Slot,所以將其他無用的Slot刪除。
我複製了Close Btn,改成啟動鍛造的按鈕,取名為Forge Btn。
在Forge Btn底下新增UI/Text,文字寫『開始』,請大家自己設定一下字型大小跟顏色。
完成後,介面大致上如下圖。
接著建立Script名為ForgeFormula.cs,這是要用來放置解析Json資料後的類別。
ForgeFormula.cs:
再來建立ForgeSlot.cs,由於本次鍛造的Slot沒有特殊處理,所以沒有覆寫OnPointerDown方法,另外也可用來讓InventorySystem識別不同種類的Slot。
記得Forge Panel內的兩個ForgeSlot也要修改為ForgeSlot.cs唷!
再來是於Forge Panel按下『開始』按鈕的事件,我們先要取得目前Forge Slot內有哪些Item,並將這些材料存入materialsIDList。
然後用foreach迴圈取得每個ForgeFormula物件,並與materialIDList一一配對材料是否符合,符合公式的話便將鍛造成果存到背包內,並消耗對應的材料。
來執行遊戲看看吧,我放入一個鍛造秘笈跟兩個鐵塊。
按下『開始』後,背包內出現了一把斧子,然後材料也被消耗掉了。
{"ForgeFormulaEntityList":[ { "Item1ID":15, "Item1Amount":1, "Item2ID":17, "Item2Amount":2, "ResultID":13 }, { "Item1ID":16, "Item1Amount":1, "Item2ID":17, "Item2Amount":5, "ResultID":8 } ]}
記得要將Json文件儲存在Resources資料夾底下,我們會用Resource.Load讀取。
接著,因為目前的介面已經滿了,所以我將商店的介面藏起來,如下圖。
隱藏的方式,請在Vendor Panel的Inspector內設定Panel的Panel Alpha為0,Canvas Group的Alpha為0即可,如下圖。
接著我們複製一下Vendor Panel重複利用。
取名為Forge Panel,我們的鍛造介面只需要兩個Slot,所以將其他無用的Slot刪除。
我複製了Close Btn,改成啟動鍛造的按鈕,取名為Forge Btn。
在Forge Btn底下新增UI/Text,文字寫『開始』,請大家自己設定一下字型大小跟顏色。
完成後,介面大致上如下圖。
接著建立Script名為ForgeFormula.cs,這是要用來放置解析Json資料後的類別。
ForgeFormula.cs:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace RPG.Inventory{ [Serializable] public class ForgeFormulaList{ public ListForgeFormulaEntityList; } [Serializable] public class ForgeFormula : ISerializationCallbackReceiver{ public int Item1ID; public int Item1Amount; public int Item2ID; public int Item2Amount; public int ResultID; List requireList = new List (); public void OnAfterDeserialize(){ for (int i = 0; i < Item1Amount; i++) { requireList.Add (Item1ID); } for (int i = 0; i < Item2Amount; i++) { requireList.Add (Item2ID); } } public List GetRequireList(){ return requireList; } public void OnBeforeSerialize(){} public bool MatchFormula(List materialsIDList){ List checkList = new List (materialsIDList); foreach(int ID in requireList){ bool isSuccess = checkList.Remove (ID); if (isSuccess == false) { return false; } } return true; } } }
再來建立ForgeSlot.cs,由於本次鍛造的Slot沒有特殊處理,所以沒有覆寫OnPointerDown方法,另外也可用來讓InventorySystem識別不同種類的Slot。
ForgeSlot.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace RPG.Inventory{ public class ForgeSlot : Slot { } }
記得Forge Panel內的兩個ForgeSlot也要修改為ForgeSlot.cs唷!
再來是修改InventorySystem的部分啦!我將主要修改的程式碼截圖說明,如下圖為解析Json的部分。
再來是於Forge Panel按下『開始』按鈕的事件,我們先要取得目前Forge Slot內有哪些Item,並將這些材料存入materialsIDList。
以下提供InventorySystem.cs的完整程式碼:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.UI; using UnityEngine.EventSystems; namespace RPG.Inventory{ public class InventorySystem : MonoBehaviour { [SerializeField] ToolTip toolTip; [SerializeField] ItemUI pickedItem; [SerializeField] CharacterProperty characterProperty; public bool isPickedItem = false; ItemList itemList; ForgeFormulaList forgeFormulaList; Slot[] slotList; int coinAmount = 100; Text coinText; void Start () { ParseItemsJson (); ParseForgeFormulaJson (); slotList = GetComponentsInChildren(); coinText = GameObject.Find ("Coin").GetComponentInChildren (); coinText.text = coinAmount.ToString(); InitialVendorItem (); } void Update(){ PressGToAddItem (); MovePickedItemByMousePosition (); DiscardPickedItem (); } private bool ConsumeCoin(int amount){ if (coinAmount > 0) { coinAmount -= amount; coinText.text = coinAmount.ToString (); return true; } return false; } private void EarnCoin(int amount){ coinAmount += amount; coinText.text = coinAmount.ToString (); } public void BuyItem(Item item){ bool isSuccess = ConsumeCoin (item.BuyPrice); if (isSuccess) { StoreItem (item); } } public void SellItem(int sellAmount){ int sellPrice = pickedItem.Item.SellPrice * sellAmount; ReducePickedItem (sellAmount); EarnCoin (sellPrice); } public void PickupItem(Item item, int amount){ pickedItem.SetItem (item, amount); pickedItem.Show (); toolTip.Hide (); isPickedItem = true; } public void ReducePickedItem(int amount){ pickedItem.ReduceAmount(amount); if (pickedItem.Amount <= 0) { isPickedItem = false; pickedItem.Hide (); } } public void WearingEquipment(ItemUI equipmentToWear){ if ((equipmentToWear.Item is Equipment) == false) { return; } foreach(Slot slot in slotList){ EquipmentSlot equipmentSlot = (slot as EquipmentSlot); if(equipmentSlot && equipmentSlot.EquipmentTypeIsEqual (equipmentToWear.Item)){ if (equipmentSlot.transform.childCount > 0) { // 人物已配戴裝備了,將裝備與背包的裝備交換 equipmentSlot.GetComponentInChildren ().ExchangeItem(equipmentToWear); } else { // 人物未配戴裝備,直接穿上 equipmentSlot.StoreItem (equipmentToWear.Item); // 銷毀背包內的裝備 Destroy (equipmentToWear.gameObject); } break; } } UpdatePropertyText (); } public ItemUI GetPickedItem(){ return pickedItem; } public Slot[] GetSlotList(){ return slotList; } public void ShowToolTip(string content){ toolTip.Show (content); } public void HideToolTip(){ toolTip.Hide (); } public void UpdatePropertyText(){ characterProperty.UpdatePropertyText (); } public bool StoreItem(int id){ Item item = GetItemByID (id); return StoreItem (item); } public bool StoreItem(Item item){ if (item == null) { return false; } // 若物品的儲存容量為1,則將該物品直接放進空的Slot if (item.Capacity == 1) { return StoreItemInEmptySlot (item); } // 將相同的Item放在同一個Slot return StoreItemInSameSlot(item); } private bool StoreItemInSameSlot(Item item){ foreach (Slot slot in slotList) { // 避開VendorSlot if (slot is VendorSlot) { continue; } if (slot.transform.childCount >= 1 && slot.GetItemID () == item.ID && slot.IsFilled () == false) { // 將新Item與同一個Item放在一起 slot.StoreItem (item); return true; } } // 若背包內不存在相同的Item,則放進空的Slot return StoreItemInEmptySlot (item); } private bool StoreItemInEmptySlot(Item item){ foreach (Slot slot in slotList) { // 避開VendorSlot if (slot is VendorSlot) { continue; } if (slot.transform.childCount == 0) { // 將Item存進該Slot slot.StoreItem (item); return true; } } Debug.LogError ("No Empty Slot."); return false; } public void ForgeItem(){ List materialsIDList = new List (); List forgeSlotList = new List (); // 取得Forge Slot內的Item foreach (Slot slot in slotList) { ForgeSlot forgeSlot = (slot as ForgeSlot); if (forgeSlot && slot.transform.childCount > 0) { ItemUI currentItemUI = slot.transform.GetComponentInChildren (); for (int i = 0; i < currentItemUI.Amount; i++) { materialsIDList.Add (currentItemUI.Item.ID); forgeSlotList.Add (forgeSlot); } } } // 檢查item組合是否匹配任一鍛造公式 foreach (ForgeFormula formula in forgeFormulaList.ForgeFormulaEntityList) { if (formula.MatchFormula (materialsIDList)) { // 符合公式,存入鍛造物品到背包內 StoreItem (formula.ResultID); // 消耗材料 ConsumeMaterials(formula, forgeSlotList); break; } } } private void ConsumeMaterials(ForgeFormula formula, List forgeSlotList){ List requireList = formula.GetRequireList(); foreach (int ID in requireList) { foreach (ForgeSlot forgeSlot in forgeSlotList) { if (forgeSlot.transform.childCount > 0 && forgeSlot.GetItemID() == ID) { ItemUI itemUI = forgeSlot.GetComponentInChildren (); itemUI.ReduceAmount (1); if (itemUI.Amount <= 0) { DestroyImmediate (itemUI.gameObject); } break; } } } } private void PressGToAddItem(){ // 測試程式碼,手動生成物品 if (Input.GetKeyDown (KeyCode.G)) { StoreItem (Random.Range(1,18)); } } private void InitialVendorItem(){ Item[] vendorItemList = new Item[10]; // 手動初始化要放入商店的物品 vendorItemList [0] = GetItemByID (1); vendorItemList [1] = GetItemByID (2); vendorItemList [2] = GetItemByID (3); vendorItemList [3] = GetItemByID (4); vendorItemList [4] = GetItemByID (5); vendorItemList [5] = GetItemByID (6); vendorItemList [6] = GetItemByID (7); vendorItemList [7] = GetItemByID (8); vendorItemList [8] = GetItemByID (1); vendorItemList [9] = GetItemByID (2); foreach (Item item in vendorItemList) { foreach (Slot slot in slotList) { // 限定Slot類型為VendorSlot VendorSlot vendorSlot = (slot as VendorSlot); // 如果同類型物品疊加在一起 if (vendorSlot && slot.transform.childCount >= 1 && slot.GetItemID () == item.ID && slot.IsFilled () == false) { slot.StoreItem (item); break; } // 如果沒有同類物品,則放入空Slot else if (vendorSlot && slot.transform.childCount == 0) { slot.StoreItem (item); break; } } } } private void MovePickedItemByMousePosition(){ if (isPickedItem) { // 將滑鼠座標轉換成Canvas上的座標 Vector2 position; Canvas canvas = GetComponentInParent
最後,記得在Forge Panel的Forge Btn中的Button事件設定,要將InventorySystem拉進去,並設定方法為ForgeItem唷!我的範例中,因為InventorySystem是放在Canvas內,所以如下圖會看見我拉進去的是Canvas。
來執行遊戲看看吧,我放入一個鍛造秘笈跟兩個鐵塊。
按下『開始』後,背包內出現了一把斧子,然後材料也被消耗掉了。
留言
張貼留言