Spring 2026 · AI Engineer
Action Game AI
Melee and ranged enemies for a third-person action game in Unreal Engine 5, driven by behavior trees, environment queries and a full perception system.
- Role
- AI Engineer
- When
- Spring 2026
- Discipline
- Games, AI & ML
Built with

Overview
Enemies in an action game have to feel like they are thinking. I designed and built the enemy AI for a third-person action game in Unreal Engine 5: melee fighters that circle the player and pick their moment, archers that keep their distance and reposition, and guards that walk a patrol route until something catches their attention.
Every NPC can be given a patrol path to guard. When it hears a noise or catches a glimpse of an enemy it breaks off to investigate, and if its health drops too low it retreats, breaks line of sight and heals before rejoining the fight.
Behavior trees
A root tree selects between states (passive, investigating, frozen and combat) and hands combat off to a type-specific branch.

The melee enemy strafes around the player and attacks at intervals rather than charging in a straight line.


The ranged enemy finds a suitable firing position, shoots, then relocates so it never stays a static target.


State sub-trees
Sub-trees keep each state self-contained, which keeps the main tree readable and makes new states easy to add.



Tasks and environment queries
A custom task walks the enemy along its patrol route.


Environment queries score points in the level so enemies make sensible spatial decisions: hiding out of the player’s sight, holding range, and circling during melee.



Perception and the AI controller
The AI controller initialises every enemy in the passive state and gives each one sight, hearing and damage senses.


Blackboard
A shared blackboard holds what each enemy knows: its attack target (the player or another NPC), its current state, a point of interest to investigate, and the attack and defend radii it tries to keep.

Interfaces and the damage system
Blueprint interfaces define melee and ranged behaviour separately, and a damage struct carries the damage type plus modifiers such as blockable or uninterruptible.



