Categories
Advanced Tutorials

Using the Inventory Package

Preface

In this tutorial we will learn how to use the Inventory package provided by Crayta to help us easily set up a system to manage a player’s inventory.

Crayta has an inbuilt Asset Library which provides easy access to packages provided by the Crayta team or Crayta users.

If you are coming from a Unity background this is similar to the Unity Asset Store. A Unity Package downloaded from their store will be a Crayta Package, that is a collection of templates, scripts, widgets etc that can be easily shared between Crayta projects to enhance the functionality of your game.

The Crayta team provides and maintains a collection of packages (Game, Shop, Inventory etc) that can help you easily put in place the basic functionality for a game or learn by studying how they work.

Installing the Inventory Package

Using the Community Tab of the Asset Library window in the editor we can easily install the inventory package to any game by selecting it from the packages list and hitting install.

Crayta will download and install the package to your game alongside any dependencies required. You can now see what the package has imported to your project by selecting and expanding it in the Packages section of the library window:

Structure of the Inventory Package

Let’s take a look at the contents of the package that are now available to be used in our game. A Crayta package can contain any kind of assets that can be authored in the editor (meshes, effects, scripts, templates etc.). In this case the Inventory package imported two templates, a widget and a number of scripts.

Templates

  • User Inventory, is a simple template that holds the main inventoryScript component and an example of setting a default item.
  • Player Inventory View, is a template containing the widget/UI logic for the inventory.

Those templates provide a basic layout on how to structure your inventory logic, you can use them as they are by dragging them straight onto the User and Player template accordingly or attaching the required scripts and widgets yourself to the User/Player entity.

Widget

  • inventoryViewWidget, this is a Crayta widget asset (a file containing HTML/CSS/Javascript) which is responsible for rendering the inventory interface on screen. This widget has to be attached to the Player template to work.

The default layout renders a configurable number of slots at the bottom of the screen, each slot can be empty or hold an item. Using HTML/CSS you can easily add your own styling to the interface.

Scripts

  • inventoryScript, this is the heart of the inventory system, this script is responsible for initialising and managing all inventory items. To use this script attach it to the User template.
  • inventoryDefaultScript, this is an optional script used to set the default items in inventory slots that are available when the game starts. You can attach this on any entity (the inventoryScript can be configured where to look for default items) or add it to the User template.
  • inventoryViewScript, this script is responsible for communicating all inventory logic to the inventory widget for rendering. It also handles equipping/unequipping items and passing through inputs / button presses to the currently equipped item. It should be attached together with the widget to the Player template.
  • inventoryItemSpecScript, is used to define an item which can be picked up by the Player and added to the inventory. It should be attached to a Template.
  • pickupSpawnerScript, this is an optional script used to handle spawning and respawning pickups of items that can be picked by the Player and added to the inventory. It can be either attached to a Template to use that template as pickup or to any entity and be configured to use a template as the pickup item.

Most of the methods in the inventory scripts have detailed comments explaining how they work and what they do, making it easy to understand and extend their behavior.

How to setup the inventory

Let’s examine now how we can start using those scripts to setup a basic inventory easily and quickly in our game.

Putting the scripts in place

After installing the package we should start by adding the base inventory scripts and widgets in place. We can do that easily by:

  1. Dragging and dropping the User Inventory template from the inventory package to our User template.
  2. Dragging and dropping the Player Inventory View template from the inventory package to our Player template.

Those two templates will add script folders with the inventory scripts to our User/Player templates.

Running the game by pressing the preview button (Key: F5) will render the inventory automatically.

Adding items to the inventory

There are 2 steps to making an item become collectable: first we have to turn the item into a template, and then we need to add the appropriate scripts to it.

Step 1: Select your item (in our example it’s a ChineseLantern) and then select Template->Create New Template. Give your new template a name (we’ve called ours ‘Lamp’).

Create a new template of your collectable item.

Step 2: At the top of the world tree you need to click the dropdown to change the view from World to your template:

Click the dropdown to select your template.

You now need to add the inventoryItemSpecScript to your template:

  • Select Entity->Add->Script->inventoryItemSpecScript

The inventoryItemSpecScript makes it easy to make any template in our game ready to be added to the inventory. We can give it a freindly name (such as ‘Lamp’), choose whether it becomes a stacked item, and what grip the player’s character should use when they carry it.

This script adds the required properties to any template so that it can now be added to the player’s inventory.

To actually appear in the Player’s inventory, we have two options – let’s explore both.

Option 1: Start with the item in the inventory

Adding the User Inventory template to our User template created a new script folder called Defaults

Add an inventoryDefaultScript component to this folder, and set the template to the one for your item (i.e. Lamp). You should now start with the item already in the player’s inventory. Here you can also configure the quantity of this item the User will start with by playing with the count property.

Running the game now you will see an item being automatically added to the inventory. The Player carries it on its assigned grip position. If no grip position is selected, the item will attach to the right hand by default.

Option 2: Add pickup items to the game

Having the Player carrying all the items from the start of the game might make it too easy and not so fun. Let’s learn how to easily add pickup spawnable items to the game world.

Add the pickupSpawnerScript to your custom item template. Now this script comes with a large number of properties to customize it to your liking:

  1. For the moment let’s decrease the min/max respawnTime property to 5 seconds, which affects how often the item will respawn after it is picked by the Player.
  2. Also be sure to enable the showOnInit property which will make the item available from the start of the game.

Return to the World Tree and add a few instances of this template to the World. Now if you go and preview the game you will find yourself able to start picking up those items with the Interact key (Keyboard E or gamepad face button left).

You can also enable the useOnCollision property on the pickupSpawnerScript to have the Player pick up any item he collides with automatically.

Configuring the inventory

You will notice that you can pick up several items and the number of items on that slot will increase. That is happening thanks to the canStack property on the inventoryItemSpecScript.

Go ahead and disable canStack and run the game again. You will see that as soon as you pick up this item, it will be added to the third item slot of the inventory. Trying to pick up more items will fail since your inventory is full.

To have more slots available go ahead on the User template and on the inventoryScript increase the maxSize property.

Using inventory items

We now have an inventory full of useful items, so how do we use them? The inventory package has by default input configured to use the following controls:

  1. Extra Action 2/Extra Action 3 to switch the active inventory slot to the previous/next slot. This is an easy way to cycle through your inventory items in game. (Keys F/Q on keyboard and Gamepad Right/Left Shoulder).
  2. Hotbar 1,2,3,4 etc to change the active inventory slot by its index (this works only on a keyboard right now, Keys 1,2,3,4 etc)

Advanced inventory features (Keyboard required)

Extending the default styling

To start extending the default styling provided by the inventory package, you have to edit the HTML/CSS code found in the inventoryViewWidget widget.

Let’s change the styling of the selected item. To do that locate the .item-selected class in the widget and replace it with the following code:

        .item-selected {
            background-color: #ffff1a;
            color: black;
            text-shadow: 0 1px rgba(0,0,0,.3);
            height: 100%;
            width: 100%;
            border-radius: 50px;
            box-shadow: 0px 0px 0px 2px #fff inset;
        }

This will update the color of the background and text and also increase the border radius making the item slot round.

Let’s make all item slots match this style by updating the .item and .item-empty classes accordingly to:

        .item {
            margin-right: 5px;
            display: block;
            background-color: #f3cda5;
            text-align: center;
            width: 100px;
            border-radius: 50px;
            height: 100px;
            color: #808080;
            z-index: 1;
        }

        .item-empty {
            background-color: #c1c1c1;
            height: 100%;
            width: 100%;
            border-radius: 50px;
        }

And also update the .item-hotkey class to center the slot index:

        .item-hotkey {
            width: 100px;
            display: block;
            padding-top: 2px;
        }
Note that you undo these changes with CTRL + Z

Saving/loading items

You can install a package available in the Crayta store, called Auto-save that can help you persist a Player’s inventory items between sessions or when changing worlds.

Installing the package will add two scripts in your project, the autoSaveScript and the inventorySaveScript.

To enable this functionality all you have to do is add those two scripts to your User template. There is only a single property that can be configured called interval. This sets the gameplay time after it elapses the inventory will automatically save in the background.

When the Player starts a new session or moves to a new world, his inventory will be automatically filled with the items he had in place.

Removing inventory items

Many inventory items in games can be used limited times or just once before they are consumed. The inventory package doesn’t provide an automatic way to handle that, though it provides a method that you can easily use from any script to add item removal logic.

Here is the method, found in the inventoryScript:

function Inventory:RemoveCurrent(removeCount)
    return self:RemoveFromItem(self.inventory[self.properties.currentIndex], removeCount)
end

Let’s create a new script called consumeItemScript and populate it with the following code:

local ConsumeItemScript = {}

function ConsumeItemScript:OnButtonReleased(btnName)
    if btnName == "primary" then
        self.inventoryScript = self:GetEntity():GetUser().inventoryScript
        self.inventoryScript:RemoveCurrent(1)
    end
end

return ConsumeItemScript

Now attach this script to your Player template and try pressing the primary action button (Left Mouse Button or Gamepad Right Trigger) while playing the game.

The active item will be used once and then it will be removed from the inventory.

Accessing the inventory items

All items the inventory holds, together with info regarding their quantity and the slot index they occupy, are stored in the self.inventory table in the inventoryScript.

Here is sample code on how to access that table from another User/Player script and print the item names in the console:

function ConsumeItemScript:Init()
    self.inventoryScript = self:GetEntity():GetUser().inventoryScript
    
    for index, inventoryItem in ipairs(self.inventoryScript.inventory) do
        
        if inventoryItem.template ~= nil then
            Printf('Item name {1}', inventoryItem.template:GetName())
        end
    end
end