[VIDEO PLAYBACK] [CLICKING] [BEEPING] - ISS to Houston,
this is Commander Diaz. Do we have any debris
close to our trajectory? - Evening, Commander. Negative on that. Clear sailing as far as
we can see down here. If there's any cause for alarm,
you know we'd see it too. Your crew members can
keep sleeping tight. - Well,
I'm seeing something out there. I can't make it out, but whatever
it is, it's getting closer. - Sorry, Commander. We're not-- - Houston, repeat again. [RADIO FEEDBACK] - This is SUITSAT. - It can't be. [RADIO FEEDBACK] - Up here we see everything. - Diaz, copy. Commander Diaz, do you copy? - Houston,
you're not gonna believe this. I'm picking up transmissions
on the ham radio that sound identical to the SUITSAT experiment. And that debris,
it's an Orlan spacesuit. - I'm not sure I'm
hearing you right. Repeat that, Commander. - SUITSAT. I'm seeing SUITSAT. - You're mistaken, Diaz. SUITSAT re-entered the atmosphere
and burned up years ago. It's impossible. - Yeah, I know it's impossible,
but I know what I'm seeing. It's SUITSAT. It's come back. And it's not just in orbit. It's headed right for the ISS. - Commander,
you're not making any sense. Say that again? Commander? [YELPS] - Up here the sky is black. Up here the sky is black. - Up here the sky is black. - I need to alert the crew. [RADIO FEEDBACK] - Diaz. Diaz. [DISTORTED SPEECH] Commander Diaz, do you copy? Diaz? [END PLAYBACK] [VIDEO PLAYBACK] SKYE RUSSELL: Welcome to this
week's news and community spotlight. How do we make the
metaverse more open? What goes into digital identity? We'll be digging into big topics and
some good old fashioned UE5 training at SIGGRAPH this year. Join us for more
than 15 talks and be sure to check out
the full schedule and the complete announcement
on unrealengine.com/feed. Hungry for more inspirational
sessions, educational programs, and even hands on
training opportunities? You'll be pleased
to know that Unreal Fest is back in
action and we cannot wait to see you all. Join over 1,000 developers and
us for more than 100 sessions from October 17 through
October 20 in New Orleans. Don't worry if you cannot make it. We'll record the talks and make them
available on demand after the event. Save the date. Registration for the event
will open in late August. This month's new Epic Developer
Community Courses are here. Whatever your next
learning conquest is, we're sure that you'll find
something to inspire and drive you. From AI animation, control
rig, cinematic lighting, and game optimization. Check them all out at
dev.epicgames.com/community. Did you miss our latest webinar,
Unreal Engine 5 For Architecture? Or perhaps you want to start using
UE5 for your Archviz projects. Watch the replay of
our recent webinar and find out how features like
the updated architecture project template and Lumen make
it easier to get started and raise the bar
for visual fidelity. Speaking of visual
fidelity in Lumen, we caught up with 3D artist
Lorenzo Drago on how he created the viral digital
recreation of Etchu-Daimon Station and how he handled creating the
day and night scene, the Blueprint magic behind the camera motion,
and the flashlight animation. Head to the feed to get all the
illuminating details and how the switch from UE4 to UE5 helped
empower Lorenzo and his projects. Swimming over to this
week's community spotlight, volcanic islands,
coral reefs and cute seahorses. Eugene B has dived into
their first 3D work with textures with this
stylized underwater utopia. From conception to crafting
this unique aquatic biome, passion and skill have been
poured into this UE4 scene without horsing around. Head to their ArtStation
page and let them know what you think of stylized
underwater landscape. Become fully immersed in
Canada's wild territories through the two
protagonists' perspectives and uncover their
realities, culture, and way of understanding life in Two Falls. Decide how the characters
will survive and watch the impact of your choices unfold
in this coming of age story. Wishlist this beautiful
and meaningful game by unreliable narrators on Steam. Take a trip to Peru with
environmental artist Jhosep Chevarria. This breathtaking cinematic
was created in Unreal Engine 5 using Megascans, Marketplace
assets, photogrammetry, and models created for the project. Words simply cannot describe
how beautiful this is. Sit back, relax, and enjoy
discovering Peru on the forums. Thanks for watching. Catch you next week. [END PLAYBACK] [WHOOSHING] TINA WISDOM: Hello,
everyone, and welcome back to Inside Unreal,
a weekly show where we learn, explore,
and celebrate everything Unreal. I am your host Tina,
and today with me, I have an incredible guest who I
will introduce in just a moment. One quick announcement
before we start. We will be going into
summer break soon. Yay for vacations for
everyone, right? [LAUGHS] So we will not have a show
for the next two weeks, but then we'll be right back on
the normal schedule after that. But focusing on the here and
now, here and today I have with me the
wonderful and incredible Michael Prinke. Would you like to introduce yourself
and tell us a little bit about what we're going to be going over today? MICHAEL PRINKE: Yes. Hello. I'm Mike Prinke. I am a technical writer on the
Unreal Engine documentation team. And I'm going to be showing you
guys basically a little crash course on how to use the Common UI
plugin with UMG in Unreal Engine. So basically what Common UI
is, it's a plugin that ships with Unreal
Engine 5 and 4.27 that has a lot of convenience
and quality of life features built into it. So it's a lot of really
typical UI features that are used in video games
very often that if you don't have the plugin to do them for
you, you would end up having to engineer them yourself
at some point or another anyway, or at least the biggest
features are like that. So to give you an idea,
there is a styling system. So basically you can instead of
configuring every single piece of text to have the font,
the size, the color and whatnot that you want it to
have individually, you can create a single font style asset
and then plug it in to the Common UI text widgets where you want them. And then if you ever want to
update the style on literally all the widgets in your
game, you just have to update that one asset that
contains all that styling data. You don't have to go into every
single UI and change them around. It makes the process a lot
less destructive and a lot more convenient. That is one of the features. The other ones,
there is an input mapping system that basically can recognize
input actions separately from the in-game input
system and it can map them to specific controller data assets. So what you can do is
you can tell it here are the input actions for my
user interface and my game. And then on each controller,
here is the button that triggers that action. And then you can use those
to trigger things in your UI. So you could, for instance,
take your shoulder buttons and bind them to flip
through different tabs at the top of the screen. And that's just a very
straightforward and intuitive process. But then you can also
map button icons. So you can decide, all right,
on this platform, the button icon for confirm is going
to be this little A button. On this one, it'll be a little
plus button or something. And then you can also map
it for mouse and keyboard and for touch screens as well. And so the really,
really nice thing about this is that basically whenever you
have to do button icons in your UI, it will automatically
pick up the platform and use the appropriate
icon that you set for it. And it'll also do that in the middle
of gameplay, as I'm going to show. So if you're playing on the
gamepad and then you switch over to your mouse and keyboard, then
it will swap the icon immediately to the keyboard icon
instead of the gamepad icon. And that is a behavior you will
see in Fortnite as well on PC. In point of fact, Common UI
is implemented in Fortnite. It is basically one
of the underlying systems for handling
UI in Fortnite. And all of these are Fortnite
features that we put into a plug-in for general use. Aside from those features,
there's also the input routing and activatable widget system. That basically makes widget focus
easier and more intuitive to manage. In base UMG,
it's a little bit tricky. You have to program your own system
for restricting which menus are active and which ones aren't. This has a built in
system for doing that. In fact, it even has
basically a menu stack widget that lets you navigate back
and forth automatically. And in fact,
the Back button functionality where you would press B to get out
of a menu, that's also built in. And I can show you how
to use that as well. Aside from those things,
there's just a lot of miscellaneous useful widgets. For instance, there's a general
universal throbber widget that you can use
for loading screens. There is a lazy load image
widget, which will basically display a placeholder
image while you are waiting for the
actual image you want to show to
download and load up, which can be useful
for live service games. There's so many things here
that I can't go into all of them and I haven't even experimented
with all of them myself. But I think what I'll go over
will handle the kind of humps that people have to get over
to start working with Common UI and start making use
of its most universally applicable and convenient features. So without further ado,
why don't we get into it? You can cut over to my screen now. All right. So to show you a look
at what I'm going to be building along with you
guys, this is just a very simple main menu. It's not got a whole
lot of functionality, but it does have a
quick game prompt. And I can just very quickly-- I just very quickly put that
together in a couple of hours, just to give you an idea of
what we're building. Even this simple thing is
going to take us a little while because we can
go into a lot of depth about all the tools that
went into building it. But I'm actually not going to
use this pre-setup project. I am going to start a
new project and we're going to build this from scratch. So let's call this-- let's use the Top Down project
just for a change of pace. Everybody always uses
the Third Person project, but I just feel like using Top Down. And I'll call it 'UIDemoStream'. We'll make it a C++ project. We'll keep all these other
settings here the way they are. Hit Create. And let it run. And in the background I'm going to keep these
UI assets for reference. And I'm going to also have
Lyra up for reference. Lyra is somewhere. Here's Lyra. So Lyra also has
Common UI implemented. And you can see a little bit of
what I was trying to do with my menu in how the main menu is set up here. This is a good reference for
a really fully featured UI, but it is a little overwhelming
to dive into Lyra blindly. So that's why I'm giving you
a simplified example of this. But without further ado,
let's go ahead and click Create to create this project. Is it frozen? Did I freeze it? I might have frozen it. OK. It's making the project. It's got the loading thingy
going up on my other screen here. That's why. 91%. TINA WISDOM: We should set a timer. [LAUGHTER] MICHAEL PRINKE: It's pretty
quick when it finally responds, but I am putting kind of a load on
this having three different Unreal Engine instances at once. [LAUGHS] TINA WISDOM: Yeah, this is
quite the test for your machine. MICHAEL PRINKE: It might
be wise to put Lyra away at least until I actually want
to bring it up and reference it. So that's what I'm going to do. All right. So to begin, we need to
enable the Common UI plugin. That's going to be
under the Plugins menu. And you just check Common UI
Plugin and restart the editor. And we're going to have to restart
the editor again in a second because there is
another setting that we have to change to get the
majority of Common UI's features, or at least the really convenient
menu focus stuff, working. All right. And now it's back. Now we go into Project Settings. And we need to look for
the 'Viewport Class'. So the Game Viewport
Client Class needs to be CommonGameViewpointClient. This is a viewport class
that comes with Common UI, as the name implies. Basically the-- sorry,
nerves getting to me here. Basically the input routing system
is built into this viewport. So input gets captured
at the viewport level. Then it gets sent to the topmost
widget in your hierarchy. At least the topmost widget
in your viewport, rather. And it will ignore
viewports that are lower in the
rendering hierarchy. And that's more or
less how it works. And that is what makes it easy
to handle things like menu stacks and to keep from
accidentally navigating to buttons in other menus,
for example, which is something that a lot of people
struggle with when they're building their first UIs. OK, we've restarted the editor. We've got this thing set up. And now we can start building some
of the components for our user interface. I'm going to make a UI
folder and I'm going to make a Blueprint folder as well. And while I'm at it
I'll make a Maps folder. And I will create a-- let's see. I will create a front end
map to hold our main menu. This is basically so that we
can set up a front end game mode and kind of partition off that
functionality from the main game. To be clear, there is no right
or wrong way to set up your UI. If you want a universal UI
that is always available, that is something that you could do. Basically your main menu could
always be around and even available during gameplay. But this is how I
prefer to do it just for the sake of a demonstration
for how it works in a typical game. It's kind of unusual to have all
of the main menu functionality in the middle of gameplay. Then we're going to go into UI. We'll make a couple of folders here. I'm going to do 'Data'. 'Icons'. And let's see. Was there some other
folder that I'm forgetting? Ah, it'll come to me in a minute. We'll go into the Data folder. And the first thing
that I'm going to do is set up the data table for
CommonInputActionDatabase. I'm going to pick
CommonInputActionDatabase as my row structure. This is going to be
my input action data table, which will hold
all of the input actions that I am able to
recognize in my UI. Now, to be clear about
something, you can split this up into multiple data tables if you
have some more specialized UI here and there. So you could make
a data table for in-game actions as
well as a data table for things that are
specific to menus. And then you could if you
have really specialized menus, you can make data tables
for those as well. You're allowed to split these
up as often as you like. There isn't a wrong way
to organize them unless it makes it difficult for your project. But basically we're going to add a
row and hope that it doesn't crash. OK, it lagged out for a second
there and scared me, but we're OK. [LAUGHS] TINA WISDOM: Made it through. MICHAEL PRINKE: And I'm going
to make an entry for 'Confirm'. And another one for 'Cancel'. And for the record-- oops. I put in 'Confirm' again. For the record, I haven't had this
data table editor crash on me yet. But whenever it lags out like
that, it's kind of sus. But anyhow, so Confirm and
Cancel, the two most basic actions that we will want to have available. And then just for the sake of
filling out other common inputs. 'Tab Left' and 'Tab Right'. These are going to be for the
shoulder buttons, basically. Now we go into the keyboard
inputs and the gamepad inputs. This is where you
set what the default inputs are that trigger these
actions, if applicable, at least. So let's grab-- let's see. This one is for tab right. Oops, that's not. That's the-- I want-- getting mixed up here. I'm going to use Q and R for
these just to have some keyboard navigation for these buttons. I will also make--
Cancel will be Escape. And Confirm will be
the Enter button. And then go down to gamepad inputs. Confirm will be Gamepad
Face Button Bottom. Cancel will be Gamepad
Face Button Right. That maps to A and B on the
Xbox controllers respectively. Nope, nope, Gamepad Left Shoulder. And now Gamepad Right Shoulder. There we go. Now let's say for just a second that
a specific console manufacturer who shall remain nameless decides
that they have the A and B buttons mapped differently. Users will typically expect A to
be confirm and B to be cancel. But let's say you
have them flipped so A is over here on the
right gamepad button and B is down here on the bottom. That could get a
little bit frustrating. That is the bane of
many a menu developer. But that's why you have this field
down here, Gamepad Input Overrides. So what you do is you
add an entry to that and then you can click whatever
platform you want to override for. Here because I'm using
a launcher build, it's only going to have the
generic controller option. So I'm not able to pick
different consoles. But if you've got the SDK set up
and you're using a source build, it will show the options for all the
different consoles that you've got. But let's say for
the sake of argument there is another controller
in here that does map the A and B buttons backwards. Basically, I can go here
and say for this platform, it will be face button right. And then down here I could
say, do face button bottom. And then I have my reversed
A and B buttons accounted for on that specific platform. Obviously, that will not
work here because I've only got the generic gamepad
listed as an option. So I have to delete those and
kind of return to normalcy here. But anyway,
that is just very quickly, the input action data table
we're going to be using. You can put many other different
types of actions in here, but we want to move on to some of
the other data assets that we need. Now we're going to go and
make a Blueprint class. And we're going to put in I believe
GenericInputData is the one. Let me make sure. CommonInputBaseControllerData. We do want that one. 'InputData_PC_Keyboard'. CommonInputBaseControllerData. 'InputData_PC_Gamepad'. And these two are going to contain
the information for our button icons. I might as well dive
into these right away. Let's open up the gamepad here. It's a blank Blueprint. You don't really need
the event graph here. It's a data Blueprint. So you really just need
the defaults for this class and to set up what icons
you're going to be using. This is a gamepad, so I'm going to
click Gamepad as the input type. I'm going to set it to Generic. Remember that. And I'll just call
it 'Gamepad' there. And I'll call it 'Windows' here. And if you wanted to,
you could set this up differently for Windows and Mac and all the
different desktop platforms. But let's go ahead and
get our brushes set up. Let's see. I really only need four
of these because I'm only using four input actions. But we're going to take the
Gamepad Face Button Bottom. And I need some icons here. So I'm going to hop
over to my Icons folder. And it just so happens that
I have some icons prepared for this occasion. Oops. There we go. It tore off the
content browser for me. Put in LB and RB there as well. And just to have
something to throw in, I'll also have a couple of keyboard
icons as well as alternatives. I'll show you a
helpful little trick. Select all of them. Go to Asset Actions. And Bulk Edit via Property Matrix... And then let me see. What was it called? There is a specific-- hang on a moment. Group. Texture Group. We can set the Texture
Group to UI for all of these without doing them all
individually basically. So make sure they're all selected
and they're all set to UI. Good. And now these are usable
as UI button icons. But now we can go back
to our gamepad here. Our gamepad data, that is. And we can put in these icons. I'm just going to go ahead and-- let's see. This is for Gamepad
Face Button Bottom. So I'll drop A in there. I'll actually override the Image
Size so that it's a little smaller. I think 64 was a little
bit big as the native size. So now let's see. Gamepad Face Button Right. Second verse same as the first. Gamepad Right Shoulder. Throw RB in there. Let's call that 64 by 32 instead. I did actually do that
here, didn't I? Yes I did. OK. And finally, we'll do one for the
Gamepad Left Shoulder as well. Throw in the LB button. 64 by 32. And that about covers
it for our gamepad. Now, there's a bunch
of other fields here that you can take advantage of
such as the Controller Texture. There's a couple of things that I
haven't explored all that thoroughly here. So the Input Brush Key Sets. I remember I used to
know what this was for, but most of the time you're going
to be using Input Brush Data Map. I think Input Brush Key Sets is
for axes or things like that. But I'm not too sure
off the top of my head. But anyway,
that gets our gamepad set up. I could put a controller
texture there so that if I wanted to fetch an image
for a controller layout screen I could use this,
but we're not going to get into that in this lesson here. So now we've got to
do the same thing. Whoops. One moment. I've gotten really used to
using the content drawer. So having it show up in odd
places muddles me up a little bit. Now we go into the keyboard. And we just leave it
at Mouse and Keyboard. And we're going to use Enter. And actually I didn't
make an Enter button. I made 1, 2, 3,
and 4 for my test for this. So little bit silly on my part. But Icon_1_Keyboard. We'll just go ahead and use
1 and 2 for Enter and Escape just to keep things moving
along so I don't turn this into a Photoshop
tutorial all of a sudden. Let's see. Add another one. Go. And funnily enough, I did think
to make icons for Q and R. Four. I haven't set the size for
them, I know. I'll get that in a moment. Right. 32's all around. And that might even
end up being too small. It might be we need
something in between and we'd be better off handling
the sizing in the UI itself. But we'll see how that turns out. But in my tests,
it turned out a little big at 64. So now that is our
input data assets. That has all the icons that
we need set up for these. And as you can see, it doesn't
go by the action mappings. It goes by the keys. So this basically is what
makes it possible for you to-- basically what makes it possible for
you to handle these on a platform by platform basis. Because again,
the face button bottom is going to be different on some
controllers versus others and that kind of thing. When you do have an input action
bound to an on screen UI element, it will look for the
key that it belongs to and then match it
to the icon for the icon set that it's
supposed to use. So there's kind of a lot
of communication going on under the hood. So now we're going to hop
into our Project Settings and we are going to set these up so
that the game has access to them. That's going to be under,
let's see, Common Input Settings. Put the Generic--
not GenericInputData. Why is GenericInputData there? That doesn't seem right. InputAction Table. Oh, I know why. I'm thinking of a different asset. So this Input Data field
is for something else. There we go. CommonUIInputData. So there's one more data
asset that we need to use. What do we call this? Hang on a moment. I did a silly thing here. I'm going to rename
these for a second. So I'm going to rename
these controller data assets to 'ControllerData'. PC keyboard and controller data. ControllerData_PC_Gamepad and
ControllerData_PC_Keyboard. Because I just got the
names mixed up a little bit. The InputData Blueprint
does something different. Basically this lets you set
a universal click action and a universal back button action. So I select my action
table that I made earlier. And I will set Confirm as
the universal click action and Cancel as the
universal back action. And then I save that
and I hop in over here. And now I put in DemoGameInputData. And now the universal back button
stuff is all ready for me to go. Then I do Platform Input. Go to Windows. And I will actually-- I'll come back to the
Default Input Type here and some of the funny things
that can happen with it. But for right now,
I'm going to plug in ControllerData_PC_Keyboard
and ControllerData_PC_Gamepad as the assets for controller
data on this platform. Obviously you could hop into
each of these other ones and set them up in whatever
way makes sense for you. As you can see, by default iOS has
Touch as its Default Input Type. But all the desktop platforms
will have Mouse and Keyboard. And again, we will get
back to that in a minute. All right. So that basically
gets my data assets all out of the way and set up. Now we need to do styling assets. So we're going to go in here. And you'd probably think
that the styling assets would be under
Miscellaneous as data assets because they kind
of behave like them. They actually show up
as Blueprint classes. So CommonBorderStyle,
CommonButtonStyle, CommonTextScrollStyle, and CommonTextStyle. We're going to be
making a border style. 'DemoGameGenericBorder'. We'll make a button style. We'll make a text style. And a border style. DemoGameGenericMenuBackground'. And actually it would
probably be a good idea to-- I already did the border. I'm sorry. What didn't I do? Oh, that's right. In my previous one,
I actually had a fourth one and it was a header
text style in case, I got around to doing
a title or something. OK. Border, button, text. Probably a good idea in
the name to preface this with 'BorderStyle_',
'ButtonStyle_', and TextStyle_' just so that they're
easy to look up. We will do a text style first. Again there's not really going to
be any Blueprint scripting here, so we can get rid
of the event graph. So basically I'm going
to make a standard UMG widget for a second, just for
the sake of showing you here what is going on with this. And I'm going to drop a
standard text widget in. And you can see that it's got
an Appearance section here in the Details panel with Color
and Opacity, Font, Strike Brush, shadows, and all that sort of stuff. What Common UI does
with the styling asset is it breaks all of the stuff
in the Appearance section out into a separate asset. So we'll set our Font Family. By the way, when you first
load up Unreal Engine, you might click on the Font Family
dropdown and see nothing here. If that's the case,
then you click this gear and-- actually not here, but rather
down here in the content browser. And you want to add
Show Engine Content. Show Engine Content
will make it visible-- will make all the font
options visible here. So I'll just pick-- I'll go against the grain
and go with DroidSansMono. Make it 16. We don't want it to be too big. Set to white. Let's see. And there's an outline, so I'll
give it like a two pixel outline. Make sure it's set to black. Check the alpha. Looks good. And that's going to be my
text style for all the text I'm going to stick in a menu. You might come up with
many text styles actually. You might come up with
a text style for menus, a text style for different headers,
a text style for the game title. There's a lot of different
ways you could do this. Or you could do an image for
the game title for all I know. But however you want to
break it up is valid. And now to show you how the
Common UI text widget works. If I look in the Palette for
all of the Common Text stuff, you'll notice there's
Common Date Time Text Block, Common Numeric Text Block,
Common Rich Text Block, and Common Text. These all automatically handle-- these two automatically handle
date and time and numbers only kind of functionality. Common Rich Text Block gives you access to doing rich
text formatting. And the Common Text just
makes it so that you can-- it's just the Common UI
version of a text block. So if I go in here,
you'll notice that there is no-- well, there is an appearance
here, and we could override this with whatever we would like. But instead we can plug
in the style and the style will take precedence instead. So now it's got a Droid Sans
Mono and the black outline on it. And we can make things even
more convenient with ourselves for ourselves, sorry,
tripping over my words here, by going into Project Settings,
scrolling down to Plugins, Common UI Editor,
and for the Template Text Style we set the generic menu text.
For the Template Button Style,
the generic button and for the Template Border
Style, the generic border. And basically when we
make new widgets that fit these descriptions,
either new text widgets, new button widgets, or new border widgets
within Common UIs set for these, they will automatically have the
style applied when you create them. So we're going to hop back into
our TestUserWidget for a second. Delete this. Grab the Common Text. Pop it in. And as you can see, it already
has Droid Sans Mono applied. So if there is a style
that you're going to use for the majority of your
game, that just automatically will apply it for you. No need to do to the busywork. And I think there should be-- I feel like I remember
there being another one. Numeric text, rich text. My mistake. I thought that there
was an editable text. But I think that
might be a C++ class that you have to extend and add a bunch of your own stuff to. I don't know. I could be remembering wrong. But in the meantime,
that will give you an idea of what styling assets are doing. But now without further ado,
let's actually get to building a UI. You've waited this long
just seeing me do setup. Now it's time for actually
creating some user interfaces. And instead of using the
normal workflow where I go to User Interface and
click Widget Blueprint, that will create a user widget. I want to create a
different type of widget. So I'm going to go
to Blueprint Class. And you can see there are
Common UI widget classes. The one I want is
CommonActivatableWidget. And what we're going to make here is
a container for our user interface where we can add and
remove different elements. So what I need here is
actually the overlay. And you'll notice I'm not
putting a canvas here. Here's a general UMG tip that a
lot of people are not aware of. You should be using canvas widgets
as little as humanly possible. It used to be that when
you made a user widget a canvas would be added by default
to the hierarchy over here. The problem being that what people
would do is they would make-- every menu would
have a canvas widget. Every button that they made,
every custom UI element they made would have a canvas widget. And they would arrange it WYSIWYG
style inside of that canvas. And the problem is that gets really,
really computationally expensive. You just eat up CPU doing that. And before you know
it, you just have this terrible performance drain. One of the things if you've
done that in your project that you can do to quickly
get a lot of performance back is actually go back and try to
eliminate the use of canvas widgets as much as humanly
possible from your project. So I'm going to minimize
my use of canvas widgets. Instead I'm going to
start with an overlay. Overlay just lets you stack a
bunch of stuff inside of it. So images, buttons, whatever. They will just render on top of
each other in a certain order. And I'm going to put a Common
Activatable Widget Stack in here. The common activatable widget
stack is a special type of widget that basically lets you build a
menu stack, for lack of a better way of explaining it. It makes it so that if you're
not aware of how a stack works, you add things into
it in a specific way. It's like a list that you add
things into in a specific way. First you push one
object into the stack. Then you push another
one and it goes on top. And then another one on top of
that, another one on top of that. And then you can also pop
things from the stack. And that removes the topmost
item and brings you back down to the next element. And so you pop things until
you get back to nothing, and that's basically
how a stack works. The thing on top is the
thing that is most important and that you most want to use. There is also a Common
Activatable Widget Queue. But I think you're a little
bit less likely to use that. That's a situation where when
you want to pop something off of it instead of popping
the topmost item, it will pop the bottom most item. But basically, I'm going to
use an activatable widget stack as my menu stack. And whenever I summon a new menu,
I'm going to put it in there. And I'm going to set the Horizontal
Alignment and Vertical Alignment to fill the entire screen. And that's basically
going to be it for that. And I notice that those
are under Uncategorized. Yeah, there's a couple of them
here that are not categorized, including the Common Video Player. I'm going to add another Common
Activatable Widget Stack into this. And I'm going to call
it 'PromptStack'. This is going to be a separate
stack for overlayed prompts. Because what it will tend to do is
when you push a menu onto the stack, the stack will want to
hide the previous menu until it becomes the top item
again, until it becomes active. So we have this separate
stack sideways of it for when we want to overlay any kind
of modal element like a context menu or a pop up prompt. And we're going to do that quick
little yes no prompt for this. So now we need a couple
of methods that we can access to actually use these. I'm going to make a
couple of custom events. 'Push Menu'. 'Push Prompt'. And what that will do is it
will act as our kind of gateway for pushing things
onto these two stacks. They're just kind of
convenient wrapper functions. Now, there's not a whole lot we
can do to this without actually having menus to push. So we're actually going to come
back to this in a little bit. But for right now this is going
to be the container for our UIs. We are going to push and pop
menus from the stacks in here, and that's going to
be how we organize it. Now we're going to make
an activatable widget for our main menu. And the reason we're
using activatable widgets is these have the ability to
be activated and deactivated without being shown it hidden. And you can customize the
functionality of these when they are activated and deactivated. Base UMG widgets don't necessarily
have that functionality already. You have to end up creating
your own system for them. But activatable widgets
in Common UI do have that. And in fact, the menu stack
system that we're using is going to automatically use that. Basically whatever the top
element is in our menu stack, if we deactivate it,
it will assume that we want to remove it from
the stack and go back down to the last item in the stack. So that's going to
just automatically handle our menu
organization for us. If you look in Lyra, it works
very, very similar there except there's a whole bunch of C++
functions built for pushing and popping from the stack. Those are following
somewhat better practices than what I'm going to be
showing you here in Blueprint just because it makes it
more convenient and probably just a little bit safer. But I think the way that we
put this together is going to work out fine for our purposes. But anyhow,
so we've got a main menu class and now we also need a button class. Because you'll notice if we go
over here into the UI designer, there is no Common
UI button element. There's just the regular UMG button. And that is not going to
work for our purposes. In fact, the Common UI button
class is very different from this. See CommonButtonStyle,
CommonButtonBase, and CommonBoundActionButton. CommonButtonBase is what
we're going to use for this. And when you open it up,
you'll see that the stage here is just completely blank. There is nothing in it whatsoever. And it's kind of a
mystery on first glance exactly how you're
supposed to work with this. All you have to do is
drop a container in here. So we will drop an overlay in. And now it's going to
fetch I believe our-- it doesn't pick up our button style
right away, but we can plug it in. And then it will pick
up our button style. And just to make things a
little more interesting, I actually forgot to configure
the button style, I'm realizing. Got a little ahead of myself there. You can see that the
button style encompasses a lot more than just the normal
hovered and pressed states. It also encompasses
sounds and text styles for any text that's
embedded into this widget. I think there's a little
bit of extra setup you have to do to get
the text styles working. Like, you have to
register them at the C++ level or
something like that. At least the examples that
I saw worked that way. So we're not going to
be getting into this. We're just going to fall back on
the built-in text style for the text that we stick in. But you can see it's got a pressed
sound, a disabled sound for error presses and all that sort of thing. And it makes it very,
very easy to set up these common kinds of feedback
that on screen buttons usually respond to. But we're going to keep
things kind of simple here. We're going to use I
think a really sickly looking '70s computer
beige for our normal color. In fact, we're going to make
it a little bit darker there. For hovered,
I'm going to make it bright yellow. And then for pressed, I'm going
to make it a very, very dark blue. And there's not any specific
rhyme or reason for this other than just to make them
different and recognizable. One thing that is a good
practice for accessibility sake is you should make sure
between each of these that you're not just
varying your color but also the tone, the value for it. Because oftentimes colorblind
people are going off of whether it's lighter or darker
as opposed to what color it is. So that can help people out a lot
if you take that into consideration. I don't know that this is
actually colorblind safe, but I just wanted to bring that
up as a kind of a little aside. And I'll also use a really dark
gray for the disabled state. You'll notice that there's a
state called Selected here. If I go into the
button, compile it, you can see that the style
took over here and now I've got the sickly '70s
computer beige color. But to explain what Selected
means, there is a Selectable property
for Common UI buttons. Basically what this does is it's
used for radio buttons and toggle switches. So if you need to do a
checkbox or something, this is what you would use. And then you could have
states specific to whether it is selected as well as whether
or not it's just unselected. We're not going to
be using this today, but I just wanted to bring up. That's what this means. This doesn't refer to whether or
not you have your mouse over it or whether it's got focus
with your controller. It refers to whether or not
you have a checkbox checked or whatever you want this to mean. So the Common UI button
class, as you can see,
is a lot more customizable and is leaving a lot
of things to the user, whereas the regular
button class for UMG basically has a lot more
things prescribed for you. But as you can see, just dropping
any container widget in here will put the background that we set
in that button style right on there for us and we don't
have to add it manually. One other thing. It's probably good
practice to use images for this kind of thing
instead of tints. This is just a really quick
demo, so I'm just using colors to do this just as
a quick way of getting it done. But you can also if you really,
really want to use a single material and override whatever the heck
you want with a Blueprint script if you feel like it. So there's a lot of
flexibility here. In Lyra I believe that the buttons
are using a transparent button style that all it is just
no inherent material to it. It's just got the
alpha all the way down. So that it's got a button
style applied to it, but otherwise it leaves
everything up to other materials that are part of the button
image and things like that. I might be misremembering
a little bit. The images might be part
of these states here. But I don't have the
ability to go look at it just now because I closed Lyra
for the sake of saving my computer. But anyhow, so now we're going to
switch this over from full screen to custom. And we're going to set the Width to
250 and the Height to, let's say, 60. And then we will put
some Common UI text. We'll center it. It's already got our
style applied to it. And now we just need to make a
method for setting the button text. So we head over to our graph. Add a Text variable. So this is another UI thing. There are three ways of representing
text information in Unreal Engine. There is Name, which is
basically a constant string, a constant character string. There is String,
which is a dynamic string. And then there's Text,
which is localized text. There is a localization system
built into Unreal Engine. Not even a Common UI feature. This is part of base Unreal Engine. Maybe I could actually bring
up the localization window. Question mark. I can't remember where
exactly it's located. There might be a table asset that
I'm supposed to put together. Been a while since I've touched it. Let me see. Miscellaneous. Trying to remember. Oh, there's actually a shortcut
for input action data tables now. I didn't even need to
use data table here. I could just have done that. Live and learn. Let me see. Well, localization is a
little out of scope here. I've got to remember where
exactly it's located. It's just been a really long
time since I've had to use it. But basically, you can set up a
localization table and bind any-- hold on a moment. Any of these text variables or
any text fields using this flag. In fact, that might actually
be-- hold on a moment. Go ahead and click it. Yeah, OK. No string tables available. So that probably means that we
need to create a data table. Not quite. Now I'm on a warpath and I have
to figure out where this is. Do we have any questions or comments
that you want to read, Tina? TINA WISDOM: Sure. It does also seem
like in chat they're saying it's under Tools and
then Localization Dashboard. MICHAEL PRINKE: Aha. Yeah it is. I had a feeling someone would know. TINA WISDOM: Thank you, chat. MICHAEL PRINKE: I had a feeling. Thank you chat. Thank you so much. I should know this, but I apologize. TINA WISDOM: There's so much. There's so much, it's so easy to
forget one little thing like that. MICHAEL PRINKE: Well,
it's kind of a big thing, but ideally you have to interact
with it relatively not too often. But yeah, this is where you
configure all of your text data tables for your game. I'm not going to fumble
around with this anymore. But that's where you can find
these using this little flag and then you pick the data table
or the string table, rather, and it will automatically assign
a key as part of a key value pair. And then it will substitute the
text for the appropriate text in the data table for the
culture that you're using. So you'll have an entry
for the Arabic version or the Spanish version
and so on and so forth, as well as the English
version, which is-- for me, that will be the default.
And then it'll just automatically
handle that for you. That is why you want to use
text as your variable type for these kinds of things. It will give you throughput
to the localization system. Whereas if you use string or
name, it's going to be a problem when
you later have to refactor it to fetch the localized text. So I'm going to make a
button text variable. I'm going to expose it. And then on pre-construct,
I will apply that. Set my displayed text. Going to take my text block
and set it as a variable here. Whoops. Didn't want to do set. Get SetText. And then it will fetch
my button text here. Whatever text I enter
in for the button is what's going to show up instead
of just some static string that's automatically set here. So if I want to put in
something, you can see it's changed it automatically
because I'm using pre-construct. You could do that on construct as
well, but if you use pre-construct, it will update for the editor. And now I'll set a minimum
width and height just to make sure that this button
takes on the dimensions that I want when I'm
constructing my menu. And now we have a button. I probably made that look more
complicated than it actually is. But it basically boils down to
drop your style asset in, drop in a container, set your
dimensions up here, and then if you feel like it, add other
things to customize the widget, like embedded text or
other kinds of elements for adding additional feedback. If you want a button
here to tell people, hey, there's a button shortcut,
then that's also something that you could do. All right. So now I'm going to go to my main
menu, which currently is empty. And I'm going to do
the same thing where I'm going to drop an
overlay and a vertical box. And then I'm going
to put my buttons. I'm going to use UI Generic Button. And put in four of them. Oops. Put that under the right parent. I will add a spacer down here. Let's see. I ought to be able to set the height
for this thing in a certain way. There we go. That's what I needed. Set the Vertical Alignment to fill. I will set the Horizontal
Alignment to align left because I want to make a left aligned menu. I could set it to be
centered if I felt like it and have a menu in the
center of the screen. But just to keep the
middle of the screen clear for prompts and other things,
I'm just going to put it there. Set the spacer so that
the y dimension is-- actually why isn't
this filling vertically the way that I expect it to? Seem to remember it-- There we go. I didn't actually
have it set to fill. I was looking at maybe a
different element there. But that'll push that one
all the way to the bottom, because that's going
to be a Quit button. And I'll put another spacer in just
to add a little bit of padding. 20 pixels. Why not? One more at the top. At the top. There we go. TINA WISDOM: You just have
to say it aggressively enough and then it work. MICHAEL PRINKE: Yes, everybody
knows if you yell at your computer. They have ears. They know what you're saying. In this case,
it kind of does have ears. I do have a microphone. So I am kind of yelling at the-- OK, enough of that rabbit hole. TINA WISDOM: It's true. MICHAEL PRINKE: I will
make this 'New Game'. 'Continue'. 'Options'. And call that one 'Quit Game'. And then just to make this
a little more attractive, I'll give them all a bottom
padding of like four pixels just so that there's a little
bit of extra space between them. I'm not being super precise about
the numbers that I'm picking here. But if I'm making a quick mock
up, this is the kind of thing that I would be doing. Give them names. And there we have it. We've got our UI with our buttons. And one last thing that I
feel like I want to do here is I'm going to take
this vertical box and I will hit Wrap With...
> Common Border. And once again, I actually
forgot to set up the border style with what I want. The border style is really simple. It's just an image, a tint,
and all that sort of stuff. It's a very straightforward
thing to set up. I'm going to make
it a dull blue here. Or you know what? Maybe I want to stick
with that computer theme. Make it like brownish beige. I could get like a wood
texture and have wood paneling and then go really old school. But I won't subject
you guys to that. I think you're suffering enough
looking at these colors as is. And I'm kind of not terribly
happy with that contrast. I will take this a
little closer to orange. And I will also saturate
it a little more and then also darken it a bit more
and make it more of a richer brown. Compile it. There we go. It's not quite right,
but there you go. Now it's got a background to it. And now we can start adding
some of the functionality that we want to be able
to show this thing. My setup here is
going to be a little more complicated
than the usual "just add it to the viewport in the
player controller" kind of method. But bear with me. So I'm actually going to make
a player controller called 'FrontEndPlayerController'. There's a few ways,
there's a few places you could go to control your UI. Player controller is
one because the UI is added to the viewport of
a specific player controller. So that's where I tend
to prefer putting it. But you could be keeping
track of it in a game mode. You could be keeping track of
it in lots of different places. But here I'm just going to
use the player controller. It all depends on what the
needs for your game are and what most helps the
functionality that you want. People often get overwhelmed looking
at the gameplay framework and all of the places where
functionality can live. And they ask themselves, oh God,
where do I put the scoreboard or what do I attach
the ability system to? Do I put it on the character or do
I put it on the player controller? There isn't a wrong
answer except the way that makes
your game not work. It all depends on the specifics
of what you need your game to do. In my case, a player controller
specific to the front end screen is going to do just fine. So, Create Widget. We'll do UI_Base. And we'll use Self
as the Owning Player. And now UI_Base. Push Menu to add
our main menu to it. Now let me see. Let's double check this for a
moment to make sure that this is something that can work. Yep, it looks like it. There's not a whole
lot that I need to do. I could do a get to fetch the stack
and just push the menu that way. But it's better to have a controlled
path for doing this kind of stuff. So one thing that I could do to
make this even more controlled is actually have a base menu class
that has all of my common menu functionality throughout my game. And basically restrict this
function to only accepting rather than common action widget,
it could use the base menu widget that I create. And then I can only pick menus when
I use the Push Menu function here. But for right now,
this will do fine. We'll just push an activatable
widget and that'll work OK. So now-- one last thing. Of course. Add to Viewport. And now we don't actually have that
player controller set to be used. So we need to go back
to our Blueprints and just quickly create a game mode. 'FrontEndGameMode'. And set the Player Controller
Class to FrontEndPlayerController. And then GameMode Override. For our map,
we will set to FrontEndGameMode. And then that is all settled. And when I hit Play,
it should show up. And there it is. We've got our menu. And lo and behold,
if I mouse over it, all these buttons will take on
the hovered style and everything. Now, that is hardly revolutionary. That's not necessarily
the cool part. It is cool that we have
a menu stack system here. But we want to actually
show it working and show the kind of
convenience that this adds. So we're going to go back
to our UI for a moment. First off, let's get the UI
focus going for the game pad. When I activate this
widget, activated is going to happen
automatically when this gets pushed onto the stack. So that's one of the features
of the activatable widget stack is it assumes that
the top widget on the stack wants to be activated. So you push it on,
it activates, and then it will run the On Activated code. So what I'm going to do
with this is Set Focus. And there is a function called
Get Desired Focus Target. I'm going to plug that in. Now, you've probably
seen this looking at-- if you've dug into Lyra,
this is how they're doing it. But the thing you probably don't
know is that if you try to use it, you'll get an error where it says
it's not getting a return value. That's because this is
an overridable function. You need to actually make
an override and tell it how you want to decide what
the desired focus target is. And you can put any logic
in here that you want. I'm going to use
the New Game button. If I wanted to, I could decide
to use the Continue button. Like if I detect a save file,
I could decide to use that one. If there's no save
file, do new game. I could have a focus
context enum that I set for this so that if I navigate
away from it with the quit menu, I could tell it go
back to the quit menu. There's a lot of things that
I could do with this other than just focusing
the New Game button. But I'm going to pick
focusing the New Game button. So now hit Play and I can see
that if I use the keyboard, it's going to give me this blue
outline here for the widget focus. But if I use my
gamepad, it will give me the actual hovering functionality. And I can use the
Confirm button here. The Back button. B. That's not going to do anything
right now because this is not a back button handler. And it's not going to be,
because it's the base level menu. If I get rid of it, I will just
be looking at a black screen. But I'll show you how to do that
when we get through the prompt. So let's see here. Yeah. So that's how you get-- that's how you handle the Get
Desired Focus Target function. But let's take a moment
to address a couple of other bits of functionality here
that might be a little frustrating. So as you can see,
this has not immediately focused the New Game button
the way that I want it to. It's kind of showing me the
wrong feedback initially compared to what I expect. That is because I have mouse and
keyboard set as my default input type for Windows. So it assumes I want to
use the mouse to click on things instead of using the
arrow keys or the gamepad buttons. So what we have to do
is we have to find-- let's see here. Was that in framework or was
that under Common Input Settings under Game? Yeah,
Common Input Settings for Game. Let's set the Default Input
Type for Windows to Gamepad. And now you see it is actually
showing the highlight straight off. And it will keep that highlight
until I use the mouse. The keyboard is still doing that
kind of blue outline thing, which is a little not quite what I want. I've actually been kind of racking
my brain trying to figure out exactly how to make the
keyboard buttons behave like gamepad buttons
in this instance. Does anybody in chat actually
know the answer to that? TINA WISDOM: It's a great question. We're going to flip it on you, chat. We're asking you the questions now. [LAUGHTER] MICHAEL PRINKE: I think it's
something that you can do at least. But I haven't decoded
it necessarily. I mean, the place you really
need it is with the gamepad. If you're using mouse and
keyboard, I think typically people would
be using a mouse, but just in case you want to
support just keyboard input, it seems like you'd want this
to be a little more accessible. If nobody's coming
up with an answer, then I'll probably
get back to you on the forums when I do
have this figured out. TINA WISDOM: No answers yet. Although some of them
missed the question. So if you want to ask again,
they might be able to pop in there. MICHAEL PRINKE: So I will ask again. So I've got my gamepad here. And when I'm using that
as the input method for scrolling through this
menu, it correctly highlights it as if
I'm mousing over it. But if I use my keyboard, it leaves
that display alone and instead highlights it with
this blue outline here, which it is actually telling you
what the keyboard is focused on. But that really isn't
the functionality I want. I want the keyboard to behave just
like the buttons on the gamepad. Does anybody know what needs to
happen in order for that to work? TINA WISDOM: We'll give
them a minute to type it up. Whoever gets it first is the winner. I don't what you win yet. I'll figure something out. MICHAEL PRINKE: Let's go to Engine
> User Interface here for a minute. Because that has a lot of
settings for how widgets are going to behave with
respect to navigation. Render Focus Rule. This is what does that blue outline. So if you never want the-- if you never want this to
show, then now you see when we go back here,
if I set it to Never, then the only highlight
I get is the highlight that I put there with
the hovered state. So there isn't a blue outline. There never will be a blue outline. Downside, the keyboard now
doesn't have anything telling you how it's navigating. But depending on the game you're
making, that might not matter. I don't know. But let's leave that for now
and get back to building our UI. So now we've got our focus set to
a button when this thing opens up. Another thing to caveat here. If you do use the mouse, it might
take focus away from the menu and you might be stuck until
you click on one of these or highlight one of these. Yeah, highlighting one will restore
focus if you're using the mouse. But that's another
feature that is a little-- I wonder. So I know that there is a method
to disable the mouse completely. Let's see. Set Consume Pointer Input. No. I haven't had to disable the
pointer input for a long time. That's another thing
that I'm rusty on here. TINA WISDOM: We're
all learning together. MICHAEL PRINKE: I wonder if that
would just solve the problem. But we're going down another
problem-solving rabbit hole here. And I want to show you this prompt
and a couple of the other features. So let's go ahead
and make our prompt. It's going to be another
activatable widget. And this is going to be
basically for a yes no prompt. So let's do an overlay. We haven't used a single canvas yet. Not one. And let me think. I think I need a
vertical box for this. I'll align it in the
center of the screen. Yeah, nothing to control the width. It scales to content. So now let's do-- let's throw in a common border. We'll set the-- oh, the style
is automatically set there. And the text. We'll call that 'PromptText'. Right. UI Generic Button. And actually we need a
horizontal box for it. So we drop that
below the PromptText. Whoops. I put the border in the wrong spot. Actually maybe I can salvage this. Hang on. Wrap it with yet
another vertical box. Not doing quite what
I'm expecting it to. But we'll drop the
horizontal box in there. I might need to rearrange
how I'm laying this out. Now we throw the UI Generic
Button under the horizontal box. And again. That's a 'No'. Throw in a spacer. Let's make it a little more
generous with the spacing there. Whoops. That is much too large. But I wonder if that'll
help us get to what we want a little more easily. Transform. Nah, doesn't look like it. OK. Overlay, vertical box,
centered, common border. Getting closer. I'm not by any means an
expert at layouts here. Stick that in the
vertical box there. Fill. Stick that in the
vertical box again. Now that's at the bottom. Fill. And now it's actually in
the center of the screen roughly where I would like it. I think I can find a better
way of laying it out like this, but that's just a really
quick, straightforward way of getting a box that's centered. We need to do a lot
of the same things with this as we did with our menu. We need to-- let's Get
Desired Focus Target. I need to actually name
these buttons for starters. Focus that. And back to the Event Graph. Do an On Activated event. Get Desired Focus Target. Now when we open it,
it will highlight the Yes button. And what else do we need to do? We need a method for setting
the information for this prompt. So I will send it the prompt text. And then this is a place
where C++ would come in handy. The way that you would want
to create something like this is actually to send a
delegate through and bind it in here through this kind
of set info function. And then you'd be able to set an
event in the base menu as something that you could fire
off instead of what I'm about to do here,
which is going to be a little bit-- well-- Yeah, I'll just do it the
way that I know works. We're going to add a couple
of variables to this. One for the prompt owner. And that's going to be
an activatable widget. Then one for the
integer-- an integer value that is going to be
the prompt index. And I will store the prompt
index so that it knows what function it's going to fire off. So what basically is going to happen
is when we call out the prompt, we're going to call this
SetPromptInfo function here. And we're going to tell it the
text that we want to display when we summon up the prompt. And then we are going to also tell
it which menu owns the prompt. And then we're going
to give it an index. And then when we go back
to trigger the function for confirming the
prompt, let's see, YesButton On Button
Base Clicked. What we do is take the owner. And we are just going to call
a special function in here. Although actually I've
done a silly thing. I should actually not be using
activatable widget for this. I should be using my main menu here. I could solve this
by using an interface or by creating a base menu class
and using that as the prompt owner instead of what I'm doing here. I'm kind of taking a few too many
shortcuts, if I'm being honest. But set the prompt owner. Then let's go back to the main menu. Go back to its Event Graph. 'TriggerPromptAction'. Or let's call it 'OnPromptConfirm'. And we will add an index value here. And what this will do is-- so if your menu has multiple
different things that prompt could potentially
do, like there's a Quit button, Apply Settings,
that sort of thing, and all of them are set to a generic
prompt like this, one shortcut around doing
delegates and things like that is-- I'm getting all muddled up. Using an index like this to tell it
which function it's supposed to use. So we're going to say that this
one will be the Quit Game function. So basically,
it will open the prompt. Ask if we want to confirm. It will send this index value 0 as
the function that we want to use. And then it will quit the game. And if we did apply settings and set
that index to 1, we could do that. You could do this
with an enum as well, but that would assume that you have
specific names you want for these. This isn't the most
elegant way of doing this. The most elegant way of doing
this is passing a delegate and just forgetting these
two variables all together. But it's a little bit iffy trying
to do that through Blueprint. They've got event dispatchers
and I can bind dispatchers. I wonder if there's a specific
pattern with event dispatchers I could use here. But it's definitely one of those
things that's easier in C++ where you can just say the confirm prompt
function or the confirm quit prompt function, like specific functions
for your prompt to trigger, that's the one that I want
to pass as a parameter here. Although actually
maybe we can cheat. Let's see if we can cheat. Now let's see. I need to get the player controller. Get the owning player
controller, rather. Cast this to my
front end controller. So now I've got access
to its functions. And nope. No super easy way of doing
that function signature. The cheat I'm thinking of is-- no, it doesn't work. Never mind. Sometimes if you click and drag this
onto a function or onto an event, it will actually take
this as a parameter. Like as an input parameter
or an output parameter. Unfortunately, I don't really
have that option by default and there's probably a really
good reason why you don't do that. So for right now my method
with the owning menu and index is going to be how this works. So we set that. We want to set the prompt
text, which I need to set here
as a variable. With so many tabs,
it's easy to get turned around. Set Text. 3:43 already, huh? We have been at it for a while. I hope everybody is hanging on OK. TINA WISDOM: Yeah, we've got
plenty of questions and stuff that have come in. MICHAEL PRINKE: Oh boy. TINA WISDOM: They're enjoying it. [LAUGHTER] MICHAEL PRINKE: All right. So SetPromptInfo. Now we'll do that. And then we will get the
prompt owner On Prompt Confirm. And we'll use this prompt index. And I'm going to do one more
thing with this prompt owner just to be on the safe side. Let's see. I'm actually going to make it a
Soft Object Reference instead. And I'm going to see. Check if it's valid before
I try to confirm the prompt. In case this thing gets
nulled out or in case like this prompt gets
destroyed, I really, really don't want to have an invalid
hard reference sitting around. OK, so click the button
on prompt confirm. Prompt confirm goes here. That quits the game with function 1. And now we just have to
actually summon up this prompt. So I'm going to go back to UI_Base. I have a PushPrompt here. We need to add some
parameters to it. Prompt text. Prompt owner. And prompt index. Integer. Getting all my names mixed up. It's main menu. UI Main Menu. There we go. And it will return this widget. It's only going to return a
common activatable widget. It's not going to return the
specific-- oh, actually it might. Hang on. Nope, just activatable. Oh no,
it's returning generic prompt. OK, that's good. Set Prompt Info. I seem to recall there being a
problem where I had to cast it, but maybe I was hallucinating
or maybe I hadn't compiled yet. So that will set the prompt info. And then when we go
over to our prompt, already setting the
focus to the Yes button. So we should be good
to go with this thing. We just have to actually
push this prompt. Let's go back to the
player controller. And make one more wrapper function. I'm just going to
copy this signature wholesale because I'm lazy. And where is my right? I'm in the controller. So I'll need to keep a
reference to my UI Base, which is the step that I forgot here. Now I can plug all this stuff in. And we have a completed
path to pushing this prompt. So that's kind of a more involved
tutorial than it seems at first just to make a simple yes no, but there's
just a lot of connective tissue that you have to navigate around. Now what I think we do is we hit
Play and just click Quit Game. Did I actually forget to
hook up the Quit Game button? Yes I did. I did forget to hook up
the Quit Game button. Get Owning Player. And this will probably be the one
and only cast that we do here. Take this guy and Push Prompt. 'Do you really want to quit?' Prompt owner is this. And then the index is 0. So when we do the prompt
confirm, it'll follow this path. So now that should
probably make more sense than when I was trying to explain
it before I laid everything out. Now let's do it. And there we have it. Click Yes and it will quit. Perfect. And now let's actually get
the No button figured out. Head back to the No button. On Button Base Clicked. And all I want to do is
deactivate this widget. That's all I need to do. Well, maybe not quite
all I need to do. We'll see in a moment. Play, Quit Game,
No comes off the stack and then I can interact
with this again. All right. Now let's use the gamepad
focus here for a second and try out how it works with that. And we lose focus for the main menu. So we have to actually reset that. I think there is a-- so there is a feature for
activatable widgets for focus. I'm looking at the button. Make sure you have the right
thing selected here before you go looking for properties. So there is an Auto
Restore Focus feature here. And in all the time that
I spent trying to do this, I didn't manage to make it
work when I used this use case. And there might be a
good reason for that. It might be that that only works
when you're using the same stack and activating and deactivating
that way as opposed to this whole sideways
modal stack thing. But in the meantime, what we can
do is we can go back to the prompt and, well, actually probably want
to go back to UI_Base instead. And we will bind to the on
widget deactivated event. 'On Close Prompt'
[INAUDIBLE] what we call it. Go back to menu stack. Actually a little faster to find it
by just clicking Activatable Widget Stack, Get Active Widget. This will return the top
widget for the stack. Set Focus. Accept. Get Desired Focus Target. Could save a couple of steps by
having a reset focus function here. But this is my method for just
doing this really quickly. And probably one more thing we want
to do is check if this is valid. Oops. Context sensitive there. And then we can set the focus. So in case we're
closing the application, when we quit we're very likely to
lose whatever menu is on this stack. And that would mean that
it will try to set focus on something that doesn't exist
and it'll cause an exception. So let's do it one more time. Oops. And there is actually that exception I was talking about. That is not what we want. Is Valid. Could say-- oh, I'm plugging
in the wrong input object. I need the widget,
not the focus target in the widget. [LAUGHS] That's why that didn't work. All right. Focus here for the buttons. There we go. And now focus is restored. And quitting does not
cause an exception. More importantly, though,
if I try to use navigation to go over to the main
menu with my gamepad, it's not going to go over there. It's going to just stay
inside of this prompt instead of doing some undesirable behavior. I'm still able to noodle
around with this over here because it's the top of
the stack for its stack. But there are ways
that you can fix that. You can decide to make
the buttons all disabled. You can set-- this thing isn't
set all of them not focusable. Or disable the
visibility of this thing. Actually that's probably
the easiest way. So Visibility. Maybe set the Visibility to Not Hit
- Testable (Self Only). Quite a few ways that
you could do this. If I do things a little differently
for this and go back to the UI_Base. And let's say that instead
of using the prompt stack, I actually use the menu stack. So I'll show you the
difference in what happens. Hit Play. And you can see that it actually
fades out the previous menu and then brings in the new one. So it's got transitions built in. If I go to the widget stack
here-- the menu stack, and I take a look at its properties
in the Details panel in design mode, you can set the Transition Type
to a variety of different types. You can set the Transition
Curve Type for it. Let's see what Zoom ends up doing. That's kind of cool. That's kind of cool. But that's an even
safer way of making sure that your menus don't interfere
with each other is just letting the menu stack
totally disable the ones that are on the bottom. And everything is fairly
configurable in terms of what happens with this widget. If you just take a look
at the base details panel for activatable widgets,
there's a lot of different things that you can configure about
how they handle activation. Oh, Back Handler. That is one that I
wanted to show you. So I'm on the prompt text. Check for the Back Handler. And now instead of clicking
No, I'm actually going to hit the B
button, which I designated as my universal back button. And it doesn't work probably because
I messed something up somewhere. Let's try that again. Go to the Project Settings. And under Common Input
Settings, DemoGameInputData. Confirm and Cancel. Did I not set up input
action table correctly? Gamepad Face Button
Bottom is Confirm. Gamepad Face Button Right is Cancel. I wonder what I did wrong. Because if I hop over to the
other demo that I put together, hitting B will actually
cancel out like this because it is a back handler. So I've done something
off in the setup. UIDemoStream. Maybe something in the
settings for the prompt itself. Back Handler. Back Handler should be the
only thing that I need to do. I might be thinking about
this for a little while because there's a number of steps
between getting this thing ready and putting this together
that I could have missed. But in the meantime,
one thing to note is that when you are
using the stack widgets, you don't need to change any
of the activation settings and you don't need to change
any of the focus settings. If you're using these
activatable widgets raw, then there are times that you would
want to control whether or not they are focusable,
whether or not they should auto activate when you
add them to the viewport. Common UI doesn't assume that you
want to activate a widget when you add it to the viewport. It assumes that there's
some other logic that you're going to use to
activate it like having a transition animation play and then activating
at the end of the transition, for example. So that's just not turned on by
default. But with the stack system here, that's actually
automatically activating the widget that you put on
the top of the stack, which is why you don't have to do
any of these other pieces. Maybe, hmm--.
I forgot to check Is Modal. Is Modal is intended
for prompts and context menus and that sort of thing. And what it does is it tells Common
UI this widget should be the root widget that you're looking at for
input routing, no matter what. So whatever else is on the pile,
however else this is constructed, even if this is a child widget
for another activatable widget, this should be
considered the root node and everything else
should be ignored. So let's turn that on
because I forgot to do that. Go back to UI_Base. And actually use the
prompt stack for this again and see what ends up happening. So OK. Everything so far is fine. And nothing here that
I'm trying to do. I did manage to accidentally
activate the Quit Game button twice. Now, I did a couple of
things over in here. This is such a complicated
example that I've probably forgotten a number of steps
that I used in my practice run. Let's take a quick look here
at how this one's working. I actually still have
the mouse over thing. So, what I said about the sideways
stacks kind of thing still applies here even
with modal turned on. But anyhow. All right,
so that basically covers all of the stuff about
working with menu stacks and setting up this type of
functionality for a main menu. Obviously I can add all
sorts of layers to this. I can create another menu
for entering your name, for instance,
when I start a new game and push that onto
the menu stack. And it will do that nice
little transition there. The back handler,
that's actually really bugging me. That should just straight up work. Is Back Handler. Did I do something-- you know what? I think I know what it is. On Handle Back Action. Right. You can configure what happens
when you hit the Back button. I'm just going to tell it
deactivate this widget. And I think that's actually--
yep, that's what I needed to do. I actually had to override it and
tell it that's what I wanted to do. It didn't assume that I wanted
to just immediately deactivate the widget, which is probably a
good thing, because there might be a whole transition system
that you want to put in for animating your menu going out. And it would just
generally be better if it didn't assume
things and let you decide what functions
to call and what features to use when you do this. So apologies for my brain
fart as I figured that out. But eventually we did. So the last thing that
I want to show you is how to bind gamepad
buttons to on screen elements and get button icons working. So I'll actually just
use the main menu here, because it's got lots of
open space in the middle. And I will put
horizontal box in here. Actually I will wrap this
with a horizontal box. And I will get the
Common Action Widget. Go put that in the horizontal box. Not actually how I
wanted that to work. I want to actually wrap the
horizontal box around this. Horizontal box around the border
which contains the vertical box. And then Common Action Widget. Give these some padding. Align them to the top. And I'm not going to apply any
kind of material to these at all. These are basically
button icons here. That's what the Common
Action Widget is. You wouldn't
necessarily know that by the name,
but what it's referring to is an input action like what we set
up in our input action data table here. So when I click on one
of these guys, let's see. Where is that setting? Input Actions. We can assign which input
actions refer to this icon. And I'm just going to
use TabLeft and TabRight. That should give me the
Q or R keys or the LB RB buttons when I display this. There's Q and R since it
detects me using my mouse. And the shoulder buttons
are not showing up. Let's see if I bound
these incorrectly. There is the left shoulder. I might have done this wrong
in the gamepad controller data. Let's see. No, left and right
shoulder are both here. That's interesting. Gamepad Name - Generic. Oh, here's one of
those gotchas I think. So we're going to go to the
Common Input Settings again. And so you'll see under
the Controller Data here, there is a Default Gamepad Name. I've got it set to Windows. You actually need to
change it to Generic. Darn it. Every time I hit Control S,
it clears that field there. All right. So basically this gamepad
name for this platform under Windows, this gamepad name
has to match the gamepad name inside of the controller data asset. So when it says Gamepad Name
- Generic, and it's got this dropdown here, that's the name it has to be. Nothing else is going to work. So unintuitively,
you have to go that you can't name the gamepad yourself. You have to actually
name it "Generic" here in the Windows gamepad name entry and then it'll work. So now I go back to gamepad
and there they are, LB and RB, just as I expect to see them. If I press the keyboard, it will
pick up that I'm using the keyboard and use Q and R instead. And so that is basically
how you get those working. You can actually make the
functionality for this a little bit more interesting. Go back to the main
menu for a moment. Now let's say I actually
have a couple of buttons here and I know that I want the
LB and RB buttons to be a shortcut for those buttons
no matter what else the user is doing navigation wise. That is where the
CommonBoundActionButton comes in. Let's open this guy
up and we're going to do a bunch of the
same kinds of things that we did in our
normal button widget. Plug in a button style
and it's going to crash. It crashed. Any questions while I get it back? [LAUGHS] TINA WISDOM: Just
the nature of things. Yeah, actually,
if you're open to it, I think this could be
a good chance to hop into some of the questions we've
got, because there were a few that have stacked up along the way. MICHAEL PRINKE: OK, go ahead. I'll try my best to answer. TINA WISDOM: So one
of the first ones-- MICHAEL PRINKE: Sorry. TINA WISDOM: No
worries if you can't. No worries. We can just refer to documentation. MICHAEL PRINKE: Well, a lot of the
Common UI docs are in progress. So in a way, I'm learning right
along with everybody else. Go ahead. TINA WISDOM: Perfect. Does Common UI work in VR as well? MICHAEL PRINKE: VR is interesting. Let me get back to you on that. I think that the answer is yes but. Mainly you don't want to add your
UI to the screen the same way you would in a PC game. You want to have a three
dimensional UI that is rendered in front of the player. And to do that, you would add a-- let's just grab this cube here
for a moment and let's see. There should be a widget. Yeah. You add a widget component
in a 2 or 3D actor and that's where your UI lives is
I think how that ends up working. But otherwise there's no
reason that Common UI's functionality itself should
be any kind of a problem. It's all just UMG widgets
when you get down to it. It's just a layer that's
built on top of UMG. TINA WISDOM: Yeah, absolutely. Let me go through. There's a lot of these that we
kind of answered just organically going through the demo. MICHAEL PRINKE: I figured as much. It's a long demo. TINA WISDOM: Yeah. Lots of great information in
there, though, for sure. Actually we answered just
about all of these, truly. MICHAEL PRINKE: Yes. Victory is mine. [LAUGHS] I am only scratching the
surface of all of this though. This is by no means the-- there are so many
things I could be doing to handle the focus
for like menus that I've got in the background. There's ways that I
can set up transitions. There's all the widgets
that I didn't get around to. But let me make this bound
button widget here real quick. Slot. That's not what I wanted. I might have done
a silly thing here. OK, well, I know-- I actually think I know how
I can do this really quickly. Let's go back in. Delete these guys. And just use the UI Generic Button. Oops. So are there any other questions? There's got to be. You can't let me off that
easy, chat. [LAUGHS] TINA WISDOM: There were a lot. I'm just digging through
to see which ones aren't going to be too
repetitive with stuff that we've actually
walked through so far. MICHAEL PRINKE: So before I crash
again, I'm actually going to-- OK, so the base button,
the base Common UI button class actually has a triggering
input action built in. So you can decide that a button
uses tab left, for instance. And then you do need to
account for the icon. You do need to account
for an action widget like what I was showing you before
to get it to display properly. But whoops. I'm not in the front end. I wonder if somebody like
the next time I'm on here is going to keep like
a whoops counter. TINA WISDOM: We'll set something up. We'll just keep it in the
top corner or something. MICHAEL PRINKE: And
what should happen here is I use the On Button
Base Clicked event here. When I press RB,
it should say "Hello". Not quite. Action, action, action. So maybe it does need
to be a specific type. InputActionTable,
Triggering Input Action. That is bound to this button. "The common input manager will trigger this button to
click if the action was pressed." So it should pick up-- oh. Oh wait, yeah. That's why. It's tab left and I'm using the
RB button, not the LB button. There is nothing I can't
forget and still nada. So there's obviously some
setup here that I'm missing. I wonder what is going on here. Display Input Action
when Not Interactable. Should Use Fallback
Default Input Action. Click Method, Input Priority. Yeah, that should be it. That should be all I have to do. But maybe I should be using the
bound action button instead. Really like this to
work before I call it and just open the floor to
any questions and discussion. CommonBoundActionButton. Over here. Overlay. Plug in my button style
and watch it crash again. Dang it. TINA WISDOM: This is the curse. [LAUGHS] MICHAEL PRINKE: Some of
these are more stable. TINA WISDOM: It doesn't want us to. MICHAEL PRINKE: It's haunted. TINA WISDOM: Well, I do have
a couple more questions now. MICHAEL PRINKE: Go right ahead. TINA WISDOM: There's quite a few. Chat definitely came through and
there are some that have popped up. Unfortunately,
I don't think we're going to be able to answer all of them in time. So if there are any questions
that we don't get a chance to go through at the end
here, especially if they're very specific use
cases, please feel free to ask those questions in
the announcement post in the forums and we'll get back to you and
answer your questions there. So my apologies if we
can't handle it here live, but we will get back to
you on how to do some of those. But there is one that a lot
of people in the YouTube chat specifically are curious about,
and that would be setting up a search bar in the UI. MICHAEL PRINKE: A search bar. That is a complicated use case. So to break that down into the
steps that you would have to do, you will need some way
of indexing UI elements that you want to be
able to search through. And then you need to
have a search algorithm that you're going
to use to figure out which ones match the search term. And then as it matches search terms,
you update each of the widgets to hide ones that don't match. And that would be I would think how
you would handle that sort of thing. That's not a trivial example. It's not something I can just
show off the top of my head. I'd have to do some research on how
best to lay out widgets and cache them for the purpose of doing that. But that is a really good question. TINA WISDOM: Yeah. And I could see how that would be a
difficult one also to kind of answer without having an example for it. So that would be another one
that I would recommend go ahead and post that as well on the
announcement post for the show. And we'll see if we
can come back to you with maybe example images
or things like that. MICHAEL PRINKE: Now I
kind of want to try it. [LAUGHS] You got my brain going. I'll give you that. But I haven't put one
together in the past before, so I can't just tell you off the
top of my head how it'll work. Yeah. Let me take a quick
look at something here. I'm actually going to take a
look at the properties for this. Are there any tags? OK, let's go over to the
Event Graph, Class Settings. OK. So probably the best way to
account for the search terms is to add a gameplay tag
field onto the base version of every widget you're going to use. This is something
that they commonly do that you'll see in example projects. They will actually make a Lyra game
button widget, Lyra game background widget and all that. And instead of using the base
Common UI widgets like I was doing, they'll use their versions of it
with whatever extra functionality they want for UI management
in the background. In this instance, you'd probably
make a searchable widget container. It would be, let's see, are there
any specific containers here that-- nah, can't search it like that. Editor, Input, Lists. Panels here. Yeah, you'd probably override
one of these panels here. And say all right,
I'm going to make a special version of the overlay that is a searchable
object for my user interface. And then you would
add a variable to it. Let's see here. How do I add that variable? That's going to be-- oh, that's up here. I'm used to the variables
panel being down here. SearchTags. This is what you would use. You would use gameplay
tags to do it. And basically that
would make it so that you can say 'UI
Option Graphics'. Add that to the list. And now you see I've got this. Probably actually want
to use a gameplay tag container so that it can be-- but it can include multiple
different tags in this. So now I can tag up-- oops. Compile it. Text_ActionName. Common Text. I've messed something up. Delete the problem class here. There we go. So once more SearchTags. Gameplay Tag Container. Now gameplay Option > Graphics. And we can check as many
things as we want in here. Gameplay tags are a hierarchical
tag system that basically can be adapted to anything you like. The Gameplay Ability
System uses them a lot. But this is an instance
where you could probably use those as a really great way to
extend the metadata for widgets. So you have an overlay
widget that's got that. And then whatever you stick
inside of that overlay widget, that's going to be visible as long
as that overlay widget is visible. And so you could iterate
through your list of widgets and see if any of them match those
tags, if any of the search terms match those tags for each widget. And that would be kind
of a dumb brute force way of setting up that
metadata and telling it these are graphics options,
these are sound options, and so on and so forth. Off the top of my
head, I don't know what use case you're thinking
about using for it. But that is a way to do it. If it's a list of items
in your inventory, then you could instead of using
tags on the widget itself, you could have it draw the
widgets based on what's-- populates the widgets,
rather, in your list based on the items in your inventory. And then the items in your
inventory themselves can have search tags attached to them. And you would just filter
out widgets that are using-- that don't match the search
terms in the search tags when you repopulate your list. You'd be doing that programmatically
rather than dragging and dropping widgets is the thing. So that would probably--
that's one that I actually can think of how off the
top of my head to implement. But if you're looking to filter
out UI options themselves for a menu like this,
then you're going to have to do some
metadata tagging and you're going to need to keep a
list of all the widgets to iterate through
somehow or get a list to iterate through all the widgets. In fact, you can do that. You can Get All Widgets
Of Class and really quickly get a list of
all of those widgets and hide all the ones
that don't match. OK, so I kind of
answered the question. TINA WISDOM: Hey, I mean, that is
one of probably a bajillion ways to do something,
which I think is the beauty really ultimately of the Engine. MICHAEL PRINKE: Yes. There isn't really a wrong
way to do anything except for, A, a way that doesn't work or
B, a way that is extremely performance prohibitive. And then at that
point, it's up to you to profile it, figure out
what is the performance drain, and how to address it,
which may be a refactor or it may just be a simple fix. TINA WISDOM: Yeah, absolutely. Well, that was fun. I like being able to throw a
question of something together and we kind of just wing
it so we can figure it out. MICHAEL PRINKE: Sorry if I kind
of focused on that question at the expense of the others. But that's a theme with my questions
when I do this is I'm always like, well, I'm not sure. Actually, hmm. And then I kind of talk
through it and make it work. TINA WISDOM: Yeah, absolutely. Which is fun. And again, no worries
about the other questions. I know there are
some that we probably didn't have the chance to get to. But again, please feel free to
post them on the announcement post or in the forums. And we'll make sure that we
get to you with some answers to those questions. Unfortunately, since we are at
about two and a half hours here on the stream, we'll probably
want to call it here. Also just because I am
personally experiencing some pretty extreme weather
outside of my window here and my power is not the most stable. So we should make sure that we-- MICHAEL PRINKE: Are
you in North Carolina? Because I think I'm
experiencing similar weather. TINA WISDOM: It's that
time of year for sure. [LAUGHS] MICHAEL PRINKE: All
right, sorry to interrupt. Go ahead. TINA WISDOM: Yeah, no, no worries. I just wanted to take the time to
thank you, Michael, first of all, for taking the time
to come on the show and walk through all of this
incredible stuff with UI with us and to, first of all, also show
a lot of the troubleshooting that you were doing live. I think that's incredibly
valuable for people to be able to see and experience
and relate to as well. So thank you for that. But also I want to thank everybody
who came to watch the show as well. The show would not be what it is
without you and your participation. You came in handy many times today. So thank you, chat,
so much for your participation and for helping us find some stuff
in the many, many menus of Unreal, the ever expanding menus. [LAUGHS] MICHAEL PRINKE: Thank you Tina as
well for having me on the show. TINA WISDOM: Absolutely. It was such a pleasure
to have you on. And a lot of this, I'll admit,
UI is definitely one of the topics that I myself need to be
brushing up a lot more on. So there was a lot for me to learn
personally, which was a lot of fun. But yeah, with that,
again, thank you so much. I really appreciate it. We'll have to have you
come back on sometime so we can go even further
into it since there is such a huge plethora of knowledge
in just this section alone. MICHAEL PRINKE: I
could literally pick up where I left off
building an entire menu system for the main menu and
the options and everything. And it would probably take three
or four sessions to get through it. But I think as you can see,
it's a lot quicker with Common UI doing some of this
heavy lifting with you. These are features that you
would spend a week implementing by themselves and then
you'd be debugging them throughout the entire project. And they're just available
for you right off the bat. So hopefully this will encourage
people to start using this plugin. TINA WISDOM: Yeah, absolutely. Save you a little bit of time. Save you a couple of
headaches as well hopefully. And yeah, just dig in there. Experiment. See what boundaries you can push
and what cool stuff you can make. And then let us know
too, because it's always fun to see the end result
of things like that as well. But yeah, unless there
was anything in particular that you wanted to squeeze
in there real quick, Mike, I want to give you the chance. MICHAEL PRINKE: Nope. I think I'll leave it at that. This has been a long one. [LAUGHS] TINA WISDOM: But
it's been wonderful. It's been seriously a pleasure. And darn it, Unreal,
with its crashing and the joys of developing live, right? MICHAEL PRINKE: Brand spanking new
plugin, brand spanking new crashes. TINA WISDOM: Yeah. Always. Well, we'll figure it out as we go. So once again, thank you so
much for coming on the show. Thank you everyone for watching. Again, don't forget, we won't have
a show for the next two weeks. We'll be off on a short vacation. But we'll be right back to
the same schedule after that. So make sure you come back and
see us in three weeks' time. But also don't forget we
post all of our streams in video format that can be viewed
on demand on our YouTube and Twitch channel at Unreal Engine. And don't forget to keep up with us
@UnrealEngine on all social media, as well as say hi in our forums,
where you can get the latest news and also find all the links
associated with today's stream. But with that, thank you, everyone. Thank you so much. We will see you later. Bye. MICHAEL PRINKE: Take care.