How-To: Author a Combo

Goal: wire up the combo system and author a branching combo where each step is its own UCrimsonGameplayAbility. Steps 1-3 are mandatory; step 4 enables directional combos.

Prerequisites
Quick Start complete. You have at least two UCrimsonGameplayAbility subclasses to use as combo steps, and your gameplay uses Enhanced Input.

1. Configure project settings

All combo knobs live in Project Settings -> Crimson -> Crimson Ability System. Two are required:

  • Combo Input Mapping Context - a UInputMappingContext containing every input action combos may use (usually your gameplay IMC, BDO-style). The combo editor's input picker reads its catalog from this IMC.
  • Move Input Action - your IA_Move UInputAction. The controller samples its raw axis value at press time to set ECrimsonComboDirection. Without it, every buffered input gets Direction = None and only direction-agnostic transitions can fire.
Without these set
The combo editor's input picker is empty (with an inline hint) and IsDataValid reports 'action not in catalog' for any authored transition. Directional handshakes (W+LMB, Back+RMB) never fire if Move Input Action is unset.

2. Add the combo controller to your pawn

Add UCrimsonComboController as a component - in C++, in the BP component panel, or via a GameFeatureAction_AddComponents. It tick-polls for the ASC, so it's safe to add before the PS-owns-ASC pattern finishes initializing.

Screenshot pendingImages/CrimsonAbilitySystem/howto-combo-add-controller.png
Pawn Blueprint -> Add Component -> Crimson Combo Controller.

3. Gate input through the controller

Every press for a combo-catalog action must be offered to the controller first: if it matches an active transition or starting handshake, the controller consumes it; otherwise it falls through to the normal ASC tag flow. Use BindAbilityActionsWithAction.

cpp
CrimsonIC->BindAbilityActionsWithAction(InputConfig, this,
&ThisClass::OnComboCapableActionPressed,
&ThisClass::OnComboCapableActionReleased,
BindHandles);
void AMyHero::OnComboCapableActionPressed(UInputAction* Action, FGameplayTag AbilityTag)
{
if (UCrimsonComboController* Combo = FindComponentByClass<UCrimsonComboController>())
{
bool bConsumed = false;
Combo->HandleInputActionPressed(Action, bConsumed);
if (bConsumed) return;
}
GetASC()->AbilityInputTagPressed(AbilityTag); // normal flow
}
You own the pawn-side callbacks
CrimsonAbilitySystem ships no pawn class - OnComboCapableActionPressed/Released are yours to author. The CrimsonCore example plugin (Discord-only) shows one wiring, but it isn't redistributed and isn't required.

4. Supply the move-input provider (for directional combos)

The controller asks the pawn for the current directional intent via a TFunction<FVector2D()> you set once at init.

Read the action's RAW value, not the consumed movement vector
APawn::GetLastMovementInputVector() returns the vector the character LAST consumed via AddMovementInput(). If an in-place ability suppresses movement, no AddMovementInput runs and the vector is zero - silently killing directional handshakes during exactly the abilities that need them. Read the action value from UEnhancedPlayerInput instead; it's computed every frame from raw key/stick state.
cpp
UInputAction* MoveAction = GetDefault<UCrimsonAbilitySystemSettings>()->MoveInputAction.LoadSynchronous();
TWeakObjectPtr<const APawn> WeakPawn = this;
TWeakObjectPtr<const UInputAction> WeakMove = MoveAction;
Combo->SetMoveInputProvider([WeakPawn, WeakMove]()
{
const APawn* P = WeakPawn.Get();
const UInputAction* MA = WeakMove.Get();
if (!P || !MA) return FVector2D::ZeroVector;
const APlayerController* PC = Cast<APlayerController>(P->GetController());
if (!PC) return FVector2D::ZeroVector;
const UEnhancedPlayerInput* EI = Cast<UEnhancedPlayerInput>(PC->PlayerInput);
if (!EI) return FVector2D::ZeroVector;
return EI->GetActionValue(MA).Get<FVector2D>(); // X = right, Y = forward
});

5. Create and author the combo graph

Content Browser -> Crimson -> Ability System -> Crimson Combo Graph Asset. Double-click to open the graph editor.

Screenshot pendingImages/CrimsonAbilitySystem/howto-combo-graph.png
The combo graph editor: Entry node, Step nodes (each referencing an ability), and Transition edges with the per-step phase track-bars.
  • The Entry node is the starting handshake - set its Input.Action (dropdown reads the IMC catalog), Direction, Kind, and charge bounds.
  • Add Step nodes (right-click -> Combo Step Node) and set each StepAbilityClass to a UCrimsonGameplayAbility subclass.
  • Drag wires between steps - the schema auto-inserts a Transition edge node; click it to set input, priority, and conditional augment grants.
  • Each step shows five tracks: Startup (red), Active (amber), Recovery (blue), Transition Window (green), and a read-only Input Buffer look-back band (soft amber). Drag the bars or type values.
  • The compile pass clamps phase boundaries to the step ability's montage length and re-clamps live if you edit the montage in Persona.
  • The asset auto-compiles on save; IsDataValid catches missing targets, ambiguous transitions, branch collisions, and 'action not in catalog' errors.

6. Root the combo on an ability

The graph describes what comes AFTER the entry; the rooting ability declares which combos it can start, via its ComboExtension.

  • Open any UCrimsonGameplayAbility, find the Combo Extension section.
  • Add a DefaultCombos entry and pick your combo asset.
  • Set Transition Open / Transition Close (seconds at 1x rate) - the window during this ability when the combo's starting input is accepted. Defaults 0.4 / 0.85.
  • (Optional) set Input Buffer TTL Override - positive overrides the global TTL; -1 defers to the default.

7. Implement GetPrimaryMontage() (recommended)

The combo editor reads the montage via this virtual to drive its timeline; without it you get a placeholder fixed-duration bar.

cpp
virtual UAnimMontage* GetPrimaryMontage() const override { return MyMontageProperty; }
Verify
In PIE, activate the rooting ability and press the combo input inside the green transition window - the next step's ability activates. Use the Combo dev-tools tab (see How-To: Debug Combos) to watch the windows live.