Skip to content

UI Widgets Without Event Graphs

The current UI rule is:

Widget Blueprint = layout
C++ widget class = behavior and data flow

The goal is not to avoid Blueprints entirely. The goal is to avoid maintained gameplay logic living in Widget Event Graphs.

The important widget classes are:

UAndromedaInteractPromptWidget
UAndromedaScanResultWidget
UAndromedaShiftResultWidget

BindWidgetOptional

Widget C++ classes use properties such as:

UPROPERTY(BlueprintReadOnly, meta=(BindWidgetOptional), Category="Andromeda|UI")
TObjectPtr<UTextBlock> ItemNameText;

BindWidgetOptional means:

If the Widget Blueprint has a Designer widget named ItemNameText
and it has a compatible type,
bind it to this C++ property.

If it does not exist,
do not fail construction.

This is useful during early UI iteration. The code can tolerate missing fields while the layout evolves.

The tradeoff is that a typo silently gives nullptr, so important widgets should be verified during testing.

Interact Prompt Widget

The prompt widget owns:

focused object reference
current prompt text
prompt visibility
text block update

The character calls:

InteractPromptWidget->SetPrompt(FocusedObject, PromptText);

or:

InteractPromptWidget->ClearPrompt();

The Widget Blueprint only needs the layout and correctly named widgets.

Scan Result Widget

The scan result widget is informational only.

It owns:

Scanner reference
FAndromedaScanResult
text population
Close button behavior

It does not own:

Sell
Quarantine
Assign Package
Shift result creation

Those were removed when the game moved to physical station handling.

Expected Designer bindings include:

ItemNameText
ManifestText
LegalRequirementText
RadiationText
MassText
SerialText
HazardText
PackageRequirementText
NotesText
CloseButton

When SetScanResult is called, the widget stores the struct and refreshes all text fields.

Close Button

The scan widget constructor marks the widget focusable:

SetIsFocusable(true);

NativeOnInitialized binds the close button:

if (CloseButton)
{
    CloseButton->OnClicked.AddDynamic(this, &ThisClass::HandleCloseClicked);
}

This binding existed before the Designer button existed because BindWidgetOptional allowed the C++ hook to be present early. Once a button named CloseButton was added to the Widget Blueprint, Unreal bound it automatically.

Closing the scan UI:

sets input mode back to game only
hides mouse cursor
unsuppresses interaction prompts
removes widget from viewport

Shift Result Widget

The shift result widget displays final processing results from warehouse zones.

It owns:

FAndromedaProcessingResult
result title text
payout text
consequence/result description text
Close button behavior

The warehouse zone creates it after placing a packaged item in a final zone.

Why No Event Graphs

There is nothing wrong with Blueprints for presentation and configuration. The current project preference is that maintained rules live in C++ so the logic is reviewable, searchable, diffable, and easier to refactor.

Blueprints still matter:

BP_PlayerCharacter assigns input and widget class references.
BP_Scanner assigns mesh and scan widget class.
WBP_ScanResult defines layout.
WBP_ShiftResult defines layout.
Data Assets define item content.

The split is not "C++ good, Blueprint bad." The split is:

C++ owns rules.
Blueprints own authored configuration and presentation.