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 List ForgeFormulaEntityList;
}
[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。
來執行遊戲看看吧,我放入一個鍛造秘笈跟兩個鐵塊。
按下『開始』後,背包內出現了一把斧子,然後材料也被消耗掉了。

















留言
張貼留言