Список объектов, система инвентаризации, проблема с укладкой - PullRequest
0 голосов
/ 12 марта 2020

Я создаю простую RPG 3D-игру в единстве. Я довольно новичок в кодировании. Я создал класс ScriptableObject с именем Item, чтобы я мог просто создать новый элемент и передать его свойства из Inspector. Затем я создал список для хранения предметов в инвентаре персонажей. Мне удалось создать код, который добавляет объект в список, как только он будет выбран. Следующим шагом был пользовательский интерфейс инвентаря - я создал 60 кнопок, которые напоминают слоты в инвентаре, и всплывающее меню, которое появляется после нажатия на них. Меню содержит две кнопки - «Использовать» и «Удалить». Я создаю кнопки «Слушатели для использования» и «Удалить» после открытия меню и при нажатии любого из них я вызываю метод Использовать или Удалить. Я храню информацию о выбранном слоте инвентаря в объекте класса Item.

Теперь проблема в том, что всякий раз, когда я нажимаю несколько раз на разные предметы в инвентаре, хотя я постоянно пытаюсь сбросить выбранный объект до нуля, каким-то образом информация о выбранных предметах складывается. Как только я нажму «Использовать» или «Удалить» - это затронет каждый элемент, на который я нажал.

Консоль Unity показывает мне (через Debug.Log), что я ввел метод с одним набором объектов, но когда метод идет дальше - это делается несколько раз для каждого элемента, щелкнувшего ранее. Я запутался.

Код для объекта ScriptableObject

using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{

new public string name = "New Item";
public Sprite icon = null;
public Image itemImage;
public bool isDefaultItem = false;
[TextArea(3, 10)]
public string ItemInfo;
public GameObject Prefab;
public Animator chestObtain;

public virtual void Use()
{
    // Use the item

    Debug.Log("Using " + name);
}


}

Код для инвентаризации (хранения предметов)

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

public class Inventory : MonoBehaviour
{

public int space = 30;

#region Singleton

public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;

public static Inventory instance;

private void Awake()
{
    if (instance != null)
    {
        Debug.LogWarning("More than one instance of Inventory found!");
        instance = this;
    }
}

#endregion

public List<Item> items = new List<Item>();

public bool Add (Item item)
{
    if (!item.isDefaultItem)
    {
        if (items.Count >= space)
        {
            Debug.Log("Not enough space");
            return false;
        }
        items.Add(item);
        if (onItemChangedCallback != null)
        {
            onItemChangedCallback.Invoke();
        }
    }

    return true;

}

public void Remove(Item item)
{
    Debug.Log("Removing " + item);
    items.Remove(item);
    if (onItemChangedCallback != null)
    {
        onItemChangedCallback.Invoke();
    }
}

public void RemoveAt(int i)
{
    if (i <= items.Count)
    {
        Debug.Log("Removing " + items[i]);
        Debug.Log("List: " + items);
        //items.RemoveAt(i);
        if (onItemChangedCallback != null)
        {
            onItemChangedCallback.Invoke();
        }
    }
}

}

Код для методов инвентаризации

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

public class InventoryItemInfo : MonoBehaviour
{
public GameObject ItemInfoTab;
public bool ItemInfoTabIsOpen = false;
public Button OpenTab;
public Text Title;
public Text UseButtonText;
public Text RemoveButtonText;
public Text ItemInfo;
public int SlotID;
public Image ItemImage;
public Item test;
public Button RemoveButton;
public Button UseButton;

Inventory inventory;

void Update()
{
    if (Input.GetKeyDown(KeyCode.Tab))
    {
        ItemInfoTabIsOpen = false;
    }
}

public void OpenTabPressed()
{
    Debug.Log("test object after opening a tab: " + test);
    test = null;
    Debug.Log("test object after opening a tab and reseting: " + test);
    UseButton.onClick.RemoveListener(OnUseButton);
    RemoveButton.onClick.RemoveListener(OnRemoveButton);

    if (ItemInfoTab.activeInHierarchy)
    {
        ItemInfoTabIsOpen = false;
    }
    int itemsCount = GameObject.Find("GameManager").GetComponent<Inventory>().items.Count;
    if (test == null)
    {
        if (itemsCount > SlotID)
        {

            if (ItemInfoTabIsOpen == false)
            {
                ItemInfoTab.SetActive(true);
                ItemInfoTabIsOpen = true;
            }
            test = GameObject.Find("GameManager").GetComponent<Inventory>().items[SlotID];
            UseButton.onClick.AddListener(OnUseButton);
            RemoveButton.onClick.AddListener(OnRemoveButton);
            Debug.Log("SlotID: " + SlotID);
            Debug.Log("Clicked item: " + test);
            Title.text = test.name;
            ItemInfo.text = test.ItemInfo;
            ItemImage.sprite = test.icon;
        }
        else
        {
            Debug.Log("Emtpy inventory slot");
        }
    }
    else
    {
        test = null;
        Debug.Log("Test object set to null");
    }
}

public void OnUseButton()
{
    Debug.Log("test object to use: " + test);
        test.Use();
        test = null;
    Debug.Log("test object after using: " + test);
}

public void OnRemoveButton()
{
    ItemInfoTab.SetActive(false);
    ItemInfoTabIsOpen = false;
    Debug.Log("test object to remove: " + test);
    FindObjectOfType<Inventory>().Remove(test);
    test = null;
}
}

Последнее примечание - я поставил все эти "test = null"; , чтобы попытаться преодолеть проблему, но она не сработала .


Редактировать

Я только что заметил в инспекторе, что как только я нажимаю на предмет, и он назначается слоту в инвентаре - он становится пустым только после вызов метода Use или Remove - никогда в любых других условиях (и это следует делать после нажатия на другой элемент).

Снимок экрана для пустого слота https://prnt.sc/rezehc Снимок экрана для занятого слота Screenshot2

Идея - значит ли это, что я только сбрасываю «переменную объекта» в скрипте, а не в слоте фактического предмета? Если да - как вернуть его в ноль? У меня более 60 слотов с предметами, которые выглядят так -> Иерархия Каждая кнопка действия содержит один и тот же скрипт (смотрите предыдущие скриншоты).


1 Ответ

3 голосов
/ 12 марта 2020

Когда вы вызываете RemoveListener, вы должны вызывать ссылку на метод экземпляра, с которым он был вызван ранее. По сути, вам нужно получить ссылку на предыдущий InventoryItemInfo, а затем позвонить:

UseButton.onClick.RemoveListener(previousInventoryItemInfo.OnUseButton);
RemoveButton.onClick.RemoveListener(previousInventoryItemInfo.OnRemoveButton);

Что ж, у вас, кажется, нет ссылки на это, легко доступной. Я бы рекомендовал просто использовать RemoveAllListeners:

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

public class InventoryItemInfo : MonoBehaviour
    {
    public GameObject ItemInfoTab;
    public bool ItemInfoTabIsOpen = false;
    public Button OpenTab;
    public Text Title;
    public Text UseButtonText;
    public Text RemoveButtonText;
    public Text ItemInfo;
    public int SlotID;
    public Image ItemImage;
    public Item test;
    public Button RemoveButton;
    public Button UseButton;

    Inventory inventory;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            ItemInfoTabIsOpen = false;
        }
    }

    public void OpenTabPressed()
    {
        Debug.Log("test object after opening a tab: " + test);
        test = null;
        Debug.Log("test object after opening a tab and reseting: " + test);
        UseButton.onClick.RemoveAllListeners();
        RemoveButton.onClick.RemoveAllListeners();

        if (ItemInfoTab.activeInHierarchy)
        {
            ItemInfoTabIsOpen = false;
        }
        int itemsCount = GameObject.Find("GameManager").GetComponent<Inventory>().items.Count;
        if (test == null)
        {
            if (itemsCount > SlotID)
            {

                if (ItemInfoTabIsOpen == false)
                {
                    ItemInfoTab.SetActive(true);
                    ItemInfoTabIsOpen = true;
                }
                test = GameObject.Find("GameManager").GetComponent<Inventory>().items[SlotID];
                UseButton.onClick.AddListener(OnUseButton);
                RemoveButton.onClick.AddListener(OnRemoveButton);
                Debug.Log("SlotID: " + SlotID);
                Debug.Log("Clicked item: " + test);
                Title.text = test.name;
                ItemInfo.text = test.ItemInfo;
                ItemImage.sprite = test.icon;
            }
            else
            {
                Debug.Log("Emtpy inventory slot");
            }
        }
        else
        {
            test = null;
            Debug.Log("Test object set to null");
        }
    }

    public void OnUseButton()
    {
        Debug.Log("test object to use: " + test);
            test.Use();
            test = null;
        Debug.Log("test object after using: " + test);
    }

    public void OnRemoveButton()
    {
        ItemInfoTab.SetActive(false);
        ItemInfoTabIsOpen = false;
        Debug.Log("test object to remove: " + test);
        FindObjectOfType<Inventory>().Remove(test);
        test = null;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...