Jump to content
Pompeyo

Sistema de Inventario

Recommended Posts

Hola a todos, estoy desarrollando un sistema de inventario para un juego de supervivencia de mundo abierto, en el cual el jugador puede recoger varios items con diferentes usos del suelo, luego podrá usarlos o equipárselos en el caso de armas o ropas.

Mi duda es la siguiente: ¿Cual es la mejor manera para recoger los item?

Para mis pruebas he creado una clase denominada SpawnItem que instanciaba un item y detectaba si el jugador entraba a un trigger, y en ese caso se activaba la función de agregar el item al inventario y destruirlo de la escena, pero realmente no sé si esa es la forma correcta, creo que ese trabajo debería hacerse en el player.

 

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

public class SpawnItem : MonoBehaviour
{

    public ItemDataBlock GenericItem;
    public bool isItem = false;

    void Start()
    {
        Instantiate(GenericItem.prefab, transform.position, transform.rotation, transform);
    }

    //void Update()
    //{
    //    if (isItem)
    //    {
    //        RecogerObjeto();
    //    }
    //}

    //void OnTriggerStay(Collider Other)
    //{
    //    if (Other.gameObject.tag == "Player")
    //    {
    //        isItem = true;
    //    }
    //}

    //void OnTriggerExit(Collider Other)
    //{
    //    if (Other.gameObject.tag == "Player")
    //    {
    //        isItem = false;
    //    }

    //}

    private void RecogerObjeto()
    {
        //FindObjectOfType<InventoryControl>().AddItem(GenericItem);
        //Destroy(gameObject);
        if (Inventory.Instance.AddItem(GenericItem, 1))
        {
            Destroy(gameObject);
        }
    }

}

 

¿Que me recomiendan ustedes?

Aquiles muestro los script para que comprendan lo que hice y si es posible me den una recomendación.

Nota: Soy principiante así que, si ven algo que está mal, por favor díganmelo para corregirlo

El script Inventory esta asignado a un game object que contiene todos los slots del inventario:

 

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

public class Inventory : MonoBehaviour
{
    public bool isInventoryFull;
    public static Inventory Instance;
    private InventorySlot[] Slots;
    private List<ItemDataBlock> ItemList = new List<ItemDataBlock>();
    private int EmptySlot = 0;
    
    public Text WeightField;
    private double StoredWeight;
    public double MaxWeight = 40.00;//Peso maximo

    private void Awake()
    {
        Instance = this;
        Slots = GetComponentsInChildren<InventorySlot>();
    }

    public void NextEmptySlot()
    {
        EmptySlot = 0;
        foreach (InventorySlot Slot in Slots)
        {
            if (Slot.StoredItem)
            {
                EmptySlot++;
            }
            else
            {
                break;
            }
        }
        if (EmptySlot >= Slots.Length)
        {
            isInventoryFull = true;
        }
    }

    public bool AddItem(ItemDataBlock item, int Amount)
    {
        NextEmptySlot();
        //En un slot vacio
        if ((item.isStackable && !ItemList.Contains(item) && !isInventoryFull) || (!item.isStackable && !isInventoryFull))
        {
            InventorySlot SlotAdd = Slots[EmptySlot];
            ItemList.Add(item);
            SlotAdd.AddItem(item, Amount);
            SlotAdd.AmountText.text = SlotAdd.StoredAmount.ToString();
            CalculateWeight(item.Weight, Amount);
            Debug.Log("test A");
            return true;
        }
        //En un slot q contenga el mismo item
        else if (item.isStackable && ItemList.Contains(item))
        {
            for (int i = 0; i < Slots.Length; i++)
            {
                //Comprobar q el slot tenga el mismo item y que tenga < cantidad q stacksize
                if (item == Slots.StoredItem && Slots.StoredAmount < item.StackSize)
                {
                    Slots.StoredAmount += Amount;
                    Slots.AmountText.text = Slots.StoredAmount.ToString();
                    CalculateWeight(item.Weight, Amount);
                    Debug.Log("test B");
                    break;
                }
                //Comprobar q el slot tenga el mismo item y que tenga >= cantidad q stacksize
                else if (item == Slots.StoredItem && Slots.StoredAmount >= item.StackSize)
                {
                    InventorySlot SlotAdd = Slots[EmptySlot];
                    ItemList.Add(item);
                    SlotAdd.AddItem(item, Amount);
                    SlotAdd.AmountText.text = SlotAdd.StoredAmount.ToString();
                    CalculateWeight(item.Weight, Amount);
                    Debug.Log("test C");
                    break;
                }
            }
            return true;
        }
        //Aqui se supone que el inventario esta lleno
        else
        {
            Debug.Log("test D");
            return false;
        }
    }

    public void RemoveItem(ItemDataBlock item)
    {
        ItemList.Remove(item);
        //restar el peso del item
        CalculateWeight(item.Weight, -1);
    }


    private void CalculateWeight(double Weight, int Amount)
    {
        StoredWeight += Weight * Amount;
        WeightField.text = StoredWeight.ToString();
    }
}


InventorySlot está asignado a cada slot del inventario:

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

public class InventorySlot : MonoBehaviour, IPointerDownHandler
{
    public ItemDataBlock StoredItem;
    public int StoredAmount;
    private Image Icon;
    public Text AmountText;

    private void Awake()
    {
        Icon = GetComponent<Image>();
    }

    void Start()
    {
        if (StoredItem == null)
        {
            Icon.enabled = false;
        }
    }

    public void AddItem(ItemDataBlock item, int Amount)
    {
        StoredItem = item;
        Icon.enabled = true;
        Icon.sprite = item.icon;
        StoredAmount = Amount;
    }

    public virtual void RemoveItem()
    {
        Inventory.Instance.RemoveItem(StoredItem);
        RestetSlotInventory();
    }

    protected void RestetSlotInventory()
    {
        Icon.sprite = null;
        StoredAmount = 0;
        Icon.enabled = false;
        StoredItem = null;
    }

    protected virtual void InventoryItemUse()
    {
        if (StoredItem)
        {
            if (StoredItem.ItemUse())
            {
                ReducedStored(1);
            }
        }
    }

    public void ReducedStored(int Amount)
    {
        StoredAmount -= Amount;
        if (StoredAmount <= 0)
        {
            RemoveItem();
        }
    }
    //Crear menu contextual
    public void OnPointerDown(PointerEventData eventData)
    {
        InventoryItemUse();
    }
}

 

NOTA: Esto fue hecho siguiendo un tutorial de youtube

Saludos y de antemano gracias por su atencion!!!

Edited by Pompeyo

Share this post


Link to post
Share on other sites

Primero: no uses // para cada linea, si quieres comentar un un metodo u otro texto largo, usa /* .... */.

Segundo: En respuesta a tu pregunta. Deberías manejar el inventario y pickup objects desde el jugador, porque si vas a implementarlos en cada objeto 'Item', que pasará cuando quieras instanciar 1K items en la escena?, Tendrás 1K scripts ejecutando funciones de eventos en cada frame innecesariamente?.

Usa un único sistema que manejé los eventos de colisión, entonces, cuando tu jugador este cerca a un objeto, se active un método que verifique si hay o no, espacio en el inventario. Y cuándo digo "UN" es solo uno, en tu primer script hay un método (RecogerObjeto ()) que se activa cuando se cumple un if, Fatal!

Que pasa si ese if nunca cambia de estado? Seguirías llamando el método una, otra y otra vez, usando innecesariamente la CPU.

 En su caso, usa los eventos de colisión para preguntar una vez si hay espacio en el inventario. Si la respuesta es falso, evita hacer una nueva llamada a la función, entonces cuando el usuario elimine un item de su inventario, lanza otra función que diga algo como "Inventario actualizado, realiza una llamada a los triggers a ver si hay items para recoger", esto sería un optimización drástica al la manera en que está planteada tu actual idea.

  • Like 2

Share this post


Link to post
Share on other sites

Si realmente ese primer script que contiene esa funcion, solo fue un comienzo para las pruebas, no pensaba dejarlo asi, muchas gracias por tu concejo amigo, lo manejare desde el jugador, estaba casi seguro que debia ser de esa manera
 

Share this post


Link to post
Share on other sites

×
×
  • Create New...