Skip to content

How the HUD, menus and saving fit together

Three things share this chapter and they barely touch each other. The HUD is a set of small widgets, each one owned by the system that needs it. The menus are one family of widgets driven by Data Assets. Saving is three SaveGame objects and one game instance that reads and writes them.

This page says which Blueprint owns which screen, what draws on top of what, and what you open when you want to change something. The pages after it do the work.

  • The widgets: Content/TheLastTemplate/Blueprints/Widgets/
  • The menu screens and rows: Content/TheLastTemplate/Blueprints/Widgets/Menu/
  • The menu pages: Content/TheLastTemplate/Blueprints/DataAssets/Widgets/Menu/Childs/
  • The save objects and the game instance: Content/TheLastTemplate/Blueprints/Misc/

There is no HUD Blueprint

The template has no AHUD class and no single widget that holds the play screen. Every element is its own widget, created by whoever needs it. That is why you can delete the ammo counter and the health ring never notices.

Widget Created by
BP_LifeCharacterWidget, BP_HitCharacterWidget, BP_AimWidget, BP_RadialWidget, BP_DeathScreenWidget, BP_SaveIndicatorWidget, BP_DevDebugHUD BP_PlayerCharacter, in Initialize Widgets
BP_AmmoCounterWidget BP_PlayerWeaponManager
BP_ThrowableWidget BP_PlayerThrowableManager
BP_InventoryWidget BP_PlayerInventoryManager
BP_InspectWidget, BP_InspectReadWidget BP_PlayerInspectManager
BP_PhotoModeWidget BP_PlayerPhotoModeManager
BP_WorkbenchWidget the BP_Workbench you place
BP_InteractWidget a Widget Component on every interactable
BP_TipWidget the BP_TipZone you place
BP_FinishWidget a Widget Component on BP_NPCCharacter and BP_ZombieCharacter
BP_NotificationWidget BFL_NotificationLibrary, from any graph
BP_LoadingScreenWidget BFL_LoadingLibrary
BP_PauseMenuWidget BP_PlayerCharacter, in Pause Game

Five of the widgets the character creates are class fields in its Details panel: BP Life Character Widget, BP Hit Character Widget, BP Aim Widget, BP Radial Widget and BP Death Character Widget. Point one of them at a child class of your own and the character builds yours instead.

What each element does and which fields are yours is on Change what the HUD shows.


The menu module

Every menu screen derives from BP_MenuScreenBaseWidget, which derives from BP_MenuBaseWidget. The base holds what all of them share: the click and hover sounds, access to the saved settings, and the whole save slot API, including Get Slot Count, Launch Slot, Delete Slot and Find Latest Slot Index. A screen of your own that derives from it gets all of that for free.

A screen is not a layout. It holds a BP_SettingsPageDataAsset, and Build Rows creates one row widget per entry in that asset's Rows array. Adding an option, a button or a whole page is filling in an array, which is why the same screen class, BP_MenuSettingsPageWidget, draws the audio, graphics, display, controls and language pages.

Three screens do their own thing because a list of rows cannot express them: BP_MenuLoadGameWidget lists save slots, BP_MenuBrightnessWidget is the calibration screen, and BP_MenuTitleScreenWidget is the press-any-key screen that BP_MenuPlayerController puts up when L_MainMenu opens.

How to add a page, a row type or an option is on Add or change a menu page.


What draws on top of what

Widgets are added to the viewport with a Z order, and the values in the template are spread far apart on purpose.

Z order What sits there
-1000 notifications, so they never cover anything
0 the play HUD, the inventory, the radial menu, photo mode, and every menu screen
5 the save indicator
100 the death screen
1000 the loading screen
50000 the inspect view
100000 the pause menu
100001 the confirm modal opened from the pause menu

Anything opened from the pause menu needs a Z order above 100000

The pause menu is added at 100000 while every other menu screen is added at 0. A modal you open from it at the default Z order draws behind it, and because the pause menu covers the screen it also swallows the clicks. It reads like a broken focus and it is not.


The three save objects

There are three SaveGame classes, and they are separate so that reading one never costs you the others.

Object Slot on disk What it holds
SG_MenuSettings TLT_MenuSettings every option the player set: Values, Text Values, Key Binds. One file for the whole game, shared by every slot.
SG_MenuProfileSlot TLT_Save_<n> the header the load screen reads: Display Name, Level Name, Play Seconds, Save Date, Slot Index, Used.
SG_TLTGameSave TLT_Save_<n>_Data the run itself: inventory, recipes, collectibles, skills, weapons, ammo, upgrades, throwables, vitals, the player transform and the per level state.

One slot is two files because of the load screen. It draws a row per slot with a name, a level and a play time, so it loads only the headers. The run itself is never deserialised until the player picks a slot.

Save Slot Prefix on BP_TLTGameInstance is the start of those names and the only place they are built. Change it and both files follow.


Who saves what

BP_TLTGameInstance does the file work and nothing else. It owns Save Game State, Load Game State, Save Checkpoint and Delete Game State, and it broadcasts On Save Started and On Game Saved, which is how the little save icon knows to appear without polling anything.

It does not know what a save contains. It asks the player character once, through Capture To Save and Restore From Save, and the character asks its own components in an order it decides. So a system you add goes into the character's Capture To Save, not into the game instance. That is on Save and load a game.

Level state is the other half and it works the other way round. Capture Level State and Apply Level State sweep every actor in the level that implements BPI_Saveable and store the result under the level name. Your actor never talks to the save manager, it just implements three functions. That is on Make your level objects remember what happened.


I want to change X, I open Y

I want to I open
Move or restyle something on the play screen the widget in Blueprints/Widgets/, see Change what the HUD shows
Change which glyph a key prompt draws DA_KeyPrompts, see Key icons and letting players rebind keys
Add an option, a button or a page to the menus the DA_Page_* asset, see Add or change a menu page
Change the level New Game opens BP_MainMenuWidget, see Maps, game modes and how the game starts
Change how many save slots there are Max Save Slot on BP_MenuBaseWidget
Change the names the save files get on disk Save Slot Prefix on BP_TLTGameInstance
Use a save class of my own Save Game Class on BP_TLTGameInstance
Put a checkpoint in a level a BP_SaveZone, and its Save Once field
Change how long the save icon stays up Hold Seconds, Fade Speed and Save Sound on BP_SaveIndicatorWidget
Make one of my actors survive a reload BPI_Saveable on that actor, see Make your level objects remember what happened
Ship the game in another language see Translate the game into another language

What is keyboard and mouse only today

Two honest limits, so you know what you are starting from.

IMC_Default maps no gamepad key, and the prompt icons that ship cover keyboard and mouse. The controls page rebinds keyboard keys. Nothing in the chain is keyboard specific, so a gamepad set is icons and mappings, not new Blueprints.

Menu rows draw their Label Key straight to the screen. The keys are written in dotted form, audio.overall and the like, so a localisation pass can pick them up, but the project ships no localisation data yet. A page you add reads its own keys on screen until the text is translated.



Join the Discord