Not quite over the covids, but I decided to ease back in and see how I get on.
Having had time to contemplate the scalability deep-dive from the other week, I've decided I need to do it properly, run the benchmark once, and record that I've done it.
To do this, I thought about starting my own save game class -- which I'll need down the road -- but realised there must be a way to extend the existing
UGameUserSettings stuff. There is, and property decorators enable some engine magic I wasn't aware of:
Indicates which of the config .ini files a class extends and
Automatically adds a member variable. The cool thing is that, although I've derived a class from
UGameUserSettings, you can, in fact, use these decorators in any class. Then, when
SaveSettings() is called, the decorated member vars are automatically output without further code implementation. Bingo bongo.
GameUserSettings.ini is output to one of three places depending on the type of build:
In your project: in
In development builds: in
In shipping builds: in
Open one up to verify everything's being saved correctly.
With that in place, I was able to change the game flow. Instead of loading directly into the main menu, I now load an empty map, which I'll use for the splash screens; you know, company logo, publisher logo, etc.
On Lumo, I used static images for the splashes, but I have a fancy logo for Triple Eh? so I needed to work out how to play full-screen video. If you look at the available plug-ins, there are a lot of Media Playback bits and pieces. I've enabled the Media IO Framework & Utilities and the Electra Player. You can try the windows media framework, but I couldn't get it to play back anything under a DX12 RHI. It's fine on DX11, though, so YMMV.
To get fullscreen video to work with the Electra Player, you need to have a Media File Source asset pointed to an H.264
.mp4 located in
./Content/Movies directory, else it won't be packaged. The Media Player can automatically output to a linked texture, which you use as the source to a UserInterface material. The material can be bound to an image in the UI editor.
My Level blueprint adds a UserWidget to the viewport that contains a full-screen quad bound to this material. The Widget has a custom event that rewinds and starts the media player; the rest is done by magic.
UE is sensitive to file IO -- compiling a billion shader variants doesn't come cheap -- so my DevRig has screaming fast NVMe drives, and they’re worth every penny. The downside: I'm always surprised when level loading isn't instant on my laptop, and now, my Steam Deck.
I side-stepped the issue of a loading screen in Lumo because, well, it's always a massive hack in Unity, so what's the point? Better to do something else. UE doesn't have that problem. Instead, it'll allow Slate to run asynchronously to the game thread, allowing images, throbbers, etc., to display as the load happens.
I've never touched Slate, so I had no idea how this worked. Fortunately, the ActionRPG example comes with a module:
ActionRPGLoadingScreen, that drops into projects to do the legwork. Not that there's very much of it. Three functions, essentially.
Although this made the Slate side reasonably trivial, it required me to change the entry to my levels. Interiors/Dungeons/Caves are simple; they all have a single point of entry in the Blueprint Library that I could use to hide the loading screen. Unfortunately, the streaming levels didn't. Here I was doing periodic polling in each level blueprint to conceal the visible streaming of Assets -- UE's incredibly aggressive at getting to interactive content -- and these checks were failing because the loading screen's visibility masked the level's.
It took me a little while to work this out (and numerous builds), but I think I'm there. It needs testing on the Deck, but I don't have the energy today.
I stumbled on something called
LightweightInstances, which looked ideal for many of the objects in my world. Essentially, it instances blueprint actors in a way analogous to mesh instancing. It's beta and not well documented, but I went through the examples I could find online and ... failed to get it to work—hard crash when converting any actor.
I wasted a while on that, which is a shame, but I'll check again when 5.1 is released. It’ll be super helpful when it works and hopefully reduce my tick count.
I spent the afternoon watching the "Introduction to Common UI" video Epic posted on YouTube. All three hours of it. I'm not going to redo my old, pure-UMG UI, but I think any new screens should use the new methodology. Tbh, having global widget styling is enough to convince me to use it.
Tentatively started to replace the current front-end menu with one built using
CommonUI. There's a fair amount of boilerplate to construct, but it all makes sense. Global text, button, and border styles are massive wins. I've taken a leaf out of Lyra's book and started using Materials for the button backgrounds. They're relatively basic right now -- just subtle gradients -- but I'll be able to get some animated stuff in there at some point, which will look cool. :)
Anyway, my first impressions of
CommonUI are very positive. I love the built-in transitions, and the stack system makes a lot of sense. It all feels like an immediate improvement over base UMG.