我一直在尝试创建库存系统,但是遇到了问题。我有一个名为“ items”的列表,这是管理要添加到库存的项目的函数的代码。
我在此代码中遇到的错误是,每当我尝试将不存在的项目添加到库存时,它都能正常工作,但是每当我尝试再次在库存中添加相同的项目时,无论我写多少,它都会递增stackSize减1,不再添加。我也尝试过使用数组,但是它仍然无法正常工作,项目中还有其他奇怪的事情发生,但是我想首先解决这个问题。谢谢!
public void AddToInventory(Item _item, int amount = 1)
{
foreach(Item item in items)
{
if(item.Name == _item.Name)
{
item.stackSize += amount;
FlushList();
return;
}
}
Item item2 = new Item();
item2 = _item;
item2.stackSize = amount;
items.Add(item2);
}
这是我的测试方式:
private void Awake()
{
items = new List<Item>();
itemsInstantiated = new List<GameObject>();
AddToInventory(itemDb.GetItem("Material"));
AddToInventory(itemDb.GetItem("Material"));
AddToInventory(itemDb.GetItem("Material"));
AddToInventory(itemDb.GetItem("Material"));
// Stacksize of materials after this code is 2.
// Doesn't matter how many times i call the function above.
AddToInventory(itemDb.GetItem("Water Bottle(Full)"), 21);
AddToInventory(itemDb.GetItem("Apple"));
FlushList();
}
FlushList()方法:
public void FlushList()
{
// Visual stuff.
// There is a more efficent way but it's just a project to pass time so
// didn't bother.
foreach(GameObject go in itemsInstantiated)
{
Destroy(go);
}
foreach(Item item in items)
{
GameObject inst = Instantiate(ItemPrefab, ListView.transform);
itemsInstantiated.Add(inst);
inst.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = item.Name;
inst.transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = item.Description;
inst.transform.GetChild(2).GetComponent<TextMeshProUGUI>().text = item.stackSize.ToString();
if(item.isConsumeable)
{
inst.transform.GetChild(3).gameObject.SetActive(true);
inst.transform.GetChild(3).GetComponent<Button>().onClick.AddListener(() => { ConsumeItem(item); });
}
}
}
ConsumeItem()方法:
public void ConsumeItem(Item item)
{
item.consumeAction?.Invoke();
PlayerNeeds pn = GetComponent<PlayerNeeds>();
// Increase methods don't touch the list.
pn.IncreaseHunger(item.hungerIncrease);
pn.IncreaseThirst(item.thirstIncrease);
pn.IncreaseSleepiness(item.thirstIncrease);
RemoveItem(item);
}
物品数据库: 项目数据库是我存储所有项目的地方。那里的物品只有名称和描述。
public Item GetItem(string itemName, int amount = 1)
{
// Amount here is used by other functions such as crafting recipes.
// I feel like this is where the problem is.
foreach(Item item in AllItems)
{
if(item.Name == itemName)
{
Item newItem = item;
newItem.stackSize = amount;
return newItem;
}
}
print("Item: " + itemName + " could not be found!");
return null;
}
物品类别:
public class Item
{
public string Name;
public string Description;
public int categoryIndex = 1;
public bool isConsumeable;
public int stackSize = 1;
public int hungerIncrease;
public int thirstIncrease;
public int sleepIncrease;
public Action consumeAction;
}
_item
是项目数据库中的一个项目,它的堆栈大小始终为1,我要求输入“项目”,因为如果该项目不在播放器清单中,我会添加该项目。
一些例子:
* AddToInventory(item A, 3)
结果:我的库存中有3件商品A(效果很好)。
* AddToInventory(item A, 3)
AddToInventory(item A, 3)
结果:4项A。
** AddToInventory(item A, 45)
AddToInventory(item A, 57)
结果:46个项目A。
答案 0 :(得分:1)
问题出在GetItem
方法中,并且与使用引用有关。
在GetItem
方法中,您在AllItems
列表中创建了该项目的“副本”,但实际上,您只是在对同一对象进行新引用。然后,您为stackSize
分配一个值(在您的示例中,它始终是1
的默认值。
这里的事件顺序如下:
AllItems
列表中获得了该项目,并使用函数提供的值(或默认值为1)更新了stackSize
AllItems
列表中获得了相同的项目,然后再次将stackSize
更新为1。这里会出现问题。由于您将引用复制到同一对象,因此,当您将对象的堆栈大小从原来的值更改为1时,清单中的对象也会更新。这可以通过在GetItem
中删除更改stackSize
的行来解决,因为在您的示例中似乎没有使用它,或者您可以向{{ 1}}类,以将每个字段手动复制到新对象。
复制方法看起来像这样。
Item
会这样称呼:
public Item CopyItem()
{
var newItem = new Item();
newItem.Name = this.Name;
newItem.Description = this.Description;
newItem.categoryIndex = this.categoryIndex;
newItem.isConsumeable = this.isConsumeable;
newItem.stackSize = this.stackSize;
newItem.hungerIncrease = this.hungerIncrease;
newItem.thirstIncrease = this.thirstIncrease;
newItem.sleepIncrease = this.sleepIncrease;
newItem.consumeAction = this.consumeAction;
return newItem;
}
答案 1 :(得分:0)
首先,通过执行item2 = _item
,您正在擦除刚创建的一行新对象。然后,这样做的后果是列表中的项目不仅是原始项目的副本,而且是项目。如果在此函数中修改一个(通过增加堆栈大小),则将在使用它们的任何地方对其进行修改。也许这就是您想要的,也许不是。
您的函数实际上可以像这样重写,没有添加或删除任何功能:
public void AddToInventory(Item _item, int amount = 1)
{
if (!items.Contains(_item))
{
items.Add(_item);
_item.stackSize = amount;
}
else
{
_item.stackSize += amount;
FlushList(); //I don't know what this function is supposed to be doing.
}
}
如果这不是您的目标,也许您需要澄清您的问题。
也许您可以显示Item类,我们会更好地理解您的问题。