Ошибка, которую я не смог найти - PullRequest
0 голосов
/ 01 марта 2019

Я пытался создать систему инвентаризации, но у меня возникла проблема.У меня есть список с именем '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 предмета А в моем инвентаре (отлично работает).

*AddToInventory(item A, 3)
AddToInventory(item A, 3)
Результат:4 шт. А.

**AddToInventory(item A, 45)
AddToInventory(item A, 57)
Результат: 46 шт. А.

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Проблема заключается в методе GetItem и связана с работой со ссылками.

В методе GetItem создается «копия» элемента в списке AllItems,но на самом деле вы просто делаете новую ссылку на тот же объект.Затем вы присваиваете значение stackSize (в вашем примере это всегда значение по умолчанию 1.

Последовательность событий здесь следующая:

  1. Вы получаетепредмет из списка AllItems и обновите его stackSize значением, предоставленным функции (или по умолчанию 1)
  2. Вы добавляете этот предмет в инвентарь
  3. Вы получаете то же самоепредмет из списка AllItems и снова обновите stackSize до 1. Проблема возникает здесь. Поскольку вы копируете ссылку на тот же объект, объект в инвентаре также обновляется при изменении размера стекаобъект из того, что он есть, обратно к 1.
  4. Вы добавляете Предмет в свой инвентарь, но размер стека этого единственного объекта был просто сброшен до 1, поэтому размер увеличивается каждый раз до 2.

Эту проблему можно решить, либо убрав строку в GetItem, которая меняет stackSize, так как она не используется в вашем примере, либо вы можете добавить метод к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;
}

и будет вызываться так:

Item newItem = item.CopyItem();
0 голосов
/ 01 марта 2019

Прежде всего, выполнив 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, мы лучше разберемся в вашей проблеме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...