Combat Roles

Documentation Unreal Engine AI Combat Roles

Coordinate a pack: cap how many enemies attack at once, and swap each enemy's moveset, reactions and movement to match the role it holds.


Four enemies around one player: one pressing the attack, the rest circling and waiting their turn. Roles decide who is which, and swap each enemy's behaviour assets to match.

Set it up

60 seconds
  1. 1

    Register the player as a combat target

    In the player pawn's BeginPlay, get the AI Combat Role Subsystem and call Register Combat Target with Self.
    BP_SEC_PlayerCharacter in the showcase content does exactly this, and BP_Dummy shows the same wiring on a stationary target.
  2. 2

    Drop three or more enemies into the level

    Each enemy joins the pool when its AI controller possesses it. Auto-Register for Combat Roles on the Enemy AI Config is ticked out of the box, so this step is already done.
    EnemyConfig_Grunt
    Combat Role
    Auto-Register for Combat Roles
    Allowed Roles (empty = any)Empty
    Priority0
    An untouched config already joins the pool and accepts any role.
  3. 3

    Cap how many attack at once

    Open Project Settings, Plugins, Soulslike Enemy Combat. Under Role Limits, set the Attacker row to 1 for the classic one-at-a-time fight. It ships at 3.
  4. 4

    Give the roles something to do

    Open the Enemy AI Config. Under Movement Profiles, set Default Movement Profile to a patient profile, then add a Role Movement Profiles entry for SEC.Role.Attacker pointing at an aggressive one. The showcase content ships five to start from, DA_MovementBehavior_Attacker through DA_MovementBehavior_Elite.
    EnemyConfig_Grunt
    Movement Profiles
    Manage Movement Profiles Automatically
    Default Movement Profile
    None
    Role Movement Profiles0 Array elements
    The default covers every role that has no entry of its own, so one override is enough to see the difference.
  5. 5

    Play, and watch the roles swap

    Press Play and run SEC.Debug.Role 1 in the console. Each enemy gets its name and role above its head, coloured by role: red Attacker, orange Flanker, blue Waiter, green Supporter, purple Elite.
An enemy with no combat target holds no role. Role slots are counted per target, so an enemy the subsystem has not paired with one is skipped both when it registers and on the reassignment timer. If the roles above every head read empty, nothing registered the player. See Getting Started and Targeting.

The six roles

Roles are gameplay tags under SEC.Role.
RoleTagWhat it is for
AttackerSEC.Role.AttackerFront-line pressure. The role the fight revolves around.
WaiterSEC.Role.WaiterHolds distance and waits for a slot to open.
FlankerSEC.Role.FlankerCircles for an angle.
SupporterSEC.Role.SupporterRanged fire or support from the back.
EliteSEC.Role.EliteBoss-tier enemy. Unlimited slots out of the box.
NoneSEC.Role.NoneWhat an enemy gets when the pass finds no free slot for it.
An enemy the pass cannot seat holds SEC.Role.None; the Fallback Role field in Project Settings takes no part in that.
Viewport
LVL_SEC_Showcase>Combat Roles
Player
Attacker
Waiter
Waiter
Flanker
Combat Slots
Attackers:1 / 1
(Others must wait)
Enemies dynamically swap roles based on slot availability and priority.
To add a role of your own, define a tag under SEC.Role in Project Settings, Gameplay Tags, then list it under Additional Roles in Project Settings, Plugins, Soulslike Enemy Combat. It is scored and filled alongside the built-ins.

Cap how many hold each role

Role Limits in Project Settings, Plugins, Soulslike Enemy Combat is a list of role and limit pairs. A role with no row has unlimited slots.
RoleShips at
Attacker3
Flanker2
Supporter2
Waiterunlimited
Eliteunlimited
Noneunlimited
Each combat target counts its own slots, so two players can each field three Attackers.
Role limits cap how many enemies hold a role. To cap how many swing at the same moment, reach for Combat Tokens, which gate one action rather than an enemy's whole behaviour set. The two stack.

Give each role its own behaviour

When an enemy's role changes, its controller resolves three assets and applies them.
Per-role listFalls back toMaster switch
Role Action SetsDefault Action SetManage Action Sets Automatically
Role Reaction SetsDefault Reaction SetManage Reaction Sets Automatically
Role Movement ProfilesDefault Movement ProfileManage Movement Profiles Automatically
All three live on the Enemy AI Config. A role with no entry in a list takes that category's default. An equipped weapon's own sets beat the config's role entries, so a bow-carrying skeleton keeps its archer moveset whatever role it holds. See Actions, Reactions, Movement.
Fill in the default as well as the role list. An enemy holding a role you did not list, or no role at all, gets whatever the default names; leave the default empty and it gets nothing.

Steer which enemy gets which role

These sit under Combat Role on the Enemy AI Config.
Combat Role
Auto-Register for Combat Roles
Allowed Roles (empty = any)
0 Gameplay Tags
Priority
0
Preferred Role
None
Fitness Evaluators
0 Array elements
Target Selector
None
Target Filter
None
Ignore Target Redistribution
FieldWhat to do with it
Auto-Register for Combat RolesUntick it to keep this enemy out of the pool. It takes no slot and holds no role, and its controller still applies the config's default action set, reaction set and movement profile at possession.
Allowed Roles (empty = any)Empty lets the enemy hold any role. List tags to pin an archer to Waiter and Supporter so it is not sent to the front.
PriorityHigher values get first pick of limited slots. 0 for a grunt, 50 for an elite, 100 for a mini-boss, 200 for a boss.
Preferred RoleAdds 0.05 to that role's fitness score, enough to break a tie. It must also appear in Allowed Roles, unless that list is empty.
Fitness EvaluatorsEmpty scores on distance alone, closest first, out to 2000 cm. See the drawers below.
Target SelectorWhich registered target this enemy fights when several exist. See Targeting.
Target FilterWhich actors this enemy will fight at all, asked before any target is selected. See Targeting.
Ignore Target RedistributionPins this enemy to its target while the rest of the pack redistributes. Use it for a boss.

How often roles change

Timing
Role Reassignment Interval
8
Min Time In Role
8
Reevaluate Targets On Reassignment
FieldDefaultWhat to do with it
Role Reassignment Interval8 sHow often the whole pool is re-scored. Lower it for a fight that reshuffles quickly. Set it to 0 to stop the timer and drive reassignment by hand.
Min Time In Role8 sHysteresis. An enemy still inside this window gets 0.3 added to its current role's score, which keeps it where it is. Lower it for more churn.
Reevaluate Targets On ReassignmentoffRe-runs each enemy's Target Selector before roles are scored. Needs two or more registered targets; it does nothing with one.
A newly registered enemy does not wait for the timer. It takes the best free slot the moment it registers, without disturbing anyone else.

Debug it

SEC.Debug.Role 1                  // Name and role above each enemy, coloured by role
SEC.Debug.LogRoleAssignments 1    // Each role change, with the fitness score behind it
SEC.Debug.LogRoleAssignments 2    // Adds every enemy-to-role pair the pass considered
SEC.Debug.All 1 turns every overlay section on at once, and SEC.Debug.WatchPawn <name> narrows them to one enemy. The role line replicates, so it reads on a client as well as on the server.
The SEC Combat Role component on the pawn carries a Debug Overlay Role checkbox that draws the same line for that one enemy without touching the console.
AdvancedNothing changes role
In the order worth checking:
  • No registered combat target. Slots are counted per target, so an enemy paired with none is skipped by registration and by the timer alike. This is the common one and it logs at Verbose.
  • Auto-Register for Combat Roles is unticked on the config.
  • The controller has no SEC Combat Controller component. That component is what calls Register Combatant at possession, so an enemy without it never joins the pool. Calling Register Combatant yourself succeeds either way, on default parameters: any role, priority 0, no evaluators. Enemy Controller Base ships with the component.
  • Only one enemy is in the fight. With default limits it takes Attacker and stays there. Roles move when there are more enemies than slots.
  • Role Reassignment Interval is 0. The timer auto-starts only when the interval is above 0. Call Force Reassignment yourself, or Start Reassignment Timer after setting an interval.
  • Reassignment is paused. Pause Reassignment freezes role changes until Resume Reassignment.
  • The role is locked. Force Assign Role with its lock argument set makes the evaluator skip that enemy. Unlock Role clears it.
  • The enemy is mid-action. An enemy whose action is executing counts as locked for that pass, keeps its role and holds its slot. Cap Attacker at 1, give it a long attack, and the pool reads frozen from the outside.
  • Min Time In Role is long against the interval. The hysteresis bonus then holds a role through most passes.
An enemy reading SEC.Role.None was scored and found no free slot. Before its first assignment the tag is empty rather than None.
AdvancedScore the fit yourself
Leave Fitness Evaluators empty and role fitness comes from distance alone, closest scoring highest, out to 2000 cm. Add evaluators to that list to score on anything else. Several combine into a weighted average.
Three fields sit on each one:
  • Role Influence Weights maps a role tag to how strongly this evaluator counts for it: 1.0 full, 0.5 half, 0.0 not at all.
  • Influence On Unlisted Roles (0) is what a role missing from that map gets.
  • Score Mode reads the raw score as-is (Higher Score = Better Fit) or inverts it (Lower Score = Better Fit).

Distance Evaluator

Scores how far the enemy stands from its assigned target. The score peaks at 1 at Ideal Distance and falls off linearly to 0 at Ideal Distance plus or minus Effective Range. It ships weighted onto Attacker.
Affected Roles
Role Influence Weights
SEC.Role.Attacker → 1.0
Influence On Unlisted Roles
0
Scoring
Score Mode
Higher Score = Better Fit
Distance Settings
Ideal Distance
0
Effective Range
2000
  • Closest enemies become Attackers: Ideal Distance 0, Effective Range 2000, Higher Score = Better Fit, weights { Attacker: 1.0 }.
  • Farthest become Waiters: the same distances, Lower Score = Better Fit, weights { Waiter: 1.0 }.
  • Mid-range enemies become Flankers: Ideal Distance 1000, Effective Range 500, Higher Score = Better Fit, weights { Flanker: 1.0 }.

Cooldown Evaluator

Scores how much of the enemy's moveset is on cooldown, so a spent Attacker rotates out and a fresh one steps in.
Affected Roles
Role Influence Weights
0 Map elements
Influence On Unlisted Roles
0
Scoring
Score Mode
Higher Score = Better Fit
Cooldown Settings
Current Role Penalty
0.5
It answers 0.5, a neutral score, whenever the role the enemy currently holds is missing from Role Influence Weights. List the roles you want to fatigue (Attacker, Flanker) and leave the passive ones out. Current Role Penalty (0.5) multiplies the score while the pass considers keeping the enemy in the role it already holds, so a lower value pushes harder for a swap.
AdvancedWriting your own evaluator
Subclass Role Evaluator in Blueprint or C++ and override Evaluate Fitness, returning 0 for unfit and 1 for a perfect fit. The subsystem applies Score Mode and the per-role weights afterwards, so return the raw number.
The context hands you four things:
FieldUse
ControllerReach the pawn and its components from here.
RoleThe role under evaluation.
Current RoleThe role the enemy holds right now.
Time In Current RoleSeconds it has held that role.
Get the assigned target with Get Combatant Target on the subsystem. Return 0.5 when your criterion does not apply.
AdvancedBosses and enemies that skip coordination
GoalSetting
Skip slot coordination entirelyUntick Auto-Register for Combat Roles on the Enemy AI Config.
Stay on one player while the pack redistributesTick Ignore Target Redistribution.
Script a fixed roleForce Assign Role with its lock argument set.
Wear a role tag without consuming a slotApply Local Combat Role on the SEC Combat Controller component.
Apply Local Combat Role resolves and applies the action set, reaction set, weapon sets and movement profile for a role, and publishes the tag for clients, without joining the coordination. An enemy still registered with the subsystem has it overwritten on the next pass, so pair it with an unregistered enemy.
An unregistered enemy wires its own sets through the config defaults and consumes no slots, which leaves the pack's Attacker cap for the enemies that need it.
AdvancedSeveral players, several pools
Each registered target keeps an independent pool with its own slot counts. Register a second player and the two pools fill separately.
FunctionDoes
Register Combat TargetAdds the actor to the pool. Auto Assign Unassigned evaluates roles straight away instead of waiting for the timer; Reevaluate Existing also re-runs every assigned enemy's Target Selector.
Unregister Combat TargetRemoves it. Enemies left behind lose their target, reset to SEC.Role.None, and re-run their own Target Selector across the remaining targets. One whose selector answers nothing stays unassigned.
Assign Combatant To TargetMoves one enemy to a pool. This one carries out the order as given, without asking the enemy's Target Filter.
Reassign Combatant TargetRe-runs one enemy's Target Selector.
Reevaluate All TargetsRe-runs every assigned enemy's Target Selector. Honours Ignore Target Redistribution.
Transfer Combatants To TargetHands one pool over to another target, for a player death handoff.
Balance Combatants Across TargetsRound-robins the pack evenly, ignoring Target Selectors.
Set Primary Target And Assign AllPuts the whole pack on one target, for a boss or a VIP.
Force Reassignment For TargetRe-scores one pool instead of all of them.
Get Role Count For Target, Get Combatants With Role For TargetPer-pool slot usage.
Team rules still apply. An enemy whose own Target Filter turns a target aside keeps what it had rather than being handed something it will not fight.
MultiplayerReading the role on a client
Role evaluation runs on the server, and AI controllers do not exist on clients. The SEC Combat Role component on the pawn replicates the tag so a nameplate, an icon or a debug overlay can read it anywhere.
Details
SEC Combat Role
AI|Combat Role
Combat Role
SEC.Role.Attacker
Replicated runtime state on the pawn. SECCombatControllerComponent calls SetCombatRole on the server; clients bind OnCombatRoleChanged.
Enemy Character Base adds the component by default. Read Get Combat Role, or bind On Combat Role Changed, which fires on the server and on every client. Set Combat Role is server only; the controller calls it, and calling it anywhere else changes what clients see and nothing more, since the behaviour assets resolve on the controller.
AlternativeDriving roles from your own controller
A custom AI controller with no SEC Combat Controller component still receives the role change on the global delegate, but nothing swaps its assets. Bind On Combat Role Changed and sync by hand through the SEC Combat Role Sync Library:
FunctionSyncs
Sync All For Combat RoleAction set, reaction set, the sets the equipped weapon gives, and the movement profile.
Sync Action Set For RoleThe action set alone.
Sync Reaction Set For RoleThe reaction set alone.
Sync Movement Profile For RoleThe movement profile alone.
Each takes the new role tag and finds the components it needs on the pawn and the controller. Sync All For Combat Role and Sync Movement Profile For Role also take the resolved Enemy AI Config; the action set and reaction set functions take the pawn and the role tag alone.
AdvancedChanging the rules at runtime
Every function below sits on the AI Combat Role Subsystem and is callable from Blueprint.
Slots and timing
FunctionDoes
Set Role Limit OverrideCaps a role for this session. -1 is unlimited, 0 disables the role. Clear Role Limit Override and Clear All Role Limit Overrides put the project settings back.
Set Reassignment IntervalSeconds between passes. 0 stops the timer.
Set Min Time In RoleThe hysteresis window.
Set Reevaluate Targets On ReassignmentTarget re-pick before each pass.
Update ConfigBulk update. With attrition on, existing holders keep their roles when a limit shrinks instead of being stripped.
Reset To Default SettingsDrops every runtime override.
Assignment and queries
FunctionDoes
Force ReassignmentRe-scores every pool now.
Pause Reassignment, Resume ReassignmentFreeze role changes through a cutscene.
Start Reassignment Timer, Stop Reassignment TimerTimer control. Start Reassignment Timer logs a warning and returns while the interval sits at 0, so set an interval first.
Force Assign Role, Unlock Role, Is Role LockedScripted roles.
Get Role, Get Role Count, Get Combatants With RoleCurrent assignments.
Is Registered, Get All Combatants, Get Total Combatant CountPool membership.
An enrage phase that opens a slot is Set Role Limit Override on the Attacker tag followed by Force Reassignment, so the extra attacker steps in on the same frame rather than at the next 8 second pass.
AdvancedEvents you can bind
EventFires when
On Combat Role ChangedAny role change.
On Combat Role Changed For TargetThe same, carrying which target the enemy is assigned to.
On Combatant Registered, On Combatant UnregisteredAn enemy joins or leaves the pool.
On Combat Target Registered, On Combat Target UnregisteredA target is added or removed.
On Combat Target ChangedA primary-target handoff.
On Combatants OrphanedA target was lost, carrying the enemies left behind. Their roles reset to SEC.Role.None; reassign them here.