Action System
Documentation Unreal Engine AI Actions
Intelligent action selection that scores every available move and picks the best one for the moment.
The brain behind enemy decisions. It doesn't just pick an attack - it evaluates the battlefield.
ActionEvaluationComponent
EvaluateBestAction()
Gameplay Ability
(Simple Action)
Behavior Tree Sequence
(Complex Logic)
The system dynamically chooses the execution method. Behavior Trees can be chained for complex sequences.
When to Use This
- Any AI that needs to choose between multiple attacks or behaviors
- Enemies with distance-dependent movesets (melee vs ranged)
- Boss fights with phase-based action sets
- Group AI where different roles use different attack patterns
This system can be used independently of the other plugin systems.
Core Concepts
Scoring
Every evaluation, all valid actions compete. The highest score wins.
Final Score = SelectionWeight
× Range Score (Distance & Angle)
× Context Multipliers (Tags)
× Novelty Bonus (Variety)
× Chain Bonus (Combos)
Range & Angle Evaluation
Each action uses an
FRangeEval curve that defines its optimal zone. An attack might be valid from 0-500cm, but its score peaks at 150-250cm.// Light Attack: Perfect at mid-close range
Distance.MinValue = 0;
Distance.OptimalMin = 100; // Score ramps up to 1.0
Distance.OptimalMax = 250; // Score stays at 1.0
Distance.MaxValue = 400; // Score ramps down to 0.0Available presets:
FRangeEval::MakeMeleeRange()- Close-range attacksFRangeEval::MakeRangedRange()- Long-range attacksFRangeEval::MakeFrontalAngle()- Forward-facing coneFRangeEval::MakeLowHealthRange()- Triggers at low healthFRangeEval::MakeAlwaysOne()- Always returns 1.0 (no range preference)
Cooldowns & Variance
| Property | Description |
|---|---|
Duration | Base time before the action can be reused. |
InitialCooldown | Cooldown applied on spawn (prevents instant nukes). |
Randomization | Adds ±% variance (e.g., 0.2 = ±20%). |
SpawnCooldownChance | Chance to start on cooldown (desyncs groups of enemies). |
MaxConsecutiveUses | Limit repeats before the AI must switch (e.g., 1 = can't use twice in a row). |
Novelty & Chains
- Novelty: Recently used actions get a score penalty. This creates diverse behavior without rigid randomization.
- Chains: Actions can define a
PreferredNextActionId. After a "Light Attack", the "Heavy Finisher" gets a massive score boost - creating natural combos.
Organic Combos
You don't script 'Hit-Hit-Smash' - you make 'Smash' very likely after 'Hit'. If the player rolls out of range, the AI naturally breaks the combo instead of swinging at air.
Execution Modes
Actions execute in one of two ways depending on complexity.
Gameplay Ability (Simple)
Activates a Gameplay Ability and listens for the end tag.
ExecutionMode = EActionExecutionMode::GameplayAbility;
AbilityClass = UGA_LightAttack::StaticClass();
AbilityTag = "SEC.Action.LightAttack";
AbilityEndTag = "SEC.Action.End";Your ability class must inherit from
UGameplayAbilityBase. It handles the end-event handshake that tells the Action System when the ability finishes. Without it, the AI gets stuck waiting.UGameplayAbilityBase provides:- Rotation Lock (
bLockAIRotation) - AI commits to the attack direction (no tracking mid-swing). - Motion Warping (
MotionWarpingTargetName) - Automatically sets up a warp target fromAIController::GetFocusActor(). - Action Context (
FActionAbilityContext) - Passes target, distance, direction, magnitude, and context tags to the ability on activation.
Activation Modes
Each action can choose how its ability is triggered via the
ActivationMode property:| Mode | How It Works |
|---|---|
| ByTag (default) | Calls TryActivateAbilitiesByTag using AbilityTag. The ability must have matching AbilityTags in its class defaults. |
| ByEvent | Sends a Gameplay Event using AbilityTag as the event tag. The ability must have a matching Trigger entry (Gameplay Event) in its class defaults, or use WaitGameplayEvent. |
ByEvent mode sends a payload containing the instigator and the current target actor, so your ability can access them immediately.
// Standard tag-based activation (default)
ActivationMode = EAbilityActivationMode::ByTag;
AbilityTag = "SEC.Action.Attack.Light";
// Event-based activation
ActivationMode = EAbilityActivationMode::ByEvent;
AbilityTag = "SEC.Action.Attack.SweepEvent"; // Used as the event tagByEvent abilities do not need AbilityTags in their class defaults. Instead, add a Trigger entry with the matching tag and set its source to Gameplay Event. The
AbilityTag field serves double duty: tag activation in ByTag mode, event tag in ByEvent mode.Behavior Tree (Complex)
For multi-stage behaviors - circling, investigating, complex boss moves. Runs one or more Behavior Trees in sequence.
ExecutionMode = EActionExecutionMode::BehaviorTreeSequence;
BehaviorTreeSequence = { BT_ChargeWindup, BT_ChargeRelease };
BehaviorTreeTimeout = 5.0f;When an action uses
BehaviorTreeSequence mode, the system writes several blackboard keys before the tree starts, so your BT tasks can read them immediately:| Blackboard Key | Type | Value |
|---|---|---|
SEC_ActionId | Name | The action's ActionId |
SEC_AbilityTag | String | The AbilityTag from the ActionSpec |
SEC_AbilityEndTag | String | The AbilityEndTag from the ActionSpec |
SEC_ActivationMode | Name | "ByTag" or "ByEvent" |
SEC_TargetActor | Object | The current target (focus) actor |
SEC_SelfActor | Object | The AI pawn |
SEC_Distance | Float | Distance to target |
These keys must exist in your Blackboard Data Asset for the writes to succeed. If a key is missing from the asset, the write is silently ignored. Add all
SEC_ keys to your Blackboard asset.BT Tasks for Ability Activation
The plugin provides two Behavior Tree tasks for activating abilities inside a BT:
Activate Blackboard Ability - Reads ability class and tags from the blackboard keys written by the Action System. Has an
ActivationMode property with three options:FromBlackboard(default) - readsSEC_ActivationModefrom the blackboard. Falls back to ByTag if the key is empty.ByTag- always uses tag-based activation.ByEvent- always uses event-based activation.
Activate Ability - A standalone task where you set the ability class directly. Has
ActivationMode (ByTag / ByEvent) and an EventTag field that appears only in ByEvent mode. Use this when you want to activate a specific ability from a BT without going through the Action System.Contextual Execution
Sometimes you need to tell an action exactly what to do - "Attack that specific target", "Use this item", or "Apply strength 0.5".
Creating a new ActionId for every variation (e.g.,
Attack_TargetA, Attack_TargetB) is impossible. Instead, use Context.1. Execute with Context
Call this function from Blueprint or C++ to pass dynamic data:
FActionExecutionContext Context;
Context.Target = CustomTargetActor;
Context.OptionalObject = SomeItem;
Context.Magnitude = 0.5f;
Context.ContextTags.AddTag(Tag_QuickVariant);
ActionEvaluationComponent->ExecuteActionWithContext("SpecialAttack", Context);2. Receive in Ability
Your ability (inheriting from
UGameplayAbilityBase) automatically captures this data.- Event:
On Action Context Received(Blueprint) - Accessor:
GetActionContext()(Blueprint Pure)
The system maps the context as follows:
| Context Field | Maps To |
|---|---|
Target | ActionContext.TargetActor |
OptionalObject | ActionContext.OptionalObject |
Magnitude | ActionContext.Magnitude |
ContextTags | ActionContext.ContextTags |
[!NOTE] IfTargetis not provided in context, the system falls back to the AI's current Focus Actor.
How Action Sets Are Managed
The plugin uses a push-based architecture. When a combat role changes, the
SECCombatControllerComponent on the controller automatically syncs everything.AICombatRoleSubsystem assigns new role
→ SECCombatControllerComponent::HandleCombatRoleAssigned()
→ SyncStateForCombatRole()
→ SECActionSetComponent::SyncForCombatRole()
→ GetActionSetForRole() // Resolution chain below
→ ActionEvaluationComponent::SetActionSetAndResetState()
Resolution Priority
When
GetActionSetForRole() is called, it walks this chain and returns the first match:- Runtime Override -
SetRuntimeOverride(ActionSet). Highest priority. Use for boss phase transitions. - Equipped Weapon - If the weapon actor implements
ISECWeaponActionSetProvider, the system callsGetWeaponActionSetForRole(RoleTag)on it. - Config Role - Role-specific ActionSet from
EnemyAIConfig(e.g., a different set for "Attacker" vs "Flanker"). - Config Default - Fallback ActionSet from
EnemyAIConfig. - Component Default -
SECActionSetComponent → DefaultActionSetproperty (set in Blueprint on the pawn). - None - No ActionSet found. AI will only move, never attack.
Changes to weapon or override take effect immediately - no need to wait for a role change.
This is the same resolution chain used bySECReactionSetComponentfor reaction sets. Learn one, know both.
Weapon-Driven AI
Because 'Equipped Weapon' outranks Config, you can change an enemy's entire brain just by giving them a different item. A skeleton with a Bow becomes a sniper. Disarm it, and it falls back to its Config set - becoming a brawler.
Weapon Action Set Provider
To make a weapon provide action sets, implement the
ISECWeaponActionSetProvider interface on your weapon actor (Blueprint or C++). Override GetWeaponActionSetForRole(RoleTag) to return the appropriate UActionSet*.// Tell the pawn about the weapon:
Pawn->ActionSetComponent->SetEquippedWeapon(WeaponActor);
// Clear to revert to Config-based resolution:
Pawn->ActionSetComponent->SetEquippedWeapon(nullptr);Dynamic Actions (Runtime)
Grant and revoke individual actions without changing the entire set.
Pawn->ActionSetComponent->GrantAction(ThrowGrenadeSpec);
Pawn->ActionSetComponent->RevokeAction("ThrowGrenade");Granted actions persist across role changes and action set swaps. They participate in evaluation alongside the base ActionSet - same scoring, same cooldowns.
For bulk operations:
Pawn->ActionSetComponent->GrantActionsFromSet(BonusActionSet); // Add all from set
Pawn->ActionSetComponent->RevokeActionsFromSet(BonusActionSet); // Remove all from set
Pawn->ActionSetComponent->ClearGrantedActions(); // Remove all grantedCustom Scoring Hooks
The
ActionEvaluationComponent provides two BlueprintNativeEvent hooks for project-specific logic.CanExecuteAction - Veto an action after all built-in gates pass.
bool CanExecuteAction(FName ActionId, const FDecisionContext& Context);
// Return false to block the action.ModifyActionScore - Adjust the score after the pipeline computes it.
float ModifyActionScore(FName ActionId, float BaseScore, const FDecisionContext& Context);
// Return a modified score. Return BaseScore for no change.Override these in a Blueprint or C++ subclass of
UActionEvaluationComponent.Quick Setup
- Create Asset: Right-click → Miscellaneous → Data Asset → ActionSet.
- Define Actions: Each entry needs an
ActionId,SelectionWeight,DistanceEval,AngleEval, and an execution mode. - Assign: Drop the ActionSet into your
EnemyAIConfig, or set it directly for testing:
ActionEvaluationComponent->ActiveActionSet = MyActionSet;See Configuration Reference for the complete
EnemyAIConfig structure.Key API
| Component | Location | Role |
|---|---|---|
ActionEvaluationComponent | Controller | Scoring, evaluation, execution |
SECActionSetComponent | Pawn | Resolution, replication, weapon/override management |
SECCombatControllerComponent | Controller | Orchestrates sync on role changes |
ActionEvaluationComponent (Controller)
EvaluateBestAction(Context, Time, OutChosen)- Run the scoring pipeline.ExecuteAction(ActionId)- Force-execute a specific action.ExecuteActionWithContext(Id, Context)- Execute with custom data (Target, etc.).SetActionOverride(ActionId, Multiplier)- Runtime buff/nerf a specific action's score.CanExecuteAction()/ModifyActionScore()- Override hooks (see above).
SECActionSetComponent (Pawn)
SetEquippedWeapon(Actor)- Weapon-driven action set override.SetRuntimeOverride(ActionSet)/ClearRuntimeOverride()- Boss phase override.GrantAction()/RevokeAction()- Runtime action management.OnActionExecutionStarted/OnActionExecutionCompleted- Replicated delegates for client UI/FX.OnActionSetChanged- Fires when the active ActionSet changes (replicated).OnActionCooldownStarted(ActionId, Duration)/OnActionCooldownExpired(ActionId)- Cooldown lifecycle delegates (replicated).GetRemainingCooldown(ActionId)/IsActionOnCooldown(ActionId)/GetAllActiveCooldowns()- Query current cooldown state.
Debug Tools
// On ActionEvaluationComponent:
ActionEvalComp->bDebugLogDecisions = true; // Log scoring breakdown
ActionEvalComp->bDebugLogExecution = true; // Log execution flowIntegration Points
| System | How It Connects |
|---|---|
| Movement System | Provides distance/angle for scoring context |
| Combat Roles | Role changes trigger automatic ActionSet swaps |
| Threat Detection | Threat level feeds into FDecisionContext |
| Multiplayer | Action state replicates to clients via SECActionSetComponent |
Custom character classes:ActionEvaluationComponentresolves theAbilitySystemComponentfrom the possessed pawn viaIAbilitySystemInterfaceon controller possession. If your pawn does not implement this interface, ability-based actions will silently fail. See Getting Started for setup details.