Adding AI Enemies in Phaser

Updated June 2026
Enemy AI transforms a Phaser game from a walking simulator into an engaging challenge. This guide covers practical AI techniques for 2D games, from simple patrol routes and chase behavior to finite state machines and boss fight patterns, using Phaser's physics and scene systems to create enemies that feel intelligent and fair.

Game AI does not need to be complex to be effective. The enemies in most classic 2D games use straightforward rules that combine a few simple behaviors to create the illusion of intelligence. A Goomba walks forward until it hits a wall, then turns around. A ghost chases the player when they are close, then returns to patrol when the player escapes. These behaviors are easy to implement in Phaser and, when combined thoughtfully, produce enemies that are fun to fight and satisfying to defeat.

Create an Enemy Sprite with Physics

Enemies start as physics-enabled sprites, just like the player character. Create them with this.physics.add.sprite(x, y, textureKey) and configure their physics body with appropriate size, offset, gravity, and collision properties. If you have many enemies of the same type, use a physics group to manage them as a collection and set shared properties like bounce and world bounds collision.

Add custom properties to track enemy state. At minimum, each enemy needs a health value, a current state indicator, and reference variables for behavior-specific data like patrol boundaries or detection range. You can add these as properties directly on the sprite object or create a wrapper class that extends Phaser.Physics.Arcade.Sprite to encapsulate enemy behavior cleanly.

Set up animations for each enemy state. A typical enemy needs idle, walk, attack, hurt, and death animations. Load these from a spritesheet or texture atlas in preload, define them in create, and switch between them based on the enemy's current behavior state. Matching animation to behavior state makes the enemy's intent visible to the player, which is essential for fair gameplay.

Register collision between enemies and the player, between enemies and the environment, and between enemies and the player's attacks. The collision callbacks handle damage calculation, knockback effects, and death sequences. Enemies that collide with the environment use the same tilemap collision as the player, ensuring they walk on platforms and bump into walls realistically.

Implement Patrol Movement

Patrol behavior is the simplest and most common enemy movement pattern. The enemy walks in one direction until a condition is met, then reverses direction. The condition can be a wall collision, a distance limit, an edge detection, or a timed interval. This creates enemies that methodically cover an area, acting as mobile obstacles the player must time their movement around.

Wall-based patrol uses collision callbacks to reverse direction. When the enemy collides with a wall tile or a barrier object, flip the velocity direction and the sprite's horizontal scale to face the new direction. This approach is simple but depends on the level geometry having walls at appropriate positions.

Distance-based patrol tracks how far the enemy has traveled from a starting point. Store the enemy's spawn position and set a patrol distance. In the update loop, check if the enemy has moved beyond the patrol distance in either direction from spawn, and reverse if so. This works well in open areas without walls, and gives level designers control over patrol range through a single parameter.

Edge detection prevents enemies from walking off platforms. Check the tile below and ahead of the enemy each frame. If there is no ground tile at the enemy's forward edge, reverse direction before the enemy steps into empty air. This requires access to the tilemap layer and a tile-coordinate calculation based on the enemy's position and direction. Edge-detecting patrol creates enemies that stay on their platform, pacing back and forth endlessly until the player arrives.

Add Detection and Chasing

Detection is the trigger that transitions an enemy from passive patrol to aggressive pursuit. The simplest detection method is a distance check: calculate the distance between the enemy and the player each frame, and if it falls below a threshold, activate chase behavior. Phaser provides Phaser.Math.Distance.Between(enemy.x, enemy.y, player.x, player.y) for this calculation.

Directional detection adds realism by only triggering when the player is in front of the enemy. Check the player's position relative to the enemy's facing direction before activating the chase. An enemy facing right should not detect a player behind it. This gives the player a tactical advantage when approaching enemies from behind and rewards careful positioning.

Chase behavior moves the enemy toward the player's position. The simplest chase sets the enemy's velocity toward the player using the angle between them: calculate the angle with Phaser.Math.Angle.Between, then set velocity components using Math.cos and Math.sin multiplied by the chase speed. For platformer games where enemies only move horizontally, just match the player's horizontal direction at a chase speed that is slightly slower than the player's run speed.

Add a detection cooldown so enemies do not instantly switch between patrol and chase every frame when the player is near the detection boundary. Once detection activates, keep the chase state for a minimum duration, typically one to two seconds, before checking whether the player has escaped. If the player moves beyond a larger "lose interest" distance, transition the enemy back to patrol. This two-threshold system prevents flickering behavior at the detection boundary.

Build a Finite State Machine

A finite state machine (FSM) organizes enemy behavior into discrete states with defined transitions. Each state has an enter function that runs once when the state activates, an update function that runs every frame while the state is active, and an exit function that cleans up when leaving. Transitions define the conditions that cause the enemy to switch from one state to another.

Common enemy states include idle (standing still, waiting), patrol (walking back and forth), alert (player detected, brief pause before chasing), chase (pursuing the player), attack (executing an attack animation and damage check), hurt (reacting to player damage with brief stun), and death (playing death animation and dropping items). Not every enemy needs all states, but organizing behavior this way makes it easy to add and modify behaviors without tangling logic.

Implement a simple FSM as an object with a currentState property and a setState method. The setState method calls the current state's exit function, updates currentState, and calls the new state's enter function. In the enemy's update, call the current state's update function. Each state's update checks its transition conditions and calls setState when a transition triggers.

State machines prevent common AI bugs like enemies attacking while stunned, chasing while dead, or patrolling while the player is standing on their head. Because each state explicitly defines what the enemy can do and what transitions are possible, impossible combinations of behaviors are prevented structurally rather than through scattered conditional checks. This also makes debugging easier because you can log state transitions and see exactly why the enemy changed behavior.

Design Attack Patterns

Melee attacks are the simplest enemy attack type. When the enemy is close enough to the player, play an attack animation and check for overlap between an attack hitbox and the player during specific animation frames. The hitbox can be a separate invisible sprite positioned in front of the enemy, or a physics body that is enabled only during the attack frames and disabled afterward.

Ranged attacks use projectiles fired from the enemy's position toward the player. Create a bullet group with object pooling, and when the enemy enters the attack state, retrieve a bullet from the pool, position it at the enemy, and set its velocity toward the player's current position. Add a fire rate cooldown to prevent enemies from machine-gunning the player, and set a maximum bullet count to keep performance manageable.

Area attacks affect a zone rather than a single point. An enemy might slam the ground, creating a shockwave that damages everything within a radius. Implement this with a circle overlap check triggered at the right moment in the attack animation. Area attacks are typically slower and more telegraphed than melee or ranged attacks, giving the player time to dodge.

Boss fights combine multiple attack patterns into phases. A boss might use ranged attacks in phase one, switch to faster melee attacks in phase two when health drops below 50%, and add area attacks in phase three below 25% health. Each phase is a state in the boss's FSM, with health thresholds triggering phase transitions. Bosses should telegraph each attack with a distinct animation windup so the player can learn the patterns and react accordingly.

Scale Difficulty and Polish Behavior

Difficulty scaling keeps the game challenging as the player's skill improves. Early enemies should be slow, have short detection ranges, and use only basic patrol and melee attack patterns. Later enemies move faster, detect the player from greater distances, use ranged attacks, and combine multiple behaviors. Gradual escalation teaches the player new mechanics before combining them into harder challenges.

Telegraphing is the most important polish technique for enemy AI. Every enemy action should have a visible and audible signal that tells the player what is about to happen. A brief windup animation before an attack, a sound effect when the enemy detects the player, a color flash before a ranged shot, these cues give the player the information they need to react. Enemies that attack without warning feel unfair, even if their damage and speed are reasonable.

Reaction delays make enemies feel more realistic and give the player breathing room. Instead of reacting instantly to player actions, add brief delays between detection and chase, between reaching attack range and actually attacking, and between taking damage and resuming aggressive behavior. These delays, typically 200 to 500 milliseconds, are too short for the player to consciously notice but create a natural rhythm to combat encounters.

Test enemy behavior by playing your own game repeatedly. Watch for enemies that get stuck on geometry, oscillate between states rapidly, attack during inappropriate moments, or fail to respond to player actions. The best AI behavior is predictable enough for the player to learn patterns but varied enough to stay interesting across multiple encounters. If enemies feel frustrating rather than challenging, the issue is usually a missing telegraph, too-fast reaction time, or unfair attack timing.

Key Takeaway

Build enemy AI from simple behaviors composed into a state machine. Start with patrol movement, add distance-based detection, implement attack patterns, and polish with telegraphing and reaction delays. Effective game AI is about readable, fair behavior, not computational complexity.