How-To: Write Your Own Placement
Goal: position combat text by rules the built-in placements do not cover - orbiting the target, snapping to a grid, tracking a spline, following the mouse.
1. Understand the contract
A placement answers one question - where does this pop sit - and owns its own projection. The subsystem never projects anything itself, which is why a placement is free to be screen-native.
| Entry point | When | Job |
|---|---|---|
AcquirePlacement | Once, at spawn | Cache what to follow and produce the first position. Return false to decline the pop |
UpdatePlacement | Every frame, while bUpdateEveryFrame | Return this frame's state |
const for that reason. Anything you need to remember about one particular pop goes in FCrimsonCombatTextPlacementState, which is handed back to you each frame - never in a member variable.2. Know the two structs
FCrimsonCombatTextPlacementContext is what you are told - target and instigator actors, the event's world location, the style key, the value, the viewing player, viewport size and DPI scale, and the pop's age.
FCrimsonCombatTextPlacementState is what you return. The fields that matter most:
| Field | Purpose |
|---|---|
Space | World or Screen. Screen skips camera-distance culling, because a HUD pop must not vanish when its cause is far away |
ScreenPosition | The final anchor in layout units. Always fill this, in both spaces |
WorldAnchor | Only meaningful in World space. Drives the distance curve and world-space renderers |
bOnScreen | false hides the pop this frame |
bUpdateEveryFrame | false freezes this state for the rest of the pop's life |
SpreadOwner / SpreadGroup | What this pop fans against. Pops sharing both deflect away from each other |
UserVector / UserScalar | Scratch for anything you sample once at spawn. The plugin ignores them |
3. Subclass and implement
Both entry points are BlueprintNativeEvent, so a Blueprint-only project can write a placement with no C++ at all. UCrimsonCombatTextPlacementLibrary carries the maths.
Content Browser -> Blueprint Class, search for CrimsonCombatTextPlacement, and pick either the abstract base or an existing placement to extend.
In the graph, override Acquire Placement and Update Placement. Both hand you a Context and expect a State back; Acquire Placement also returns a bool - return false to decline the pop and let the fallback chain try.
Typical Update chain: Get Actor Anchor Location (Target Actor from Context) -> Project World To Layout (Context) -> set Screen Position on the State -> return it.
Available on UCrimsonCombatTextPlacementLibrary: Project World To Layout, Clamp To Viewport Edge, Viewport Anchor To Layout, Get Actor Anchor Location.
4. Add it to the placement set
Add a row to your placement set, choose your class, and give it a Placement Id under CrimsonCombatText.Placement. Point a style's Placement Preset at it.
PlacementId make the later one unreachable. The asset logs a warning naming the duplicate when that happens.Placement policy: line shows your class's description.See also
- How-To: Position Pops - the built-in world placements.
- How-To: Show Pops on the HUD or a Health Bar - the built-in screen and widget placements.
- API Reference -> UCrimsonCombatTextPlacement - the full contract.