Example: Dodge Roll¶
Intermediate
Overview¶
A dodge roll ability that grants invulnerability frames (i-frames) during the animation, costs stamina, and blocks other abilities while rolling. This demonstrates how Activation Owned Tags create temporary character states, how those states integrate with the damage pipeline, and how Activation Blocked Tags prevent re-rolling mid-dodge. The roll uses root motion from the montage for physically grounded movement.
What We're Building¶
- Stamina cost of 20 per roll
- Short cooldown of 0.5 seconds to prevent roll spam
- I-frames during the entire roll animation via
State.Invulnerabletag - Root motion movement -- the dodge distance comes from the animation, not manual velocity
- Ability blocking -- can't attack or re-roll while rolling
- CC blocking -- can't roll while stunned or dead
- Tags as state --
State.EvadingandState.Invulnerableare granted automatically on activation and removed on end
Prerequisites¶
What you need before starting
This example assumes you have completed Project Setup and have:
- A character with an Ability System Component
- An AttributeSet with Health and Stamina attributes
- A base ability class (
YourProjectGameplayAbility) with anInputTagproperty - An input binding system that routes Enhanced Input actions to abilities by tag
- A dodge roll animation montage (
AM_DodgeRoll) with root motion, set up for your character's skeleton
If any of that is missing, start with Project Setup.
Step 1: Create the Effects¶
The dodge roll only needs two effects -- a cost and a cooldown. There is no damage effect because the dodge doesn't deal damage. The i-frame behavior comes entirely from tags, not from a Gameplay Effect.
GE_Cost_DodgeRoll¶
| Setting | Value |
|---|---|
| Duration Policy | Instant |
| Modifiers[0] -- Attribute | YourProjectAttributeSet.Stamina |
| Modifiers[0] -- Modifier Op | Add |
| Modifiers[0] -- Magnitude | Scalable Float: -20.0 |
GE_Cooldown_DodgeRoll¶
| Setting | Value |
|---|---|
| Duration Policy | Has Duration |
| Duration Magnitude | Scalable Float: 0.5 (half a second) |
| GrantedTags | Cooldown.Evade |
We use Cooldown.Evade rather than Cooldown.Ability.DodgeRoll because you might have multiple evasion abilities (dodge, dash, blink) that share a single cooldown. If you want independent cooldowns per evasion type, use more specific tags like Cooldown.Evade.DodgeRoll.
Step 2: Create the Ability¶
Create a new Blueprint class with YourProjectGameplayAbility as the parent. Name it GA_DodgeRoll.
Class Defaults¶
| Property | Value | Why |
|---|---|---|
| Input Tag | InputTag.Movement.Dodge |
Maps to your dodge input |
| Ability Tags | Ability.Movement.DodgeRoll |
Identifies this ability for queries |
| Activation Blocked Tags | State.Dead, CrowdControl.Hard, State.Evading |
Can't roll while dead, stunned, or already rolling |
| Activation Owned Tags | State.Evading, State.Invulnerable |
Granted on activate, removed on end |
| Block Abilities With Tag | Ability.Combat |
Can't attack mid-roll |
| Instancing Policy | InstancedPerActor |
Required when using Ability Tasks |
| Net Execution Policy | LocalPredicted |
Feels responsive on the client |
| Cost Gameplay Effect Class | GE_Cost_DodgeRoll |
Stamina check and deduction |
| Cooldown Gameplay Effect Class | GE_Cooldown_DodgeRoll |
0.5s re-activation delay |
How Activation Owned Tags create i-frames
Activation Owned Tags are the core mechanic here. When the ability activates, the ASC automatically grants State.Evading and State.Invulnerable to the owning actor. When the ability ends (for any reason -- completion, interruption, cancellation), those tags are automatically removed. No manual tag management required.
State.Invulnerable is what your damage pipeline checks. State.Evading serves double duty: it blocks re-activation (via Activation Blocked Tags) and can be queried by other systems (animation, UI, AI perception).
State.Evading in Activation Blocked Tags
Notice State.Evading appears in both Activation Owned Tags and Activation Blocked Tags. This is intentional -- it prevents the player from re-activating the dodge while already dodging. Since Activation Owned Tags are granted before activation checks on subsequent attempts, the second activation sees State.Evading and fails. This is the standard "can't re-use while active" pattern.
Event Graph¶
Event Graph
- ActivateAbility fires -- at this point,
State.EvadingandState.Invulnerableare already granted by Activation Owned Tags - CommitAbility checks cost and cooldown, deducts stamina, applies cooldown. If it fails (not enough stamina, still on cooldown), the ability ends immediately and the tags are removed
- PlayMontageAndWait plays
AM_DodgeRollwith root motion. The character moves through space based on the animation - When the montage completes or is interrupted/cancelled: EndAbility. Activation Owned Tags (
State.Evading,State.Invulnerable) are automatically removed
flowchart LR
A["ActivateAbility"]:::event --> B["CommitAbility"]:::func
B -->|Failed| C["EndAbility\n(cancelled)"]:::endpoint
B -->|Success| D["PlayMontageAndWait\nAM_DodgeRoll"]:::task
D -->|Completed / BlendOut| E["EndAbility"]:::endpoint
D -->|Interrupted / Cancelled| E
classDef event fill:#5c1a1a,stroke:#ff6666,color:#fff
classDef func fill:#2a2a4a,stroke:#9b89f5,color:#fff
classDef task fill:#1a3a5c,stroke:#4a9eff,color:#fff
classDef endpoint fill:#1a4a2d,stroke:#6bcb3a,color:#fff
void UGA_DodgeRoll::ActivateAbility(
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
{
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
return;
}
UAbilityTask_PlayMontageAndWait* MontageTask =
UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(
this,
NAME_None,
DodgeMontage, // UPROPERTY: TObjectPtr<UAnimMontage>
1.0f);
MontageTask->OnCompleted.AddDynamic(
this, &UGA_DodgeRoll::OnMontageFinished);
MontageTask->OnBlendOut.AddDynamic(
this, &UGA_DodgeRoll::OnMontageFinished);
MontageTask->OnInterrupted.AddDynamic(
this, &UGA_DodgeRoll::OnMontageCancelled);
MontageTask->OnCancelled.AddDynamic(
this, &UGA_DodgeRoll::OnMontageCancelled);
MontageTask->ReadyForActivation();
}
void UGA_DodgeRoll::OnMontageFinished()
{
EndAbility(
CurrentSpecHandle,
CurrentActorInfo,
CurrentActivationInfo,
true, false);
}
void UGA_DodgeRoll::OnMontageCancelled()
{
EndAbility(
CurrentSpecHandle,
CurrentActorInfo,
CurrentActivationInfo,
true, true);
}
The C++ version is straightforward -- the dodge roll is a simple montage-driven ability with no gameplay events or damage application. All the interesting behavior comes from the Class Defaults (Activation Owned Tags, Blocked Tags, Block Abilities With Tag).
Always End Ability
Every code path must call End Ability. This is especially critical for the dodge roll because Activation Owned Tags (State.Invulnerable) persist as long as the ability is active. A leaked dodge roll ability means permanent invulnerability.
I-Frames: How State.Invulnerable Works in the Damage Pipeline¶
The State.Invulnerable tag doesn't do anything on its own -- your damage pipeline needs to check for it. There are two approaches:
The simplest approach. In your AttributeSet's PostGameplayEffectExecute, check for the tag before applying damage:
void UYourAttributeSet::PostGameplayEffectExecute(
const FGameplayEffectModCallbackData& Data)
{
// ... other processing ...
if (Data.EvaluatedData.Attribute ==
GetPendingDamageAttribute())
{
UAbilitySystemComponent* TargetASC =
Data.Target.AbilityActorInfo->AbilitySystemComponent.Get();
if (TargetASC && TargetASC->HasMatchingGameplayTag(
FGameplayTag::RequestGameplayTag(
FName("State.Invulnerable"))))
{
// Target is invulnerable -- zero out the damage
SetPendingDamage(0.f);
return;
}
// Normal damage processing continues...
const float FinalDamage = GetPendingDamage();
SetPendingDamage(0.f);
SetHealth(FMath::Clamp(
GetHealth() - FinalDamage, 0.f, GetMaxHealth()));
}
}
A cleaner approach for production. Create an infinite-duration Gameplay Effect with an ImmunityGameplayEffectComponent that blocks damage effects. The dodge ability applies this GE on activation and removes it on end. This is more setup but keeps your damage pipeline free of hardcoded tag checks. See Immunity for details.
Which approach to use?
The PostGameplayEffectExecute check is simpler and works well for prototyping and small projects. The Immunity GE Component approach is more scalable -- it lets you define immunity rules in data (which tags block which effects) without modifying C++ code. Most shipped games use some form of the immunity system.
Step 3: Wire Input¶
1. InputAction Asset¶
Create IA_Dodge (right-click > Input > Input Action). Set the Value Type to Digital (Bool).
2. InputMappingContext¶
In your IMC_Default, add:
- Input Action:
IA_Dodge - Key: Space bar, B button, or your preferred dodge key
3. Route Input to the ASC¶
In your Character Blueprint's Event Graph:
- Add an Enhanced Input Action event node for
IA_Dodge - From the exec pin, call Get Ability System Component on Self
- Iterate activatable abilities and try to activate any whose Input Tag matches
InputTag.Movement.Dodge
See Input Binding for the full production input routing setup.
4. Grant the Ability¶
Add GA_DodgeRoll to your character's Startup Abilities array in Class Defaults.
Step 4: Test¶
Basic Test¶
- Hit Play
- Press your dodge key -- character should play the roll animation and move via root motion
- Stamina should decrease by 20
- Press dodge again immediately -- should not activate (0.5s cooldown)
- Wait 0.5 seconds -- dodge should work again
I-Frame Test¶
- Set up a damage source (enemy attack, damage volume, or console command)
- Time the damage to hit during the roll
- Verify no damage is taken during the roll (
State.Invulnerableis present) - Verify damage works normally before and after the roll
ShowDebug Checklist¶
Open the console and type showdebug abilitysystem:
| Scenario | Expected Result |
|---|---|
| Press dodge with 20+ Stamina | Montage plays, Stamina drops by 20, State.Evading + State.Invulnerable appear in tags, Cooldown.Evade appears |
| Press dodge with < 20 Stamina | Nothing happens -- Commit Ability fails cost check |
| Press dodge during cooldown | Nothing happens -- cooldown tag blocks |
| Press dodge while already rolling | Nothing happens -- State.Evading in Activation Blocked Tags |
| Press attack during roll | Nothing happens -- Ability.Combat blocked by Block Abilities With Tag |
| Damage hits during roll | No health change -- State.Invulnerable present |
| Roll ends | State.Evading and State.Invulnerable disappear from tags |
Press dodge while stunned (CrowdControl.Hard) |
Nothing happens -- blocked by Activation Blocked Tags |
Edge Cases¶
- Dodge at exactly 20 stamina -- should succeed (cost check is
>=, not>) - Interrupted by a force (knockback) -- montage interrupted, ability ends, tags removed, character is no longer invulnerable
- Network: dodge on client -- prediction should make the roll feel immediate. If the server rejects (out of stamina due to a race), the client rolls back
Nothing happening?
Common issues:
- No root motion movement -- make sure
bEnableRootMotionis true on the montage and your Character Movement Component is configured to accept root motion - Permanent invulnerability -- End Ability is not being called on all paths. Check that every montage delegate leads to End Ability
- Can still attack during roll -- verify
Block Abilities With TagincludesAbility.Combatand that your combat abilities haveAbility.Combatin their Ability Tags - Stamina not deducting -- make sure
GE_Cost_DodgeRollis assigned to the Cost Gameplay Effect Class property
Connecting to UI
Show a cooldown sweep on the dodge icon, or flash the stamina bar when cost is deducted. See Connecting GAS to UI for reactive UI patterns that listen to GAS events instead of polling.
The Full Flow¶
Here's what happens from button press to roll completion:
- Input fires
IA_Dodge - Input handler finds abilities with
InputTag.Movement.Dodgeand callsTryActivateAbility - The ASC checks activation requirements:
- Blocked tags: Does the owner have
State.Dead,CrowdControl.Hard, orState.Evading?
- Blocked tags: Does the owner have
- If checks pass, the ability activates:
- Activation Owned Tags are granted immediately:
State.Evading,State.Invulnerable ActivateAbilityfires
- Activation Owned Tags are granted immediately:
CommitAbilitychecks cost and cooldown:- Cost: Do we have 20+ Stamina? If yes, apply
GE_Cost_DodgeRoll(Stamina -20) - Cooldown: Apply
GE_Cooldown_DodgeRoll(tag granted for 0.5 seconds) - If commit fails, End Ability is called immediately (tags are removed)
- Cost: Do we have 20+ Stamina? If yes, apply
- Play Montage and Wait starts
AM_DodgeRollwith root motion. The character physically moves through space - During the roll,
State.Invulnerableis on the ASC. Any incoming damage that checks this tag is zeroed out - During the roll,
Block Abilities With Tag: Ability.Combatprevents combat abilities from activating - The montage completes. End Ability is called
- Activation Owned Tags (
State.Evading,State.Invulnerable) are automatically removed - After 0.5 seconds, the cooldown effect expires and
Cooldown.Evadetag is removed. The dodge is available again
Variations¶
Directional Dodge¶
Instead of always rolling forward, use the player's movement input to determine roll direction. Before playing the montage, read the character's last movement input vector and select a directional montage section (Forward, Back, Left, Right). Pass the section name to PlayMontageAndWait via the StartSection parameter.
Dash (No Animation)¶
Replace the montage with a LaunchCharacter or direct velocity override. Use a short WaitDelay task (0.3 seconds) to control the i-frame duration. This is faster to set up and works well for top-down games where you don't need a roll animation.
Dodge with Stamina Regeneration Pause¶
Add a second Gameplay Effect -- GE_StaminaRegenPause -- with a duration of 1.5 seconds that applies a modifier blocking stamina regeneration. Apply it alongside the cost in ActivateAbility (after CommitAbility succeeds). This prevents the "dodge spam + regen" loop that trivializes stamina management.
Related Pages¶
- Melee Attack -- montage-driven ability with damage application
- Ranged Attack -- projectile spawning, passing GE specs to actors
- Ability Tasks -- PlayMontageAndWait details
- Cooldowns and Costs -- cost/cooldown deep dive
- Immunity -- the GE Component approach to i-frames
- Damage Pipeline -- where invulnerability is checked
- Tag Architecture -- designing State.* and CrowdControl.* tags