【问题标题】:Unity inventory System stack systemunity 库存系统 堆栈系统
【发布时间】:2017-11-14 15:52:15
【问题描述】:

我使用 C# 在 Unity 中创建了一个库存系统。我目前在我的库存中有一个简单的堆栈系统,如果一个项目大于堆栈,它会停止将其添加到当前的库存槽。但我想知道如何设置它,以便在另一个插槽已满时将同一项目的实例添加到另一个插槽?

这是我的代码,如果你们需要我分享更多课程,请告诉我,任何帮助将不胜感激。

/**
 * Controller class used to handle the logic and functionality of the 
inventory system
 **/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventoryController : MonoBehaviour
{

Inventory inv;
ItemDatabase database;
public int maxSize = 3;

private void Awake()
{
    database = GetComponent<ItemDatabase>();
    inv = GetComponent<Inventory>();

    inv.slotAmount = 25;
    inv.background = GameObject.Find("SlotBackgroundPanel");
    inv.slotPanel = inv.background.transform.Find("SlotPanel").gameObject;
    for (int i = 0; i < inv.slotAmount; i++)
    {
        inv.items.Add(new InventoryModel());
        inv.slots.Add(Instantiate(inv.inventorySlot));
        inv.slots[i].GetComponent<ItemSlot>().id = i;
        inv.slots[i].transform.SetParent(inv.slotPanel.transform);
    }
}

public void AddItem(int id)
{
    InventoryModel itemToAdd = database.FetchItemByID(id);
    if (itemToAdd.Stackable && CheckItemInInventory(itemToAdd))
    {
        for (int i = 0; i < inv.items.Count; i++)
        {
            if (inv.items[i].ID == id)
            {

                ItemData data = inv.slots[i].transform.GetChild(0).GetComponent<ItemData>();
                data.amount++;
                data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
                break;
            }
        }
    }

    else
    {
        for (int i = 0; i < inv.items.Count; i++)
        {
            if (inv.items[i].ID == -1)
            {
                inv.items[i] = itemToAdd;
                GameObject itemObj = Instantiate(inv.inventoryItem);
                itemObj.GetComponent<ItemData>().inventoryModel = itemToAdd;
                itemObj.GetComponent<ItemData>().amount = 1;
                itemObj.GetComponent<ItemData>().slot = i;
                itemObj.transform.SetParent(inv.slots[i].transform);
                itemObj.transform.position = Vector2.zero;
                itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
                itemObj.name = itemToAdd.Title;
                break;
            }
        }
    }
}

public void RemoveItem(int id)
{
    InventoryModel itemToRemove = database.FetchItemByID(id);
    if (itemToRemove.Stackable && CheckItemInInventory(itemToRemove))
    {

        for (int j = 0; j < inv.items.Count; j++)
        {
            if (inv.items[j].ID == id)
            {
                ItemData data = inv.slots[j].transform.GetChild(0).GetComponent<ItemData>();
                data.amount--;
                data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
                if (data.amount == 0)
                {
                    Destroy(inv.slots[j].transform.GetChild(0).gameObject);
                    inv.items[j] = new InventoryModel();
                    break;
                }
                if (data.amount == 1)
                {
                    inv.slots[j].transform.GetChild(0).transform.GetChild(0).GetComponent<Text>().text = "";
                    break;
                }
                break;
            }
        }
    }
    else
    {
        for (int i = 0; i < inv.items.Count; i++)
        {
            if (inv.items[i].Title == null && inv.items[i].ID == id)
            {
                Destroy(inv.slots[i].transform.GetChild(0).gameObject); inv.items[i] = new InventoryModel();
                break;
            }
        }

    }
}

public void FullItem(int id)
{
    InventoryModel itemIsFull = database.FetchItemByID(id);
    if (itemIsFull.Stackable && CheckItemInInventory(itemIsFull))
    {
        for (int y = 0; y < inv.items.Count; y++)
        {
            if (inv.items[y].ID == id)
            {
                ItemData data = inv.slots[y].transform.GetChild(0).GetComponent<ItemData>();
                data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();

                if (data.amount >= maxSize)
                {
                    inv.slots[y].transform.GetChild(0).transform.GetChild(0).GetComponent<Text>().text = "3";
                    data.amount = 3;
                    Debug.Log(data.amount);
                    break;
                }
            }
        }
    }
}

public bool CheckItemInInventory(InventoryModel inventoryModel)
{
    for (int i = 0; i < inv.items.Count; i++)
        if (inv.items[i].Title == inventoryModel.Title)
            return true;
    return false;
}
}

用于视图的类

using System.Collections;
/**
 * View class, used to handle the User Interface
 **/

using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class Inventory : MonoBehaviour
{

public GameObject background;
public GameObject slotPanel;
InventoryController inventoryController;
public GameObject inventorySlot;
public GameObject inventoryItem;
public int slotAmount;

public enum type { diamond = 0, iron = 1, gold = 2, fuel = 3 };

public List<InventoryModel> items = new List<InventoryModel>();
public List<GameObject> slots = new List<GameObject>();

private void Start()
{

    inventoryController = GetComponent<InventoryController>();

    inventoryController.AddItem((int)type.diamond);
    inventoryController.AddItem((int)type.diamond);
    inventoryController.AddItem((int)type.diamond);
    inventoryController.AddItem((int)type.diamond);

    inventoryController.AddItem((int)type.gold);
    inventoryController.AddItem((int)type.fuel);

   inventoryController.FullItem((int)type.diamond);
}
}

用于模型的类

    /**
 * Model class used to handle and store variables
 **/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryModel
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool Stackable { get; set; }
public string Slug { get; set; }
public Sprite Sprite { get; set; }

public InventoryModel(int id, string title, string description,
    bool stackable, string slug)
{
    this.ID = id;
    this.Title = title;
    this.Description = description;
    this.Stackable = stackable;
    this.Slug = slug;

    this.Sprite = Resources.Load<Sprite>("Sprites/Items/" + slug);
}

public InventoryModel()
{
    this.ID = -1;
}
}

Json 文件

[
{
"id" : 0,
"title" : "Diamond",
"value" : 5,
"stats":{
    "defence": 9,
    "power" : 8,
    "weight" : 5
    },
"description": "Mined Diamond is stronger than metal",
"stackable" : true,
"rarity" : 10,
"slug": "Diamond"
},

{
"id" : 1,
"title" : "Iron",
"value" : 2,
"stats":{
    "defence" : 5,
    "power" : 6,
    "weight" : 7
},
"description" : "Mined Iron is stronger than bronze",
"stackable" : false,
"rarity" : 6,
"slug" : "Metal"
},

{
"id" : 2,
"title" : "Gold",
"value" : 2,
"stats":{
    "defence" : 0,
    "power" : 0,
    "weight" : 0
},
"description" : "Gold is valuable",
"stackable" : false,
"rarity" : 10,
"slug" : "Gold"
},

{
"id" : 3,
"title" : "Fuel2",
"value" : 2,
"stats":{
    "defence" : 0,
    "power" : 0,
    "weight" : 0
    },
"description" : "Fuel is needed for ship engines",
"stackable" : true,
"rarity" : 2,
"slug" : "Fuel2"
}


]

【问题讨论】:

  • 你不能在你的库存模型中有一个可变数量并检查你在哪里做if (inv.items[i].ID == id &amp;&amp; inv.items[i].amount &lt;= maxAmount)。因此,您将检查此库存模型是否已满。

标签: c# json unity3d stack inventory


【解决方案1】:

啊,我在制作库存系统时记得这个问题。我做了一个类似于 Minecraft 的,基于插槽的,拖放......等等。任何丢失源代码的人哇。
我真的很无聊,所以我决定复制你的代码并添加一个函数来检查项目的数量是否小于最大堆栈大小。看看:

InventoryModel itemToAdd = database.FetchItemByID(id);

    // First check if the item is in the inventory
    // This check can be discarded. See below...
    // You might be able to use this check in some form of anti-cheat system, so I've left it there.

    if (CheckItemInInventory(itemToAdd))
    {
        // Iterate through the inventory and check items against their ID/Name
        for (int i = 0; i < inv.items.Count; i++)
        {
            // If the item in the slot has the same ID as the item we want to add...

            if (inv.items[i].ID == id)
            {
                // Check if the item is actually stackable and the slot is not full
                // I.E the stack size (amount) is less than the max stack size.

                // You'll need to add a new variable to your InventoryModel class
                // int maxStackSize

                if (inv.items[i].amount < inv.items[i].maxStackSize && itemToAdd.Stackable)
                {
                    ItemData data = inv.slots[i].transform.GetChild(0).GetComponent<ItemData>();
                    data.amount++;
                    data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
                    break;
                }
                // If not, then we skip adding a new item because this slot is already occupied and it's stack size is full
            }
            else if (inv.items[i].id == -1)
            {
                // If we encounter an empty slot, add a new item.
                inv.items[i] = itemToAdd;
                GameObject itemObj = Instantiate(inv.inventoryItem);
                itemObj.GetComponent<ItemData>().inventoryModel = itemToAdd;
                itemObj.GetComponent<ItemData>().amount = 1;
                itemObj.GetComponent<ItemData>().slot = i;
                itemObj.transform.SetParent(inv.slots[i].transform);
                itemObj.transform.position = Vector2.zero;
                itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
                itemObj.name = itemToAdd.Title;
            }
        }
        // If the code's execution reaches this point, then we are essentially skipping action on the slot.
        // This means that we were not able to find an item that matched the ID OR the stack size was full...
        // So we keep scanning the other slots next in line...
    }
    else
    {
        // do something if the player tried to add an item but it does not exist in their inventory
        // or something doesn't quite add up... Good for anti-cheat systems.
    }

如您所见,我对您的代码进行了一些调整和优化,包括删除了一些冗余检查。你检查了玩家的物品栏两次。一次验证他们是否有该项目,然后再次将该项目添加到库存中。您可以一口气完成这两项操作。
我还应该提到我在visual studio中编写了代码,所以它应该适合复​​制粘贴。享受吧!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-27
    • 2014-07-21
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    相关资源
    最近更新 更多