How-To: World-Space Indicators

Goal: float a widget over a world object (quest marker, nameplate, ping) with screen clamping and an off-screen arrow, using the pooled indicator pipeline.

Prerequisites
Quick Start done (the indicator layer lives in your HUD layout). A target actor with a USceneComponent to anchor to.

1. Put an indicator layer in the HUD

In BP_HUDLayout's Designer add a Crimson Indicator Layer (UCrimsonIndicatorLayer) filling the screen (e.g. in an Overlay slot, anchors Fill). Its ArrowBrush is the clamp-to-edge arrow sprite. The layer hosts and projects every indicator for the owning player.

Screenshot pendingImages/CrimsonUI/howto-indicator-layer.png
BP_HUDLayout Designer: Crimson Indicator Layer added under the root Overlay, anchors = Fill, Arrow Brush set.

2. Ensure the controller has the manager component

UCrimsonIndicatorManagerComponent (a UControllerComponent) owns the indicator list. Add it to your PlayerController: in Blueprint via Add Component -> Crimson Indicator Manager, in C++ via CreateDefaultSubobject, or let a GameFeature action inject it on the full stack. (CrimsonCore's UCrimsonCoreGameplayAbility_Interact creates one on demand for its default on-actor interaction prompt - manual setup is only needed when you drive indicators yourself.)

cpp
// PlayerController constructor
#include "IndicatorSystem/CrimsonIndicatorManagerComponent.h"
AMyPlayerController::AMyPlayerController(const FObjectInitializer& OI) : Super(OI)
{
IndicatorManager = CreateDefaultSubobject<UCrimsonIndicatorManagerComponent>(TEXT("IndicatorManager"));
}

3. Add an indicator

Screenshot pendingImages/CrimsonUI/howto-indicator-add-bp.png
Get Indicator Manager Component (Crimson Indicator Library, Controller = Get Player Controller) -> Construct Object From Class (Crimson Indicator Descriptor) -> Set Scene Component / Set Indicator Class / Set Clamp To Screen / Set Show Clamp To Screen Arrow -> Add Indicator.

Get the manager with Get Indicator Manager Component (from UCrimsonIndicatorLibrary). Create the descriptor with Construct Object From Class (class = Crimson Indicator Descriptor, outer = the manager), call its setters, then Add Indicator.

Placement setters beyond the basics: SetProjectionMode (ComponentPoint, ComponentBoundingBox, ComponentScreenBoundingBox, ActorBoundingBox, ActorScreenBoundingBox), SetComponentSocketName, SetHAlign/SetVAlign, SetWorldPositionOffset, SetScreenSpaceOffset, SetBoundingBoxAnchor, SetPriority, SetDesiredVisibility, SetAutoRemoveWhenIndicatorComponentIsNull (auto-cleanup when the target dies).

Verify
The widget tracks the target in PIE; walking it off-screen pins it to the edge with the arrow pointing at the target.

4. The indicator widget itself

Any UUserWidget works. Implement Crimson Indicator Widget Interface (ICrimsonIndicatorWidgetInterface) to receive lifecycle calls:

EventWhenDo
BindIndicator(Descriptor)Widget assigned to a descriptor (fresh or from the pool)Read GetDataObject / target and populate visuals.
UnbindIndicator(Descriptor)Widget returned to the poolClear every bound reference - the next bind may be a different target.
Screenshot pendingImages/CrimsonUI/howto-indicator-widget-bp.png
WBP_QuestMarker: Class Settings -> Interfaces -> add Crimson Indicator Widget Interface; Graph implements Event Bind Indicator (read descriptor's Data Object) and Event Unbind Indicator (clear state).
Widgets are pooled by class
The layer reuses indicator widgets. State you do not clear in UnbindIndicator leaks into the next target that reuses the widget.

See also

  • How-To: Show a Context Menu - world-anchored menus use a different (focusable) mechanism.
  • Concept: Policy & Layout Architecture - where the indicator layer sits in the stack.