Make ShowHUD actually show and hide your UMG HUD

Unreal has a console command "ShowHUD" which is supposed to toggle HUD visibility, but it's extremely legacy and only hides things that are drawn via code from the HUD, not your UMG Widgets.

This gist is a base class AHUD class that does the following

  1. Intercepts the ShowHUD command and toggles visibility of all of your UI
  2. Optionally hides the hid when you switch to simulate in PIE (Hit F8)

Main principle at work is to find the SPlayerLayer Widget, which is the root of all the UMG widgets you add to the player screen:

Overview of the main code, for reference. Full code in [the gist]

namespace RTMHUDBaseStatics
{
	SWidget* FindWidgetByTypeRecursive(SWidget* root, FName widgetType)
	{
		SWidget* ret = nullptr;
		root->GetChildren()->ForEachWidget([widgetType, &ret](SWidget& child)
		{
			if(!ret)
			{
				if(child.GetType() == widgetType)
					ret = &child;
				else
					ret = FindWidgetByTypeRecursive(&child, widgetType);
			}
		});

		return ret;
	}
}

void ARTMHUDBase::UpdateUIVisibility()
{
	const bool wantVisible = bShowHUD && !(bHideUIDuringSimulate && IsSimulatingInEditor());
	const EVisibility visibility = wantVisible ? EVisibility::SelfHitTestInvisible : EVisibility::Hidden;
	if(auto* playerLayerWidget = GetPlayerLayerWidget())
		playerLayerWidget->SetVisibility(visibility);
}

SWidget* ARTMHUDBase::GetPlayerLayerWidget() const
{
	const FName playerLayer("SPlayerLayer");

	// TODO - investigate if this works for local multiplayer, as it's unclear if this will find the Player Layer for this player, or the first one it finds
	const ULocalPlayer* localPlayer = Cast<ULocalPlayer>(PlayerOwner->Player);
	const UGameViewportClient* viewportClient = localPlayer ? localPlayer->ViewportClient.Get() : nullptr;
	auto viewportWidget = viewportClient ? viewportClient->GetGameViewportWidget() : TSharedPtr<SViewport>();

	return viewportWidget.IsValid() ? RTMHUDBaseStatics::FindWidgetByTypeRecursive(viewportWidget.Get(), playerLayer) : nullptr;
}
2 Likes