Přidání předmětu do inventáře postavy. Log #18 (Unity, C#)
01.06.2018

    V minulém díle jsem předmět, po kliknutí na něj, jen zničil (odebral ze scény). V tomhle díle předmět přidám do inventáře. Postava hráče bude mít vlastní kontejner pro předměty inventáře tzv. inventory holder. Bude to třída dědící ze třídy Inventory, která bude implementovat základní manipulace s inventářem, jako přidání předmětu a odebrání, případně hromadné přídávání předmětů nebo celých stacků. Třída Inventory bude předměty držet v generickém listě, z ní pak budou dědit inventáře například obchodníků nebo truhly a skladiště. Inventory holder pak jen implementuje singelton pro inventář hráče.

 

   Fyzické modely ve scéně po přidání do inventáře mizí, ale v paměti je potřeba stále uchovávat původní data o předmětu a jejich stav, jako například jestli ji postava používá, v jaké ruce ji má, nebo jestli se jedná o zbraň, vytvořím proto kontejner tzv. item holder, uchovávající tyto informace. Třída ItemHolder bude samostatná (nebude dědit od nikoho), bude obsahovat proměnnou Item itemData pro ScriptableObject předmětu a taky další zmíněné informace jako bool isEquipped aj.. Tahle třída mi bude reprezentovat předměty ve hře a budou s ní manipulovat inventáře a interakce. Od ScriptableObjectu tuto třídu úmyslně odděluji, aby se nadbytečné informace neobjevovali v inspektoru při vytváření předmětů a taky protože tyto informace se mění v průběhu hry.

 

using UnityEngine;

[System.Serializable]
public class ItemHolder
{
    public Item itemData { get; private set; }

    public ItemHolder(Item itemData)
    {
        this.itemData = itemData;
    }
}

 

    Základní chování třídy Inventory definují funce AddItem(ItemHolder), RemoveItem(ItemHolder) a další hromadné funkce jako AddAll(List<ItemHolder>) a RemoveAll(List<ItemHolder>). Tyhle funkce jednoduše upravují list předmětů.

 

using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    protected List<ItemHolder> itemList;

    public void AddItem(ItemHolder item)
    {
        itemList.Add(item);
    }

    public void AddAll(List<ItemHolder> items)
    {
        foreach (ItemHolder _itemHolder in items)
        {
            AddItem(_itemHolder);
        }
    }

    public void RemoveAllItems()
    {
        itemList.Clear();
    }

    public void RemoveAll(List<ItemHolder> items)
    {
        foreach (ItemHolder _itemHolder in itemList)
        {
            foreach (ItemHolder _itemInList in items)
                if (_itemInList.itemData == _itemHolder.itemData)
                {
                    RemoveItem(_itemHolder);
                }
        }
    }

    public void RemoveItem(ItemHolder item)
    {
        itemList.Remove(item);
    }

    public List<ItemHolder> GetItemList()
    {
        return itemList;
    }
}

 

    Pro zmíněný inventory holder vytvořím script PlayerInventoryHolder, dědící z Inventory, v něm z třídy udělám singeltona a incializuji list z nadřazené třídy.

 

using System.Collections.Generic;

public class PlayerInventoryHolder : Inventory
{
    public static PlayerInventoryHolder Instance { get; private set; }

    void Awake()
    {
        //Singelton
        if (Instance == null)
            Instance = this;
        else if (Instance != this)
            Destroy(gameObject);
        DontDestroyOnLoad(gameObject);

        itemList = new List<ItemHolder>();
    }
}

 

    Každý fyzický předmět ve scéně si bude držet data o předmětu v proměnné ItemHolder item v komponentě ItemInteraction, po přidání do inventáře se ItemHolder item, uchovávající informace o předmětu, předá do listu v inventory holder. Tímhle se zajistí i předání správných informací při odebírání z inventáře a to tak, že při vytváření fyzického předmětu se do proměnné ItemHolder item daného předmětu jen předá aktuální předmět (opět komponenta ItemInteraction). Protože každý předmět, se kterým lze interagovat, implementuje funkci Interact(), stačí akci po kliknutí definovat chování uvnitř této metody. V mém případě je to přidání předmětu do inventáře.

 

using UnityEngine;

public class ItemInteraction : Interactable
{
    [Header("Item Interactable")]
    public Item itemData;

    public ItemHolder itemHolder { get; private set; }

    protected new void Awake()
    {
        base.Awake();
        itemHolder = new ItemHolder(itemData);
    }

    public void SetItemHolder(ItemHolder itemHolder)
    {
        this.itemHolder = itemHolder;
    }

    protected override void Interact()
    {
        PlayerInventoryHolder.Instance.AddItem(itemHolder);
        Destroy(gameObject);
    }
}

 

    Komponentu PlayerInventoryHolder přetáhnu na objekt Player ve scéně, reprezentující postavu hráče. Tím je přidání předmětu do inventáře hotové. V následujícím díle budu předmět v inventáři zobrazovat.