Introduction to Common UI | Inside Unreal

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[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.
Info
Channel: Unreal Engine
Views: 122,617
Rating: undefined out of 5
Keywords: Unreal Engine, Epic Games, UE4, Unreal, Game Engine, Game Dev, Game Development
Id: TTB5y-03SnE
Channel Id: undefined
Length: 161min 30sec (9690 seconds)
Published: Thu Jul 21 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.