Step-by-Step Enemy Creation
Documentation Unreal Engine AI Tutorial
Build a complete, armed enemy: a multi-action moveset with combos, a weapon, and testing. Builds on Getting Started.
Getting Started built a one-attack enemy. This guide arms it into a real fight: a moveset that scores different ranges, a light-into-heavy combo, a retreat, a weapon that lands hits, and a way to watch the AI decide. Each part links to the system page behind it.
Before you start
- Finish Getting Started. You reuse that pawn, controller, and config here.
- Have two or three attack montages ready, and know which frames carry the hit.
1. Reuse the pawn, controller, and config
You already made these in Getting Started: a Blueprint from
EnemyCharacterBase, a controller from EnemyControllerBase, and an EnemyAIConfig. Keep them. To swap in your own classes, use the reparent steps in Getting Started. The rest of this guide extends the ActionSet those pieces already point to.2. Build a moveset
One action is enough to see the AI attack; a fight needs several that win at different ranges and moments. Open your ActionSet and add these to the Actions array. For the full field reference, see the Action System.
Light attack, close range
| Property | Value | Notes |
|---|---|---|
| Action ID | LightAttack | Used for chaining and cooldowns |
| Execution Method | Gameplay Ability | Set its Ability Class to GA_LightAttack |
| Scoring → Distance Scorer | 0 / 100 / 250 / 400 | Min / OptimalMin / OptimalMax / Max, in cm |
| Scoring → Angle Scorer | 0 / 0 / 30 / 90 | Ideal within 30 degrees of facing |
| Cooldown → Duration | 2.0 | Two seconds between uses |
| Cooldown → Initial Cooldown | 1.0 | Cannot open with it in the first second |
| Selection Weight | 1.0 | Base weight |
Heavy attack, the combo finisher
| Property | Value | Notes |
|---|---|---|
| Action ID | HeavyAttack | |
| Execution Method | Gameplay Ability | Ability Class GA_HeavyAttack |
| Scoring → Distance Scorer | 0 / 150 / 300 / 450 | Slightly farther than the light |
| Cooldown → Duration | 4.0 | Longer than the light |
| Selection Weight | 0.8 | Comes up less often on its own |
| Risk Penalty | 1.5 | Divides the score, biasing against it |
To chain light into heavy, set Preferred Follow-Up Action to
HeavyAttack on the light attack, and Chain Bonus Multiplier to 1.5. The heavy scores 50% higher for one pick after a light lands.Retreat, when crowded
| Property | Value | Notes |
|---|---|---|
| Action ID | QuickRetreat | |
| Execution Method | Behavior Tree Sequence | Set Behavior Tree Sequence to [BT_QuickBackstep] |
| Scoring → Distance Scorer | 0 / 0 / 100 / 200 | Best when very close |
| Cooldown → Duration | 3.0 | |
| Selection Weight | 1.5 | Higher priority in range |
| Tag Score Multipliers | State.PlayerAttacking → 2.0 | Doubles the score while the player attacks |
Tag Score Multipliers map a
FGameplayTag to a multiplier. When the tag is on the AI, the target, or the world, it scales the score. Use State.Stunned → 2.0 on the target for a punish, or World.Phase.BossPhase2 → 1.3 for late-fight aggression. The Action System covers the full scoring model.3. One ability per Gameplay Ability action
Each action using the Gameplay Ability method needs an ability Blueprint. Inherit from
GA_SEC_Attack, assign the montage, and you are done: it plays the montage, forwards the notify events, and sends the end tag the action system waits on. Getting Started, Step 3 covers this and the from-scratch route.4. Arm the enemy
The attacks play, but nothing lands until the weapon runs melee traces. The full weapon build lives on the Melee Trace page: inherit
ASECWeaponBase, define the trace sockets, add the SECMeleeTraceWindow notify to each montage, and assign a damage config. Set that up, then come back to test.5. StateTree, if you want authored structure
Leave the config's
DefaultStateTree empty and the native loop runs the combat you just built. Set it to StateTree_SEC_Core, or author your own, when you need patrol, investigation, or boss phases on top. The StateTree Tasks page covers the graph nodes.6. Test and debug
Drop
BP_MyEnemy into a level with a built NavMesh, and confirm its AI Controller Class points to your controller.Turn on the decision logs while tuning:
ActionEvaluationComponent → bDebugLogDecisions: logs each action's score and why it won or lost.MovementEvaluatorComponent → bDebugDrawScoring: draws the scored movement directions in the world.
The decision log reads something like:
LogEvaluation: Evaluating 3 actions for BP_MyEnemy...
LogEvaluation: LightAttack -> 0.95
LogEvaluation: HeavyAttack -> 0.60
LogEvaluation: QuickRetreat -> 0.10
Expect the enemy to close to its scored range, strafe, open with a light attack, sometimes chain into the heavy, and retreat when you crowd it or press an attack.
Per-scorer values live in
FScoreBreakdown.CustomScores, keyed by each scorer's GetDisplayName(), and fold into the Custom factor. There is no separate Dist or Angle line in the log anymore.Common issues
| Problem | Cause | Fix |
|---|---|---|
| AI does not attack | No ability on the action | Set the Execution Method's Ability Class, and confirm the ability activates |
| AI repeats one action | Only one scores well | Add actions with different distance and angle ranges |
| AI does not move | No NavMesh | Add a NavMeshBoundsVolume and build navigation |
| Weapon does not hit | Socket ID mismatch | Match the notify's Socket IDs to the weapon's TraceSockets ID (see Melee Trace) |
| AI stuck after an attack | End tag never sent | Inherit the ability from GA_SEC_Attack or GameplayAbilityBase |