Appearance
Blueprint RTS commands and selection
Historical example recipe. The current UE5.8.3 Ironfront/Emberfall interfaces and their public Blueprint workflows are in army and RPG HUD authoring and the current gallery. Earlier paths and engine references below describe the retained earlier example.
ForgeOutpost uses an original InterfaceForge layout and presentation. Game Master's design, widgets, artwork, styling and animations stay reference-only. The example's small local Outpost provider owns selection and command rules; InterfaceForge owns presentation, navigation, input prompts and model/entry lifecycle.
Run /Game/Maps/ForgeOutpost and choose Begin expedition. Next scout selects one scout. Select all scouts selects the current group and becomes Select one scout. Clicking a scout replaces selection; Shift-click toggles it. Selected scout bodies use mint, with gold for unselected bodies. The UI buttons provide selection without a pointer. The remapping-aware prompt still resolves IFExampleInteract for Next scout.
Patrol moves the selected group to the beacon, updates the group summary, completes the objective and earns 40 supplies once. Rally selected scouts moves only that selection. Train scout · 60 starts a four-second production queue and adds a scout. Busy commands stay focusable, display their reason, and reject activation. Pause freezes the example's movement/production clocks. Return to main releases the HUD's subscriptions. This local demonstration is not a multiplayer RTS simulation or a MassForge implementation.
Create a command entry in Blueprint
The saved WBP_OutpostCommand derives from IFEntryWidget. It contains CommandChoice, a WBP_OutpostCommandButton deriving from IFButton, and an Object Reference variable ActionSource. The button's ordinary Designer tree has a Border named FocusBorder, and IFText components named LabelWidget and AvailabilityWidget. IFButton supplies theme, input/focus feedback and availability presentation to these optional components.
The button's On Appearance Updated graph casts the inherited Text Block references to IFText, sets their Theme Override from the event's Theme, and calls Refresh Appearance. Label uses Base Size 12, with Body when Enabled and Caption when unavailable; the reason uses Base Size 10 and Caption. This public hook preserves player text scaling, focus feedback and local/global theme changes while giving dense commands a local typography choice. The cast is necessary because IFButton's inherited component references are typed as Text Block.
Use these graphs:
| Event | Nodes and data | Expected result |
|---|---|---|
| On Entry Refreshed | Cast Entry Data to IFPresentationData → Set Label on CommandChoice, Text = Title → Set Action Availability, Available = bEnabled, Reason = UnavailableReason | Initial state and subsequent model updates change the same button |
| CommandChoice: On Button Base Clicked | Cast Entry Data to IFPresentationData → Request UI Action (IFDataSource interface message), Target = ActionSource, Action Name = StableKey | External provider validates and responds to the command |
| On Entry Released | Set ActionSource = None → Set Label to empty → Set Action Availability(false, empty) → Cancel Latent Actions | Reuse cannot invoke a previous provider, retain its label/reason or complete an old deferred reveal |
The base entry binds OnDataChanged and unbinds the old model before release/reassignment. It does not know the meaning of Patrol, Rally or Recruit. A developer can use this same entry for another game by supplying a compatible model and IFDataSource object.
After updating availability, Delay Until Next Tick → HasAnyUserFocusedDescendants → Branch checks whether this entry owns focus after input activation finishes. Get Parent → Is Valid → Get Parent → Cast to ScrollBox → Force Layout Prepass → Scroll Widget Into View requests a reveal with Widget to Find = Self, Animate Scroll = false, Scroll Destination = IntoView and Padding = 4. This sample's entry sits in a Vertical Box inside a Scroll Box. Missing parents or a different container skip the reveal. The deferred focus check and fresh measurement let a newly visible reason fit inside the scroll viewport. This is a bounded response to a model update, without per-widget polling. Entries without focus never pull the user's scroll position. Release cancels pending latent actions.
Compose the HUD
In WBP_AshenRTSHUD → Initialize Screen, call Parent: Initialize Screen. Initialize the existing readouts from Resources, Selected, Objective, Queue and Notice. For each command entry, call Get UI Model → Initialize Entry, then Set ActionSource = Screen Data. Set the source after Initialize Entry: initialization first releases an old assignment and the release graph clears ActionSource.
| Designer entry | Get UI Model name / StableKey |
|---|---|
| NextChoice | SelectNext |
| GroupChoice | ToggleGroup |
| PatrolChoice | Patrol |
| RallyChoice | Rally |
| TrainChoice | Recruit |
Selected.Quantity is the selection count. Title describes a single scout, group or empty selection; Detail summarizes moving and waiting scouts. Each command model supplies its own current label, availability and reason. Edit the existing stable model, then call Notify Data Changed once after a group of edits. No widget scans the world population.
flowchart LR
A[HUD Initialize Screen] --> B[Get UI Model]
B --> C[Command: Initialize Entry]
C --> D[Set ActionSource = Screen Data]
E[Provider edits command model] --> F[Notify Data Changed]
F --> G[On Entry Refreshed]
G --> H[Set Label and Set Action Availability]
I[Button activation] --> J[Request UI Action interface message]
J --> E
Event On Initialized → Set Initial Focus targets PatrolChoice.CommandChoice. Event Construct → Set Navigation Rule Explicit connects the inner buttons in the order Next → Group → Patrol → Rally → Train → Pause, with inverse Up links. Construct runs after the Slate widgets exist, so cross-tree navigation resolves the actual buttons. Standard Scroll Boxes reveal focused commands. RTSSelectionDock keeps SelectionReadout above the command Scroll Box; that Scroll Box uses a Fill vertical slot. Scrolling to a command retains the selection summary. At small viewports with enlarged UI/text, the command panel deliberately scrolls rather than overlapping the world or shrinking the chosen text size.
The HUD sets its existing readouts' ReadoutTitle.BaseSize = 12 and ReadoutDetail.BaseSize = 11, followed by Refresh Appearance, before assigning data. This local Blueprint choice keeps passive information readable at 800×600 with both UI and text at 150%, while retaining the common readout classes, theme and player scaling.
Customize and verify
Duplicate either command Widget Blueprint, change its Designer tree and refresh graph, and choose the new class for a HUD entry. Retain the inner IFButton for CommonUI navigation or explicitly link your chosen focus targets in Construct. Change ActionSource or model keys to consume another IFDataSource; selection rules remain in that provider. Replace themes through Set Theme, or set a widget's Theme Override for a local change.
The opt-in Development fixture -IFVerifyRTS uses the actual saved Blueprint HUD and synthetic Slate Enter/arrow events, while its setup, pause/return and actor-lifetime controls are programmatic. It tests group selection, observable movement, busy rejection, pause/resume, production, selection-only rally, stale actor cleanup, nested navigation and release subscriptions. -IFVerifyRTSEnlarged previews 150% UI/text without saving. -IFVerifyRTSCapture captures the rendered training state. Exact revisions and results are in Evidence/RTS_SELECTION_RUNTIME.md.
Physical mouse/controller/touch tests of this revision, drag selection, production cancellation, large entity populations, multiplayer and the optional Mass adapter remain separate gates. Do not infer them from the local synthetic-input fixture.
Compact overview and visible production
The original passive card uses RTSPassiveFit (Overlay), Fill/Bottom inside the existing .55-weight lower dock. Its existing Size Box/Surface follows content, with padding14 and retained bounded scrolling. RTSOverviewColumn pins QueueReadout and the existing remap-aware IFActionPrompt below the resource/notice Scroll Box. Queue title/detail use per-instance Base Size12 → Refresh Appearance in Construct; its model and the shared readout class are unchanged. Command entries keep48-unit minimum targets,6-unit gaps and no trailing gap. All five labels fit at default1280×720; at enlarged800×600, navigation scrolls commands and passive prose while production/prompt remain pinned. These are normal Designer/Blueprint properties.
Both HUDs share the public navigation hint host. The body shows the command description in a reserved .28→.46 lane and yields to result notifications. It uses the same source model and public entry refresh/release contract. Pointer popups and the action provider remain independent. The examples retain original styling; Game Master's design is not redistributed.