The focus of the Ultimate Character Controller is to be an exceptional character controller so the inventory system is less focused on features and more focused on being flexible. With that said, in order to have a functioning item system the inventory system does need to be able to support the basics such as keeping an ammo count or determining if the character has a weapon.

The inventory uses Item Definitions to identify a particular item. Item Definitions are also used for consumables such as assault rifle bullets or amount of battery left. The built-in inventory class uses a concept of Item Types, which are a subclass of Item Definitions. You’ll also see Item Identifiers within the asset and these are a reference to the specific item instance. This distinction is made to allow for easier integration with our inventory solution asset. Item Types are used within the character controller and are both Item Definitions and Item Identifiers.Item Types can be created within the Item Type Manager.

Pickup Script

The script below will add a new ItemType to the inventory:

using UnityEngine;
using Opsive.UltimateCharacterController.Inventory;

/// <summary>
/// Picks up the specified ItemType within the Start method.
/// </summary>
public class Pickup : MonoBehaviour
{
    [Tooltip("The character that should pickup the item.")]
    [SerializeField] protected GameObject m_Character;
    [Tooltip("The ItemType that the character should pickup.")]
    [SerializeField] protected ItemType m_ItemType;
    [Tooltip("The number of ItemType that the character should pickup.")]
    [SerializeField] protected int m_Amount= 1;

    /// <summary>
    /// Picks up the ItemType.
    /// </summary>
    public void Start()
    {
        var inventory = m_Character.GetComponent<InventoryBase>();
        if (inventory == null) {
            return;
        }

        // Adds the specified amount of the ItemType to the inventory.
        // m_ItemType: The ItemType to pick up.
        // m_Amount: The amount of ItemType to pick up.
        // -1: The slot ID that picked up the item. A -1 value will indicate no specified slot.
        // true: Should the item be picked up immediately? If false the EquipUnequip ability may not switch to the newly picked up item.
        // false: Should the item be force equipped?
        inventory.Pickup(m_ItemType, m_Amount, -1, true, false);
    }
}

Equip ItemSet Script

The script below will equip a specific ItemSet from the ItemSetManager. The item must first be picked up before it can be equipped.

using UnityEngine;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Abilities.Items;

/// <summary>
/// Equips the specified ItemSet within the Start method.
/// </summary>
public class Equip : MonoBehaviour
{
    [Tooltip("The character that should drop the item.")]
    [SerializeField] protected GameObject m_Character;
    [Tooltip("The index of the category that the ItemSet belongs to.")]
    [SerializeField] protected int m_CategoryIndex;
    [Tooltip("The index of the ItemSet that should be equipped.")]
    [SerializeField] protected int m_ItemSetIndex;

    /// <summary>
    /// Equips the ItemSet.
    /// </summary>
    public void Start()
    {
        var characterLocomotion = m_Character.GetComponent<UltimateCharacterLocomotion>();
        var equipUnequipAbilities = characterLocomotion.GetAbilities<EquipUnequip>();
        for (int i = 0; i < equipUnequipAbilities.Length; ++i) {
            if (equipUnequipAbilities[i].ItemSetCategoryIndex == m_CategoryIndex) {
                // Starts equipping to the specified ItemSet.
                // ItemSetIndex: The ItemSet to equip/unequip the items to.
                // ForceEquipUnequip: Should the ability be force started? This will stop all abilities that would prevent EquipUnequip from starting.
                // ImmediateEquipUnequip: Should the items be equipped or unequipped immediately?
                equipUnequipAbilities[i].StartEquipUnequip(m_ItemSetIndex, true, false);
                return;
            }
        }
    }
}

Drop Script

The script below will drop an ItemType from the inventory:

using UnityEngine;
using Opsive.UltimateCharacterController.Inventory;

/// <summary>
/// Drops the specified ItemType within the Start method.
/// </summary>
public class Drop: MonoBehaviour
{
    [Tooltip("The character that should drop the item.")]
    [SerializeField] protected GameObject m_Character;
    [Tooltip("The ItemType that the character should drop.")]
    [SerializeField] protected ItemType m_ItemType;

    /// <summary>
    /// Drops the ItemType.
    /// </summary>
    public void Start()
    {
        var inventory = m_Character.GetComponent<InventoryBase>();
        if (inventory == null) {
            return;
        }

        // A single ItemType can exist in multiple slots. Drop all of the items.
        for (int i = 0; i < inventory.SlotCount; ++i) {
            var item = inventory.GetItem(i, m_ItemType);
            if (item != null) {
                // Removes the item from the inventory. The last parameter drops the item.
                // ItemType: The ItemType to remove.
                // SlotID: The ID of the slot.
                // amount: The amount of the ItemIdentnfier that should be removed.
                // Drop: Should the item be dropped when removed?
                inventory.RemoveItem(m_ItemType, i, 1, true); 
            }
        }
    }
}

Item Amounts

The total amount of ammo the active item has can be determined with the following script:

using UnityEngine;
using Opsive.UltimateCharacterController.Inventory;
using Opsive.UltimateCharacterController.Items.Actions;

/// <summary>
/// Outputs the amount of ammo the active item has.
/// </summary>
public class OutputItemAmount : MonoBehaviour
{
    [Tooltip("The character that contains the inventory.")]
    [SerializeField] protected GameObject m_Character;

    /// <summary>
    /// Outputs the item amount.
    /// </summary>
    public void Start()
    {
        var inventory = m_Character.GetComponent<InventoryBase>();
        if (inventory == null) {
            return;
        }

        for (int i = 0; i < inventory.SlotCount; ++i) {
            var item = inventory.GetActiveItem(i);
            if (item != null) {
                Debug.Log("Inventory Amount: " + inventory.GetItemIdentifierAmount(item.ItemIdentifier));
                // A single item can have multiple Item Actions.
                var itemActions = item.ItemActions;
                for (int j = 0; j < itemActions.Length; ++j) {
                    var usableItem = itemActions[j] as IUsableItem;
                    if (usableItem != null) {
                        var consumableItemIdentifier = usableItem.GetConsumableItemIdentifier();
                        if (consumableItemIdentifier != null) {
                            // The loaded amount is retrived from the UsableItem and hte unloaded amount is retrieved from the inventory. 
                            Debug.Log("Consuambe Loaded Amount: " + usableItem.GetConsumableItemIdentifierAmount());
                            Debug.Log("Consuambe Inventory Amount: " + inventory.GetItemIdentifierAmount(consumableItemIdentifier));
                        }
                    }
                }
            }
        }
    }
}

Inspected Fields

Current Inventory

The Current Inventory foldout will list every item that is currently in the inventory. This list will only be populated when the game is running. This list is purely for informational purposes as the list cannot be edited.

Default Loadout

The character will spawn with any items specified within the Default Loadout. New ItemTypes can be added and removed by selecting the plus or minus icon on the bottom right of the list.

Remove All on Death

Should all of the items be removed when the character dies?

Load Default Loadout on Respawn

Should the inventory load the Default Loadout after the character has respawned?

API

Most for the operations performed directly on the inventory will be to react to an event sent by the inventory rather than performing an operation on the inventory. The inventory exposes many events using the built in Event System:

// Called when the item is initially added to the inventory (ex. an assault rifle has been added to the character at edit time).
OnInventoryAddItem(Item item)

// Called when an ItemIdentifier is picked up (ex. the character finds an assault rifle on the ground and picks it up).
OnInventoryPickupItemIdentifier(IItemIdentifier itemIdentifier, int amount, bool immediatePickup, bool forceEquip) 

// Called when an Item is picked up. This event is similar to OnInventoryPickupItemIdentifier except it is only called for ItemIdentifiers that have an item attached to them.
OnInventoryPickupItem(Item item, int count, bool immediatePickup, bool forceEquip)

// Called when the item is equipped (ex. the event is called for the assault rifle when switching from a knife to an assault rifle).
OnInventoryEquipItem(Item item, int slotID)

// Called when the ItemIdentifier amount is changed (ex. the event is called when an assault rifle being fired).
OnInventoryAdjustItemIdentifierAmount(IItemIdentifier itemIdentifier, int remaining)

// Called when the item is unequipped (ex. the event is called on the assault rifle when switching from an assault rifle to a knife).
OnInventoryUnequipItem(Item item, int slotID)

// Called when the item is removed from the inventory (ex. the event is called when the character dies and drops all of their items).
OnInventoryRemoveItem(Item item, int slotID)

Corresponding Unity events exist for each of these events. The following code can be used as an example for subscribing to one of these events using the built in event system:

using UnityEngine;
using Opsive.Shared.Inventory;
using Opsive.Shared.Events;

public class MyObject : MonoBehaviour
{
    public void Awake()
    {
        EventHandler.RegisterEvent<IItemIdentifier, int>(gameObject, "OnInventoryAdjustItemIdentifierAmount", OnAdjustItemIdentifierAmount);
    }

    /// <summary>
    /// The specified ItemIdentifier has changed values.
    /// </summary>
    /// <param name="itemIdentifier">The ItemIdentifier that has been used.</param>
    /// <param name="remaining">The remaining amount of the specified ItemIdentifier.</param>    
    private void OnInventoryAdjustItemIdentifierAmount(IItemIdentifier itemIdentifier, int remaining)
    {
        Debug.Log("The inventory used " + itemIdentifier + ", " + remaining + " is remaining.");
    }

    public void OnDestroy()
    {
        EventHandler. UnregisterEvent <IItemIdentifier, int>(gameObject, "OnInventoryAdjustItemIdentifierAmount", OnAdjustItemIdentifierAmount);
    }
}