Introduction to UIs in Unreal

Welcome to the first in a series of tutorials on creating UIs in Unreal. Most
other tutorials I've seen online only cover basic UI creation using Blueprints
and UMG, however this series is focussed on creating professional-quality UIs
in Unreal using C++ and Blueprints.

Let's Get Started

The first thing we will be dealing with is UMG, the name given to Unreal 4's
latest UI system. We will first get used to using it from within the editor,
and learn what its features and limitations are.

In order to get started with UMG, the first thing you should do is create
a space that lets you experiment with the UI tools available.

In the case of level design this would be making a new Map asset in Unreal. In
the case of UMG, you need to create a UserWidget asset. We'll talk about
what UserWidgets are in detail below. But for now just right-click in the
Content Browser, choose UserWidget from the pop-up menu and call it whatever
you want.

At first Unreal's UMG system can be a bit daunting. There are a large number of
widgets, a large number of options on each one, and learning how they all
affect each other is quite a steep learning curve. But don't panic, this
stuff will make sense the more you use it. I promise :)

The editor view on UserWidgets is split into two tabs, shown in the top-right.
The Designer view and the Graph view. They are two views onto the same
widget, one is its visual aspect, the other its logic.

The Designer view is where you set up how your UserWidget will look when it is
created. You can add new widgets, lay them out, change their default
properties.

The Graph view is where you set up your Blueprint logic and control how
the widget will behave in-game.

Editing UserWidgets in the editor
(Labelled screenshot of UI)

Designer View

▲ Designer view of the editor

The screen presented to you is composed of a few parts:

Palette: Lists all the widgets available to you

Hierarchy: The tree view of your UserWidget, with the UserWidget's
root at the very top. You can click on any of the widgets to select them.

Widgets in bold are "Is Variable" widgets. These are available in the
Graph view.

Viewport: The selected widget is shown with a green border.

Details: Shows the properties available on the curently-selected widget.

Animations: Lists animations within the current UserWidget

Timeline: Shows the timeline of events for the currently-selected animation

We will cover the details of some of these sections later, for now let's move
on to explaining more about how UMG documents work.

Graph View

▲ Graph view of the editor

Nesting and Slots

The first thing to understand is that the "document" in UMG is a tree of nested
widgets. Some widgets cannot contain any children, some can contain a single child, and
some can contain many children.

no children: Image, TextBlock

one child: UserWidget root, Border, NamedSlot

many children: CanvasPanel, Overlay, WidgetSwitcher

Slots

When a widget is put inside another, we can customise how it behaves inside its
parent through its Slot property. In the editor it's the first set of
variables shown in the the property view.

▲ On the left, Image&lowbar;1 is inside a CanvasPanel. On the right it is inside an OverlayPanel.

Notice in the screenshot that our Image widget's Slot properties are different
depending on whether it's inside an Overlay or a Canvas widget.

In the Overlay Slot property we can set how the widget is stretched or aligned
in its parent. The Canvas Panel Slot gives us the option of setting pixel-based
offsets from the edges of the parent.

In Blueprints, to access the Slot property of a widget use the GetSlotAs
node.

Widgets

We're not going to list every type of widget here and explain what each one
does. The best thing you can do as a new UI developer is to try out each widget
and see what you can do with it. What options it has for itself, if it can
contain children what options are available on its children's slots etc.

To give you an idea of where to start, here's a list of widgets that are most
commonly used. Try out each of these, read up about them, see what they do in
the editor and how to use them from Blueprints.

If you can understand how to use these widgets you should be able to make
pretty much anything.

UserWidgets

Your experimentations above should have been done inside a UserWidget. So
what's a UserWidget? Similar to the way Blueprint Classes are used to create
reusable objects with custom logic in maps, UserWidgets are used to create
reusable objects with custom logic for user interfaces.

To use a concrete example, to set up the UI shown below, I could:

create a UserWidget called "PageTitle" and include it once

create a UserWidget called "LargeButton" and include a few copies of it on
the page

▲ Simple example showing a page title and large button user widget on an example widget. We can build up more complex widgets from re-usable individual pieces.

It's important to note that I could create the same UI with just regular
widgets, and copy-paste them to create identical-looking buttons. In the case
of the PageTitle, there is only one instance of it on the page so I wouldn't
even have to copy-paste!

As a UI programmer and designer it's up to you to decide whether or not to
create UserWidgets for elements, whether they'd be better served by using
existing Widgets, or whether it would be worth creating your own C++ based
Widget. We will cover the latter of these in our more advanced tutorials on
creating new UWidget subclasses in C++ and
creating Slate classes in C++.

However in general there are some guidelines for when it's better to create
a UserWidget rather than copy-pasting a set of regular widgets:

When you want widgets with the same visuals in multiple parts of your UI.

When the widgets need complicated or very specific logic to set up their appearance or contents.

When you need to need to add and delete pre-styled widgets at run-time.

Document View

At first glance this panel seems fairly straightfoward: it shows you a preview
of your UserWidget. You've probably been using it until now without thinking
about it.

However there are a few features that are worth knowing about:

Desired Size

A widget's desired size is something worth discussing further.

You can preview a widget's desired size by choosing it from the drop-down menu
at the top-right. This is the size at which it will display when its size is
not overridden or stretched. This might sound kind of redundant but here are
some examples:

if a widget is placed inside an Overlay, and its OverlaySlot settings are
Horizontal-Left and Vertical-Top, it will display in the top-left at its
desired size.

if a widget is placed in a Canvas, and its CanvasSlot setting "Size to
Content" is set to true.

The desired size of a widget is especially useful when putting many widgets
inside a with flow-layout style widget panels like HorizontalBox and
VerticalBox.

You may have noticed when playing with UMG that placing more than one widget in
a HorizontalBox or VerticalBox, that subsequent widgets are positioned based on
the size of previous widgets. The desired size is what is used to calculate
widget positions.

You can override a widget's desired size in a few ways:

Size Box: Set a forced explicit height/width, or enforce a min/max size.

Canvas Panel: The widget's desired size will be based on

Tricks of the Trade

The problem with Unreal and tutorials that I've seen so far is they often
outline many different ways to solve a problem and don't really give any
suggestions on what kinds of approach work best.

In this series I will try to distill what I've learned in working on a large
game in an industry-leading company, and what I've seen recommended by Epic.

I'm not trying to claim that this is the very best way to solve the problem, or
all problems, but rather explain what did or didn't work for me when working on
a large game.

There are a few problems with creating entire UI systems in Blueprints:

You are likely to hit performance problems in large Blueprint-based UIs.
Small one-use blueprints are fine, but for large, complicated logic that is
called every frame, a Blueprint-based UI can really affect performance.

In Blueprints complicated logic is a nightmare to maintain. Anyone who's
written large Blueprint scripts can attest to the constant fight against
spaghetti.

Separation of data acquisition and data presentation. With
a Blueprint-only system, it's easy to mix getting data from disparate
sources, and formatting it for display. This makes future changes to data or
display a real pain to implement as your display graph nodes are so closely
tied to data-acquisition nodes.

Harder for many people to work on the UI at once. Blueprints are binary
assets, meaning they're impossible to merge, so only one person can edit them
at a time. If the UI artist wants to update the appearance of a widget, and
the developer is updating some Blueprint logic, they artist will have to
wait. If most of the logic is in C++, both people are less likely to step on
each others' toes.

As we'll see in the next chapter, we can solve a lot of these problems by
moving some of our logic into C++.