skip to Main Content

Implementing an Inventory System in C++

In this post, we’re going to implement a basic Inventory System in C++. Create a First Person C++ Project Template and make sure to have a cup of coffee nearby because this will be a lengthy tutorial!

Before we dive in to type our code, here is the end result:

Since our Inventory System includes glowing effects, inputs and user interactions we will breakdown the functionality in order to avoid confusion. This means that we will create our system using the following workflow:

  1. Create a minor aspect of the system
  2. Test its functionality
  3. Repeat

Eventually, by merging all the minor systems, our Inventory System will be working just like the video above.

Throughout the tutorial I’ve used some very basic Assets. You can download them from here.

Moreover, you can find all the source code of this tutorial here.

Setting up our Pickup Class and creating the Glowing Effect

The first thing we’re going to create is the Glowing Effect of our Pickups. When your First Person C++ Project Template loads up:

  1. Add a new C++ class based on the Actor class and name it Pickup.
  2. Inside the Pickup’s header file type in the following code:
Then, switch to Pickup’s source file and inside the constructor initialize your static mesh component and  pickup texture like so:
When you’re done with that, add the following implementation of the SetGlowEffect and Interact functions:
Save and compile your code.

The SetGlowEffect function will make sure to highlight the static mesh of our pickup. This will work when we setup our Post Process effect in the Editor.

Switch to your Editor and create some pickup classes. I’ve created 3 pickups each with a different static mesh and item texture. Everything is included in the .zip file at the start of the post.

Adding a Post Process effect inside our Level

Before we setup our Post Process we need to make sure we have the right material in order for our items to Glow. For my project, I’ve used the material named M_Highlight from 4.8 version of Content Examples of UE4. In case you don’t have this version, the material is included inside the ziped file at the start of the post.

To add the downloaded material inside your project, close your Editor and copy the file inside the Content folder of your project. Then open up your project and the material will be where you’ve copied it.

In case you’re working with 4.10.4 version of UE4 the First Person Map will already include a post process volume. If you’re working with another version you may need to place one yourself. When you have placed a Post Process volume, setup the following options:

PostProcessSettings
Click on the image to enlarge in a new tab

To sum up:

  • Select the Blendables option and add the material you’ve downloaded. (Make sure you select the Asset Reference option when prompted)
  • Mark your Post Process volume as Unbound.

That’s it. We’re done with our Post Process. Let’s move on to our character setup in order to complete the Glowing effect!

Setting up our Character

Open up the source file of your character and add the following code:

Don’t forget to add the “Pickup.h” include right before the .generated.h file.

Switch to your Character’s source file and type in the following code for the above functions:

When you’re done with that, create a Blueprint based on your Pickup class and place it somewhere in your Level. Then, test if the glowing effect works as intented.

Setting up the pickup functionality

After setting up our glowing effect, it’s time to create the pickup functionality for our Character. Go to your Project Settings and add a new Action Mapping named Pickup. Then assign a keybind of your liking (I assigned the button E) like the following screenshot suggests:

action_mapping

Then, go to your Character’s header file again and add the following code:

Moreover, right after your #includes add the following line:

Since we will attach UMG to our Inventory later on, we need to create a somewhat hardcoded value for the total number of the items that a character can pick up. However, by defining a value and use that instead of a hardcoded value is somewhat more flexible for future use.

Then, inside your character’s begin play function, right after the initialization of the last seen item, type in:

Moreover, go to the SetupPlayerInputComponent function and add the following mapping:

Then, implement the PickupItem function:

In case the Inventory is full and there isn’t a nullptr Item inside our inventory the Inventory.Find function will return INDEX_NONE instead of the AvailableSlot. In this case, this means that the engine is telling you that your TArray of items doesn’t have an available slot for a new item.

 

Right now you have the pickup functionality of you inventory. Place a couple of pickups inside your map and test it and make sure their default static mesh/materials are different. The Inventory is exposed so you can test what’s happening inside your inventory from within the editor!

Setting up our Project for the UI logic

In order to create a functional inventory with it’s dedicated window we need to add UMG to our project. However, before doing that, we need:

  1. A Controller to communicate information between our Character and our UMG logic
  2. A GameMode which will tie our Character and our Controller together
  3. A User Widget responsible for the whole Inventory
  4. A User Widget responsible for each individual inventory item

Before adding any classes, go to your project’s header file (I named my project InventorySystem so I will select the “InventorySystem.h” file) and add the following includes:

Moreoever, locate the [YourProjectName].Build.cs file and replace the following line from:

to:

Save and compile your project.

Then, switch to your editor and add the following C++ classes:

  1. A PlayerController (name it MyPlayerController)
  2. A UserWidget (name it InventoryWidget)
  3. A UserWidget (name it InventorySlotWidget)

When you’re done with that add a Blueprint Game Mode and named it BP_MyGameMode. In this case we need the game mode just to tie the controller and the character together. Since we won’t need any C++ for that we will add a blueprint instead.

After you have completed all the steps above, create a Blueprint which is based on the MyPlayerController (I named mine BP_PlayerCon). Then, open up the BP_MyGameMode and tie everything together like the following screenshot:

bp_gamemode

Now that you have completed this step, go to your map and inside the World Settings assign the BP_GameMode.

Setting up our Inventory Slot User Widget

Open up the InventorySlotWidget.h and add the following code:

Switch to your source file and add the following implementations:

Then, switch to your Editor and create a Bluprint based on the InventorySlotWidget and name it UW_InventorySlot. Open up the UMG editor and:

  1. Place a button which covers the whole area
  2. Inside the button place an image which covers the whole area
invslotwidget
Click on the image to enlarge in a new tab

Here is the end result:

I know it looks like an abomination but please bear with me. After that Select the Image you’ve placed inside your button and in the Appearance menu, make a brush binding to the ItemTexture property we’ve created inside our C++. Here is an image to make things easier:

inventoryslot_img
Click on the image to enlarge in a new tab

We’re done with our Inventory Slot Widget, for now at least!

Setting up our Inventory User Widget

Open up the InventoryWidget.h and add the following code:

Save and compile your code. After that, create a Blueprint based on the Inventory User Widget and name it UW_Inventory.

Open up the UW_Inventory and create the following UI:

inventorywidget_hierarchy
Click on the image to enlarge in a new tab

Again, I know it doesn’t look like much, but bear with me!

Each InventorySlot is a UW_InventorySlot and has the Vertical and Horizontal Alignment set to Fill. Moreover, make sure you enter the following values for your inventory slots:

  • All Rows set to 0
  • For InventorySlot_2 set Column to 1
  • For InventorySlot_3 set Column to 2
  • For InventorySlot_4 set Column to 3
inventory_eventgraph
Click on the image to enlarge in a new tab

When you’re done with that, switch to your Event Graph and add the following logic:

We’re done with the Inventory Widget for now.

Go to your Editor and specify a new Action Mapping named Inventory.

Then, open up the header file of your character and add the following function:

Then, switch to your source file and add the “MyPlayerController.h” file. Moreover, locate the SetupPlayerInputComponent and add the following line of code:

When you’re done with that, add the following implementation of the HandleInventoryInput function:

Don’t compile your code yet because we have yet to write the HandleInventoryInput function for our controller.

 

Open up your Controller’s header file and add the following code:

Don’t forget to include the “InventoryWidget.h” file.

Then, switch to the Controller’s source file and add the following code:

Don’t forget to:

  • Add your Character’s file and
  • Change the line 15 to match your character!

Save and compile your code!

Go to your Editor and open up the BP_PlayerCon and set up the UW_Inventory as a reference:

controller_ref

At this step we’re ready to test our code. Place some BP_Pickups inside your level and don’t forget to setup a texture for each and every one of them. Otherwise you will not be able to see your Pickup’s Texture!

Here is my end result after picking up 2 items at this step:

endresult_1
Click on the image to enlarge in a new tab

Since we have the base functionality we now need to update our code. In the next section we’re going to implement a Pause system so that the game won’t continue until you either close the inventory or select an item.

Setting up a pause state

In most games, when the player has an open inventory the game pauses. We would like to achieve this functionality. To create that, we need a bind that gets called even though the game is paused. In order to achieve that:

  • Navigate to your Character .cpp file and locate the function SetupPlayerInputComponent
  • And replace the Inventory action mapping:
with the following code:
Now that we made sure that our Inventory Bind is executed while on pause, let’s add the following features:

  • Pausing and unpausing the game
  • Showing our Cursor
  • Consume Inputs for our Inventory Slots Widgets

To do that, navigate to MyPlayerController.cpp and make the following changes in the HandleInventoryInput:

With the above code we have achieved the Pause and unpause as well as showing and hiding the cursor of our game. You should compile, save and test your code at this state! Let’s move on and create the logic for our Inventory Slot Click status.

For this case, we won’t create a system that will make our Character actually equip our awesome cubes. However we will create a basic Equip functionality just for demonstration purposes.

Navigate to your Character’s header file and add the following code:

Then switch to the Character’s source file and add the following implementation for the SetEquippedItem function:

We’re done with tha Character. Locate the InventorySlotWidget.cpp file and add the following implementation of the SetEquippedItem function (remember that we’ve left that empty):

Don’t forget to include the Character.h file and replace my character’s class to fit your needs.

Save and compile your code. Then, locate the UW_InventorySlot Blueprint and select the Button we’ve added. From the details panel locate the OnPressed event and click the “+” Icon. Then, implement the following logic:

uw_inventoryslot_graph

Save and compile your Blueprint. You now have an Equip functionality!

Creating the Drop Pickup Functionality

In this post we’re going to create a drop functionality. Specifically, the character will be able to drop the currently equipped item. Let’s start!

Add the following function inside the header file of the character:

Then, switch to your source file and add the following implementation:

Don’t forget to add:

  • An Action Mapping using the Editor and its corresponding button
  • The binding inside the SetupPlayerInputComponent that points to the above function!

If you’ve made it so far, I would like to thank you for reading my tutorial! Have fun!

Avatar photo

This Post Has 52 Comments

  1. In the function “DropEquippedItem(),”int32 IndexOfItemhe” haven’t be initialized,how it is works?

    1. Hello, I’m not initializing the IndexOfItem variable because right after, I’m calling the Find function which exists in all TArrays.

      This function searches your specified array for a given item (in this case the CurrentlyEquippedItem). If the item exists inside the array, the Find function will return true and will modify the second parameter (in this case IndexOfItem) to match the index of the found item. However, if it failed to locate the given item inside your TArray, it will return false.

      Having said, since we’re using an if statement we have no need to initialize our variable because the Find function will take care of that.

      -Orfeas

      1. I see,thanks!
        In this tutorial,your make a particular actor -“PickupActor”-for pick up.But in the real game world ,should we need let the “Pickupactor” to be the Baseclass of the whole actor or using interface ?

        1. Yes. In fact, notice that we created only one class (the pickup class) and then we created different Blueprints derived from our pickup. This means that we used the pickup class as a Base class.

          I would use the interface approach only if my game demanded it. For example, imagine that you’re building World of Warcraft. WoW has a vast variaty of items, like inventory items, collectable items, cosmetic items and so on. That said, in my opinion an interface approach would offer a more flexible solution.

          -Orfeas

  2. When i create a blueprint derived from the InventorySlotWidget C++ class, i open it up, but there is no designer tab… help?

  3. Alex, I cannot reproduce your bug both in 4.11 and 4.12. Have you tried deleting and recreating a Blueprint based on your c++ user widget?

    -Orfeas

    1. Yes, several times… maybe the C++ class’ parent class could be Widget Component instead of User Widget?

      1. You need to inherit the User Widget class since we’re not creating a widget component. Have you tried to reproduce your bug in an empty project?

        -Orfeas

          1. That’s strange, if you are not able to open up the designer tab at all in any projects, could it be that there’s something wrong with the installed version of the engine?

            -Orfeas

            1. I don’t think so. I can create a blueprint that is a child of UserWidget and the designer tab will show up… only when i derive it from a C++ class that is child of UserWidget does this not work…

              1. I think you should open up a thread on answershub and describe your issue.

                I understand that this is frustrating since you can’t complete the tutorial so I suggest (as a temporary workaround) to create a Blueprint user widget and transfer the logic of the widget to a Blueprint functions library which will be written in C++.

                -Orfeas

  4. on “Setting up our Character” do we create a new “Character” C++ class?

    and if so, im stuck on “FVector StartLocation = FirstPersonCameraComponent->GetComponentLocation();”

    “”FirstPersonCameraComponent” is undefined”

    I guess it can’t find the camera component to attach to
    Anyone know how to fix this?

    1. In this post we’re using the first person C++ template project, so you don’t need to create a new character class – modify the existing one

      -Orfeas

  5. I couldnt get past the Raycasting because appearantly the LineTraceSingleByChannel doesnt return true if I use the CollisionQueryParams for ignoring the character himself. If I don’t use them, it returns only the Character. Any help? (Working with 4.14)

    1. Are you sure that you have the correct collision profile set up for your inventory item? (There are some meshes that ignore all collision by default)

      -Orfeas

      1. I’ll check on that, but wouldn’t it still be possible for the raycast to return anything at all if I ignore the player (There are other meshes in the level too)?

  6. Hey Orfeas, can you explain a little more about how you setup your inventory_widget heirarchy.png

    I followed the tutorial and everything works except for the textures are not showing up on my widgets, they are always staying as white boxes no matter what items I pickup or drop.

    I am new to UI in unreal so I basically had to guess based off the screenshot and I probably have conflicting layer render issue.. but its impossible to know.

    1. Hello,

      I’m using a Canvas Panel as a root for my UI. Then, I created a Uniform Grid Panel which contains all the inventory widgets. This control makes sure that each inventory widget has the same space in your UI.
      Inside the Panel I’ve placed the widgets that you see in the screenshot. Since you’re having the desired functionality but you’re not seeing any textures this means that your Blueprint cannot find a valid texture so it remains at the default texture (white in this case). Have you checked your Brush binding and your SetTexture assignments? Moreover, make sure to provide a valid texture for each item.

      Update: It’s unlikely to have a layer render issue because the Add to Viewport node places your UI 10 layers above your top layer (this is done inside the engine code).

      -Orfeas

        1. I was able to get them displayed finally by adjusting my button scale really low to match the size of the ones inside of my grid panel

  7. Orfeas,

    First off thanks for the tutorial, it’s greatly appreciated. I’ve implemented the pickup function and it successfully adds the item to my inventory. However, from a BP I’m attempting to get the name of the item which is stored in inventory location 0. I am getting the following error in the message log.

    Attempted to access TestItem_101 via property CallFunc_Array_Get_Item, but TestItem_101 is pending kill

    This makes sense in that I’m storing a reference to an actor that was just destroyed and is pending garage collecion. I’m curious if you get the same message in your game.

    since the item is an actor it must exist in the world, in other words it has to be spawned to hold a reference to it’s instance. Otherwise, you’d have to store it’s class and not the actor reference.

    thoughts?

    1. Hello Sean,

      The behavior you’re describing seems correct (however I cannot remember if I’ve encountered the same problem). The workaround in your case would be to set the visibility of your world item to false and disable its collision. Since you’re still having a valid reference to that item (through your array), the engine’s GC won’t mark your item as pending kill and the player won’t be blocked by that item.

      Check out my latest portfolio project that contains the described behavior:
      https://github.com/orfeasel/PortfolioSnippets/blob/master/UE4_TechDemos/PuzzleGame/Private/Components/BackpackComponent.cpp#L47
      https://github.com/orfeasel/PortfolioSnippets/blob/master/UE4_TechDemos/PuzzleGame/Private/Items/BaseItem.cpp#L73

      -Orfeas

  8. Hey there, I’ve just finished the part right before you implement the pause state. Unfortunately I’ve got a problem. Whenever I pick an item, the image of the item appears but the image in the inventory slot doesn’t change size to fit the button, so all that ends up showing up in the button is the top left corner of the image. Is there anyway to fix this?

    Also for anyone in the future RemoveFromViewport no longer works, use InventoryWidgetRef->RemoveFromParent(); instead.

      1. Yep, I’ve tried that and still no luck. Here’s some screenshots showing the problem

        Before setting to Horizontal/Vertical fill:
        http://imgur.com/fo5ZuZV

        After setting to H/V fill:
        http://imgur.com/wJuOYJa

        It doesn’t change no matter if I draw it as an image or box (which you see I’ve done in the screenshots)

        Thank you for still replying so late after you posted the article.

        1. MaxPro (a few comments above) encountered the same issue and stated that it was fixed by adjusting the buttons scale really low to match the size of the ones inside his grid panel. Can you give this workaround a go to see if this works for you?

          -Orfeas

  9. If I put Pickup object in my level and try to save I get some error:

    Can’t save C:/Users/User/Documents/Unreal Projects/MyProject9/Content/FirstPersonCPP/Maps/FirstPersonExampleMap.umap: Graph is linked to private object(s) in an external package.
    External Object(s):
    AssetImportData

    Try to find the chain of references to that object (may take some time)?

    Any idea how to solve it? 🙂

  10. I heard some people say going to file while inside your blueprint and selecting “Refresh all nodes” can fix this. But this error can happen for multiple reasons. It comes and goes for me all the time.

  11. So I can get everything but the UI/UMG to work for this tutorial in 3rd person template.

    Any idea as to why?

    I understand the tutorial is made for the First Person template and I will do it in 1st person tomorrow night. I am just curios as to why the UI/UMG isn’t rendering, are there drastic differences in those templates when it comes to UMG/UI or am I possible horribly overlooking something?

    Also thanks for three tutorials they have been a nice intro to UE4 from Unity.

  12. Hey Orfeas, thanks for all these tutorials!

    I got one one question. Where is function GetInventory() defined? I can’t compile my code cuz of Character class doesn’t have GetInventory() function. Should I declaare and define it in Character class? If yes, what should go in that function?

    Thanks.
    -Thevale

  13. Hey great tutorial, however I’m having an issue with the inventory. I don’t exactly know how to reproduce it, but the inventory will empty itself out sometimes and the game will crash with an error relating the the mycontroller class at this line:

    //Re-populate the ItemsArray
    InventoryWidgetRef->ItemsArray = Char->GetInventory();

    when I check the logs it says

    Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0xffffffff

    I’m not sure but it seems like there is an issue when populating the array. Any ideas? otherwise it seems to work fine as I’m able to euip and drop items, but I’m not understanding why this issue sometimes happens. I can replicate it after a few minutes each time I hit play.

    1. Hello,

      This error seems to be caused by attempting to read a pointer that points to either garbage memory or unavailable memory to your program. This might be caused by the way we’re initializing the inventory. Instead of initializing the inventory using the following lines:

      //Initializing our Inventory
      Inventory.SetNum(MAX_INVENTORY_ITEMS);

      Try to initialize the inventory with the Init function: https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/TArrays/index.html

      (Inventory.Init(nullptr,MAX_INVENTORY_ITEMS);

      -Orfeas

      1. Unfortunately that has not fixed the issue. The array will empty itself after testing placing it in the world and dropping it and picking it up again, and the crash will happen, however when I tested it didn’t seem to happen as quickly

        Is there a possibility of something else that might be occurring? The error in the log is the same, and I have initialized it in the way you described

        1. Chances are that you’re attempting to access a null pointer. Try to use multiple “if” statements each time you’re accessing a pointer and assign a console message for every “else” statement (so you know which code block has failed). This method will eventually show you the culprit.

          -Orfeas

  14. hi, is this work in multiplayer ? it is work for one player but if i switch to 2 player engine was crashed

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back To Top