
Snake Game in Phaser 3: Build It With an AI Bot
Controls: Arrow keys to move · Press B to toggle AI bot mode · Press R to restart
You are about to learn how to build a snake game in Phaser for beginners, step by step, and then give your snake a brain. By the end you will have a working Snake game with two modes: manual control, and an AI bot that plays by itself. You will learn grid-based movement, collision detection, and a simple greedy pathfinding algorithm that powers the bot. Everything you need is one HTML file.
How This Guide Was Built
This tutorial synthesizes the official Phaser getting-started guide, the Phaser GitHub repository, the Wikipedia Snake genre entry, the Wikipedia Greedy algorithm article, and a community snake-ai pathfinding project. The code examples follow the Phaser 3 API as documented in the official getting-started tutorial, and the playable demo embedded above is the verification — run it and watch the bot play. Sources are official documentation and community reports. Last verified: August 2026.
What Is a Snake Game?
A Snake game is a grid-based arcade game where the player controls a growing line that must eat food without hitting walls or itself. Snake-style games date to the mid-1970s arcade era, starting with Blockade in 1976, per Wikipedia. The core loop: move one cell per tick, eat food to grow, and avoid self-collision. For more practice after this, browse our other beginner game tutorials on the games hub.
How to Build a Snake Game in Phaser for Beginners
Building a Snake game in Phaser 3 for beginners involves five steps: configure the game with Scale.FIT and CENTER_BOTH as shown in the official tutorial, create a grid-based coordinate system, handle arrow-key input, run a tick-based loop with this.time.addEvent, and detect collisions with Arcade Physics. The snake moves one cell per tick, not continuously. Food spawns at random grid positions, and eating it makes the snake grow. New to Phaser? Start with our Phaser Pong tutorial first.
Setting Up the Phaser 3 Project
Setting up a Phaser 3 project requires an HTML file, the Phaser library, and a game configuration object that tells Phaser what to render. The Phaser GitHub repository hosts the MIT-licensed source and installation instructions. Here is a minimal config that creates a 640x480 game with Arcade Physics and responsive scaling, mirroring our Breakout tutorial.
const config = {
type: Phaser.AUTO,
width: 640,
height: 480,
parent: 'game-container',
scene: SnakeScene,
physics: { default: 'arcade' },
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
}
};
new Phaser.Game(config);
Building the Snake Grid and Movement
Building the snake grid means representing the play area as a fixed grid and moving the snake one cell per tick. The snake is an array of segment objects with x and y grid coordinates. On each tick you add a new head in the current direction and remove the tail, unless the snake just ate food. Arrow keys change direction. The complete scene class below implements all of this, based on the pattern from the official getting-started tutorial.
class SnakeScene extends Phaser.Scene {
constructor() { super('SnakeScene'); }
create() {
this.gridSize = 20;
this.snake = [{ x: 10, y: 10 }];
this.direction = { x: 1, y: 0 };
this.nextDirection = { x: 1, y: 0 };
this.grow = false;
this.score = 0;
this.botActive = false;
this.cursors = this.input.keyboard.createCursorKeys();
this.keyB = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.B);
this.keyR = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.R);
this.scoreText = this.add.text(16, 16, 'Score: 0', { fontSize: '20px', fill: '#fff' });
this.spawnFood();
this.time.addEvent({
delay: 150,
callback: this.tick,
callbackScope: this,
loop: true
});
}
tick() {
this.direction = this.nextDirection;
if (this.botActive) this.botMove();
const head = this.snake[0];
const newHead = {
x: head.x + this.direction.x,
y: head.y + this.direction.y
};
this.snake.unshift(newHead);
if (this.grow) {
this.grow = false;
} else {
this.snake.pop();
}
this.checkCollision();
}
update() {
if (Phaser.Input.Keyboard.JustDown(this.keyB)) this.botActive = !this.botActive;
if (Phaser.Input.Keyboard.JustDown(this.keyR)) this.scene.restart();
if (!this.botActive) {
if (this.cursors.left.isDown && this.direction.x !== 1) this.nextDirection = { x: -1, y: 0 };
if (this.cursors.right.isDown && this.direction.x !== -1) this.nextDirection = { x: 1, y: 0 };
if (this.cursors.up.isDown && this.direction.y !== 1) this.nextDirection = { x: 0, y: -1 };
if (this.cursors.down.isDown && this.direction.y !== -1) this.nextDirection = { x: 0, y: 1 };
}
this.scoreText.setText('Score: ' + this.score);
}
}
Spawning Food and Detecting Collisions
Spawning food means picking a random grid cell that does not overlap the snake, and collision detection checks whether the head touches food, a wall, or its own body. When the head matches the food position, the snake grows by one segment and the score increases. Self-collision or hitting a wall triggers a scene restart, using the API documented in the Phaser GitHub repository. Add these two methods to the class above.
spawnFood() {
let valid = false;
while (!valid) {
this.food = {
x: Phaser.Math.Between(0, this.gridSize - 1),
y: Phaser.Math.Between(0, this.gridSize - 1)
};
valid = !this.snake.some(s => s.x === this.food.x && s.y === this.food.y);
}
}
checkCollision() {
const head = this.snake[0];
const hitWall = head.x < 0 || head.x >= this.gridSize ||
head.y < 0 || head.y >= this.gridSize;
if (hitWall) { this.scene.restart(); return; }
for (let i = 1; i < this.snake.length; i++) {
if (head.x === this.snake[i].x && head.y === this.snake[i].y) {
this.scene.restart();
return;
}
}
if (head.x === this.food.x && head.y === this.food.y) {
this.grow = true;
this.score += 10;
this.spawnFood();
}
}
Adding a Greedy AI Bot Mode
A greedy AI bot picks the locally optimal move at each step without planning ahead, as described in the Wikipedia Greedy algorithm article. On each tick the bot evaluates all valid directions — excluding reversal, out-of-bounds moves, and body hits — and picks the one that minimizes Manhattan distance to the food, a pattern outlined in the snake-ai pathfinding project on GitHub. The B key toggles bot mode, and the class above already listens for it.
botMove() {
const head = this.snake[0];
const options = [
{ x: 1, y: 0 }, { x: -1, y: 0 },
{ x: 0, y: 1 }, { x: 0, y: -1 }
].filter(d => {
const nx = head.x + d.x;
const ny = head.y + d.y;
const inBounds = nx >= 0 && nx < this.gridSize && ny >= 0 && ny < this.gridSize;
const notReverse = !(d.x === -this.direction.x && d.y === -this.direction.y);
const notBody = !this.snake.some(s => s.x === nx && s.y === ny);
return inBounds && notReverse && notBody;
});
if (options.length === 0) return;
let best = options[0];
let bestDist = Infinity;
for (const d of options) {
const dist = Math.abs(head.x + d.x - this.food.x) + Math.abs(head.y + d.y - this.food.y);
if (dist < bestDist) {
best = d;
bestDist = dist;
}
}
this.nextDirection = best;
}
For a deeper explanation of this pattern, see our adding a bot mode guide.
Game Over, Score Display, and Restart
Game over occurs when the snake hits a wall or itself, and restart reloads the scene with this.scene.restart(). The score is a text object that updates on every food eaten, and the R key restarts the game, following the same pattern used in our Tetris in Phaser tutorial. All of this is already in the complete class above — the assembled source is the playable demo embedded at the top of this page.
What You Learned
- Phaser 3 scene lifecycle — how
createandupdatework together to run a game loop. - Grid-based movement — using a tick timer and array manipulation to move the snake.
- Collision detection — checking head-to-food, head-to-wall, and head-to-body overlap.
- Greedy pathfinding — evaluating local options to pick the best direction toward food.
- Game mode toggling — switching between player input and bot control with a key press.
FAQ
Can I build a snake game in Phaser 3 without any prior game dev experience?
Yes, you can build a snake game in Phaser 3 without prior game dev experience if you know basic JavaScript. This tutorial covers everything from the config object to the AI bot, with code you can copy and run. The official Phaser getting-started guide provides the foundation, and the rest is simple math and array manipulation.
How does the greedy AI bot decide which direction to move?
The greedy AI bot evaluates all valid adjacent cells on each tick, excluding reverse moves, walls, and cells occupied by the snake’s body. It then picks the move that minimizes Manhattan distance to the food, which is the sum of horizontal and vertical differences. This is a classic greedy approach, as described in the Wikipedia Greedy algorithm article.
What is the difference between Arcade Physics and Matter Physics in Phaser 3?
Arcade Physics is the simpler system for grid and rectangle-based games, providing basic collision and overlap checks with minimal setup. Matter Physics is a full physics engine with gravity, rotation, and complex bodies, which is overkill for a Snake game. The Phaser GitHub repository documents both, but Snake only needs Arcade Physics.
Where to Go Next
Now that you have a working Snake game with an AI bot, try extending it. Add wall obstacles to make the bot’s pathfinding harder, or implement A* pathfinding instead of greedy for smarter movement. Add controller support with our Phaser gamepad controls guide, persist high scores with our save system tutorial, or explore more projects on the games hub.