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.
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
UInputMappingContextcontaining 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_MoveUInputAction. The controller samples its raw axis value at press time to setECrimsonComboDirection. Without it, every buffered input getsDirection = Noneand only direction-agnostic transitions can fire.
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.
Images/CrimsonAbilitySystem/howto-combo-add-controller.png3. 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.
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}
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.
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.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.
Images/CrimsonAbilitySystem/howto-combo-graph.png- 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
StepAbilityClassto aUCrimsonGameplayAbilitysubclass. - 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;
IsDataValidcatches 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
DefaultCombosentry 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;
-1defers 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.
virtual UAnimMontage* GetPrimaryMontage() const override { return MyMontageProperty; }