Design a grid style inventory window with UI Toolkit

12 minutes
4.6
(56)

Inventory systems are a great way to help facilitate how you want the player to engage in your game. Perhaps one of the most important components to consider are the constraints you want the system to help enforce. For example, many games gate what a player can carry based on the total weight of all the items. A slightly less common way is based on the item size. This has been done by games such as Resident Evil 4 and Dues Ex. In addition to controlling how much a player can carry, it also creates a mini game out of the inventory by requiring them to strategically organize to maximize what they can carry.

This tutorial is part of a series which will explore how you can create an inventory that requires the player to sort by item size. Part 1 will walk through creating the UI design in UI Builder.

Learning Outcomes

This tutorial will cover the basics of UI Toolkit and how you can create a complex inventory UI. By the end, you will learn:

  • A practical workflow for building up a complex UI with different zones.
  • The basics of using UI Toolkit & UI Builder.
  • How to create and work with a stylesheet.
  • How to add the UI to a scene

Prerequisites

  1. You should have Unity 2021.1.12f1 or later to follow along with this tutorial.
  2. This tutorial assumes you have basic knowledge of Unity.

This tutorial will work with earlier versions of Unity but has a higher chance of having UI Toolkit related bugs and may have different installation requirements. Check out the UI Builder release notes for more information.

Resources

  1. Clean Vector Icons by PONETI

Getting started

This tutorial does not have a starter project. Instead, create a new Unity project, ideally using 2021.1 or later. The UI uses the Clean Vector Icons (Free) pack from the Asset Store. Download add it into your project.

Install UI Toolkit for runtime & UI Builder

The steps in this section are not needed if you are on 2021.2 or above.

UI Toolkit and UI Builder are packaged with Unity Editor in version 2021.1 and above. However, the features that are needed to use UI Toolkit at runtime require the installation of the com.untiy.ui package. Since the package is not discoverable in the editor, you will need to add it by doing the following:

  1. Go to Window > Package Manager.
  2. Click on the + button and choose Add Package from git URL.
  3. Enter the following URL: com.unity.ui.

As of the writing of this tutorial, the latest UI Toolkit version is 15, which is incompatible with the UI Builder version bundled in editor version 2021.1. If UI Builder is broken, you will need to downgrade to package version 14:

  1. In package manager, expand UI Toolkit and select See other versions.
  2. Pick 1.0.0-preview.14 and click the Update to 1.0.0-preview-14 button.
  3. Restart Unity to clear any errors that won’t go away.

Getting to know UI Toolkit

UI Toolkit (formerly UI Elements) is a Unity UI system that can be used as an alternative to IMGUI (editor UI) and Unity UI (runtime UI). It’s still in preview, so some of the screenshots in this tutorial are likely to change as new releases occur.

UI Toolkit follows UI patterns similar to web design, including the ability to define stylesheets! Stylesheets are a great way to abstract away properties that define the look of various elements in your UI. This gives you the ability to define once, and use any where. Additionally, all components that you make can be reusable, making the design pattern a lot quicker. There are two key assets that are important to building a new UI:

  1. Unity eXtensible Markup Language Documents (UXML): Defines the structure of the user interfaces and reusable UI templates.
  2. Unity Style Sheets (USS): Similar to Cascading Style Sheets (CSS), USS allows you to set visual styles and behaviors to your UI. These can be used in any UXML file.

UXML and UI Document are two terms that are often used interchangeably during this tutorial.

The layout engine that UI Toolkit uses is the open source project called Yoga, which implements a subset of Flexbox. Flexbox is an HTML/CSS based layout system. Understanding the basics of Flexbox is very helpful when designing your UI. A useful guide to Flexbox can be found here

UI Toolkit Resources

There are many tools and resources that you can use throughout development to better understand how to setup your UI and how to debug issues:

  1. UI Builder: Visually create and edit your UXML and USS files. Located at Window > UI Toolkit > UI Builder.
  2. UI Debugger: A diagnostic tool that lets you traverse the hierarchy of the UI to get useful information around the underlying structure and styling. You can also temporarily change properties to see how they impact your running project. Located at Window > UI Toolkit > UI Debugger.
  3. UI Samples: Library of code samples for various UI controls. Located at Window > UI Toolkit > Samples.

UI Toolkit was originally designed as an alternative for IMGUI and many of the controls that you get out of the box with UI Builder do not work with the Runtime version.

UI Builder Basics

UI Builder is a way to visually create and edit UXML and USS files. I am often creating bits of my UI through code and often times use UI Builder to mockup mockup how it will look or to see what the proper syntax is for a style variable. Open the window by going to Window > UI Toolkit > UI Builder.

The window has six sections:

  • Stylesheets: Manage the stylesheets and individual selectors that are used. Style Sheets can be shared across multiple UXML files, thereby maximizing reusability.
  • Hierarchy: A list of all elements that are in the file.
  • Library: Contains a list of standard elements that can be instantiated. The Standard tab contains UI Documents from Unity. The Project tab contains UI Documents created in your project.
  • Viewport: Visual of the UI document.
  • Inspector: Contains modifiable attributes and style properties for the element currently selected in the hierarchy or Stylesheet sections.
  • Code Preview: Displays the UXML and USS code that UI Builder is generating based on your decisions.

Configure the resolution and container elements

The inventory screen that you’ll design will have six major zones that provide the player with different bits of information. They are:

  • Window title
  • Character level and current experience
  • Currency available
  • Total weight of items carried
  • Items in the inventory
  • Selected item details

You can design a UI that is flexible and scales with the resolution of your game. To keep it simple and predictable, I’ve designed this screen based on 1920×1080 resolution. First thing you will do is set the right resolution for both the Game window and UI Builder:

  • In Unity, click on the Game window and set the display to Full HD (1920×1080).
  • Inside UI Builder, click on the first item in the Hierarchy window, called «unsaved window».uxml. This pulls up the base properties.
  • Check the Match Game View checkbox. This ensures that the UI scales with the screen.

In theory, you should be able to set the Size of the canvas to 1920×1080, rather than selecting Match Game View. However, I have noticed an occasional bug that purges the size values when the editor is restarted.

Setup the Container Elements

Drag VisualElement from the library and drop it in the Hierarchy window. Click on it to pull up the inspector properties. Set the following:

  • Name: Container
  • Flex > Grow is 1.
  • Background > Color: #1D1D1D

Setting the Container to Flex-grow 1 tells the layout engine to expand the VisualElement to the full height/width of the window. Read more about Flex-grow here.

The body of the inventory is broken into two sections. Above the yellow line is the header, and below is the body. Set both of these up now.

Add a VisualElement as a child of the Container. Set the following properties:

  • Name: Header
  • Flex > Direction: Row
  • Size > Height: 100px
  • Size > Max Height: 150px
  • Size > Min Height: 100px
  • Margin & Padding > Padding: 10px 10px 0px 0px
  • Border > Color > Bottom: #FF7C00
  • Border > Color > Width: 0px 0px 0px 1px

Add another VisualElement as a child of Container. Set the following:

  • Name: Body
  • Flex > Grow: 1
  • Flex > Direction: row-reversed
  • Margin & Padding > Padding: 10px

There were two options that made sense for the direction of Body: row and row-reversed. Using row-reversed will ensure that the Visual Elements generated for each item in the inventory appear above everything in the hierarchy. (You’ll do this in part 2.)

Here’s how the properties behave:

Row

Displays the children left to right, sorting from the first child to the last child.


Row-reversed

Displays the children left to right, sorting from the last child to the first child.

Don’t worry if the impact of this decision doesn’t quite make sense yet. You’ll write the code for generating the VisualElements in Part 2, which will give you the opportunity to experiment with the two settings.

Design the header

The header is broken into four sections, the window title, character level, currency, and total weight.

Window Title

Drag a Label into the hierarchy window and make it a child of Header. Set the following:

  • Name: lbl_Header
  • Text: INVENTORY
  • Flex > Grow: 1
  • Text > Align: Middle

Your hierarchy should look like this:

Create the style sheet

You create an “inline style” every time you set a property directly on an element in the inspector. This means that the style is written directly to the UXML file, rather than being saved in the style sheet (USS). I tend to add styles to a USS file for two main scenarios:

  1. The style is something I want to reuse across two or more elements.
  2. I want to add and/or remove style properties via code.

You’ll do both in this project. Create a new selector that will be applied to the main labels. It’ll control the text size, so that if you decide to adjust it later you only need to do it in one spot.

Create the USS file and new selector by going to:

  • In the StyleSheets section, click the + button and select Create new CSS.
  • Name it InventoryStyles.
  • Select the InventoryStyles.uss header to pull up the Inspector properties.
  • In the Selector text box, type .header_main and click Create new USS Selector.

Click on .header_main and set the following property:

  • Text > Size: 50px

Putting a period (.) in front of the name designates the selector as a class. You must manually set it for any elements you want it to impact.

Drag and drop .header_main onto lbl_Header to set it.

You can format your selector as #elementName to have it automatically apply to any element named the same. For instance, instead of .header-main, you could have called it #lbl_Header and then skipped the drag/drop step above.

Add the level widget

The level widget has the most complicated layout of all the sections in the header. The rest will be a piece of cake!

To start, add a VisualElement as child of Header. Set the following:

  • Name: Container_Level
  • Flex > Grow: 1
  • Flex > Direction: Row
  • Align > Justify Content: Center
  • Margin & Padding > Padding: 0px 0px 10px 0px

Add a Label as a child of the Container_Level. Add .header_main as a class. Set the following:

  • Name: Level_Value
  • Text: 30
  • Text > Align: Middle

Add a VisualElement as child of Container_Level. Set the following:

  • Name: Container_Level_Bar

Add a Label as child of the Container_Level_Bar. Set the following:

  • Name: Header
  • Text: LEVEL
  • Text > Size: 18px

Add a VisualElement as child of Container_Level_Bar. Set the following:

  • Name: Bar_Outer
  • Size > Height: 100px
  • Size > Width: 250px
  • Border > Color: #FF8000
  • Border > Width: 1px
  • Border > Radius: 3px

Add a VisualElement as child of Bar_Outer. Set the following:

  • Name: Bar_Inner
  • Size > Width: 75%
  • Size > Height: 100%
  • Background > Color: #98591A
  • Border > Color: #98591A
  • Border > Width: 1px
  • Border > Radius: 2px 2px 0px 0px

Add a Label as a child of the Container_Level_Bar. Set the following:

  • Name: Experience_Value
  • Text: 1500 / 2000

Add the currency widget

The currency widget is very simple and only contains three elements.

Add a VisualElement as a child of Header. Set the following:

  • Name: Container_Currency
  • Flex > Grow: 1
  • Flex > Direction: Row
  • Align > Align Items: Center
  • Align > Justify Content: Center
  • Margin & Padding > Padding: 0px 0px 10px 0px

Add a VisualElement as a child of Container_Currency. Set the following:

  • Name: Icon
  • Size > Width & Height: 60px
  • Margin & Padding > Margin: 0px 10px 0px 0px
  • Background > Image: T_24_diamond_

Add a Label as a child of Container_Currency. Add .header_main as a class. Set the following:

  • Name: Value
  • Text: 521

Add the weight widget

The weight widget is fairly similar to the currency widget. To speed things up, you can duplicate Container_Currency:

  • Select Container_Currency and right click > Duplicate.

Change the following properties:

  • Rename it to Container_Weight
  • Change Align > Justify Content to Right.
  • Select Icon and change Background > Image to T_1_anvil_.
  • Select Value and change Text to 100/300

Design the body

The body has two major sections: the inventory and a spot to display details about the selected item.

Add the item details widget

Add a VisualElement as a child of Body. Set the following:

  • Name: ItemDetails
  • Size > Width: 25%
  • Margin & Padding > Margin: 0px 15px 50px 50px
  • Margin & Padding > Padding: 10px
  • Border > Color: #FF8000
  • Border > Width: 1px

Add a Label as a child of ItemDetails. Set the following:

  • Name: FriendlyName
  • Text: Item Name
  • Text > Size: 36px

Add a Label as a child of ItemDetails. Set the following:

  • Name: Description
  • Text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam eu tortor eget justo ullamcorper malesuada nec a nisi. Phasellus hendrerit id ex eget vestibulum. Phasellus pretium ac risus in viverra.
  • Flex > Grow: 1
  • Margin & Padding > Padding: 1px 2px 10px 0px
  • Text > Size: 20px
  • Text > Wrap: Normal

Add a VisualElement as a child of ItemDetails. Set the following:

  • Name: Container_Buttons
  • Flex > Direction: Row
  • Margin & Padding > Padding: 1px 2px 10px 0px

Add a Button as a child of Container_Buttons. Set the following:

  • Name: btn_Equip
  • Text: EQUIP
  • Flex > Grow: 1
  • Size > Height: 52px
  • Text > Size: 24px
  • Background > Color: #E2892D
  • Border > Color: #E2892D

It’s best to put the properties in a stylesheet because they will be shared across multiple buttons. Fortunately, it’s easy to extract all inline styles into a new selector. Scroll to the top of the Inspector and look for the Style Class List section. Type btn-main into the text field and push Extract Inlined Styles to New Class.

You should see the new selector appear in the Style sheet section and a reference to it was automatically added to the element.

Next, duplicate btn_Equip and change the following properties:

  • Name: btn_Drop
  • Text: DROP

The footer is all that’s left. Add a new VisualElement as a child of ItemDetails. Set the following:

  • Name: Footer

Duplicate Container_Currency from the Header section and make it a child of footer. Change the following properties:

  • Margin & Padding > Margin: 0px 0px 20px 0px
  • Margin & Padding > Padding: 0px 0px 5px 0px
  • Border > Color: #FF8000
  • Border > Width: 0px 0px 1px 0px

Select Icon and change Size > Width & Height to 30px.

Select Value and change:

  1. Name: SellPrice
  2. Text > Size: 32px

That’s it for this section. Your window should now look something like this:

Add the inventory section

Add a VisualElement as a child of Body. Set the following:

  • Name: Inventory
  • Flex > Grow: 1
  • Align > Align Items: Center
  • Align > Justify Content: Center
  • Margin & Padding > Margin: 0px 20px 0px 0px
  • Margin & Padding > Padding: 5px

Add a VisualElement as a child of Inventory. Set the following:

  • Name: Grid
  • Flex > Direction: Row
  • Flex > Wrap: Wrap
  • Size > Height: 894px

Add a VisualElement as a child of Grid. Set the following:

  • Name: SlotIcon
  • Size > Width & Height: 150px
  • Size > Max > Width & Height: 150px
  • Size > Min> Width & Height: 50px
  • Border > Color: #4B4B4B
  • Border > Width: 1px

Duplicate SlotIcon until you have six rows of nine items (54 in total).

Setup the scene

You must add a UI Document GameObject to your scene to load the UI. This will also trigger Unity generate the necessary components and PanelSettings asset for you. Here’s how you can quickly set up the scene:

  1. Add the UI Document GameObject by going to GameObject > UI Toolkit > UI Document.
  2. Name it Inventory.
  3. Set the Source Asset to the Inventory UXML file that you saved earlier.

Push play to see your inventory screen.

Depending on the Unity version you are running, you may notice an inconsistency in the styles when comparing what you saw UI Builder to what you are seeing now. That is because UI Toolkit has three stylesheets that it uses to give you a base look and feel. They are light editor, dark editor, and runtime themes. UI Builder gives you a preview of what your UI will look like based on the stylesheet selected.

Change the preview theme in UI Builder by clicking on Active Editor Theme and picking Unity Default Runtime Theme. You can find the option on the toolbar of the Viewport.

For my version of Unity, this will impact the font color used for the labels – they’re now dark grey instead of light grey. Fixing this is relatively easy since you used a stylesheet for the headers! Set the following Text Color properties to #D2D2D2:

  1. .header_Main
  2. Body > Item Details > FriendlyName
  3. Body > Item Details > Description

You may encounter a bug that is showing the value as D2D2D2 already. If that’s the case, simply wiggle the alpha value to register a change.

That’s it! You should now have a complete layout of the UI!

Part 2, Code the grid based inventory system, walks through how you can manage items using scriptable objects, generate a visual representation in your inventory and enable organization through mouse events and bounds checking.

How useful was this tutorial?

Share this tutorial...

Thank you for rating - Do you have any feedback you'd like to share?