Mastering 2D Game Path Finding with Phaser3 — AI Path Finding

Tajammal Maqbool
5 min readDec 28, 2023

--

Introduction

Embarking on the journey of game development often leads developers to the intricate realm of pathfinding. In this blog post, we will explore the fascinating world of 2D game pathfinding using the powerful Phaser3-NavMesh plugin in Phaser. Join us as we unravel the secrets behind creating fluid and intelligent navigation systems that will elevate your game to new heights.

Path Finding

Understanding the Importance of Pathfinding:

Efficient pathfinding is the backbone of engaging 2D games, enabling characters to navigate dynamic environments, avoid obstacles, and respond intelligently to player input. Phaser3-NavMesh is a game-changer, offering a user-friendly solution for implementing sophisticated pathfinding algorithms with ease.

Getting Started with Phaser3-NavMesh:

Phaser3-NavMesh is a plugin that uses navigation meshes to simplify the search. Instead of representing the world as a grid of tiles, it represents the walkable areas of the world as a mesh. That means that the representation of the world has far fewer nodes, and hence, can be searched much faster than the grid approach. This approach is 5x — 150x faster than Phaser’s A* plugin (see performance section), depending on the mesh.

Path Finding with Phaser3-NavMesh

The example map below (left) is a 30 x 30 map. As a grid, there are 900 nodes, but as a navmesh (right) there are 27 nodes (colored rectangles).

Example of NavMesh

Working Example with Code:

I have made a project where I used it for finding the path. Here you can check the code and follow it same for your project.

Setup Plugin:

First need to setup it by updating the config of Phaser Game. Add a plugin section in it as here added.

import Phaser from 'phaser';
import { PhaserNavMeshPlugin } from "phaser-navmesh";
import MainScene from "./mainScene.js";
import { DEBUG_PHYSICS } from './settings.js';

const config = {
type: Phaser.WEBGL,
width: 800,
height: 500,
antialias: true,
autoRound: false,
roundPixels: false,
pixelArt: false,
mipmapFilter: 'LINEAR_MIPMAP_LINEAR',
parent: "game",
physics: {
default: 'matter',
matter: {
gravity: { x: 0, y: 0 },
sleepEnabled: true,
debug: DEBUG_PHYSICS
},
},
dom: {
createContainer: true
},
plugins: {
scene: [
{
key: "PhaserNavMeshPlugin",
plugin: PhaserNavMeshPlugin,
mapping: "navMeshPlugin",
start: true
}
]
},
scene: [MainScene]
}

export default config;

Create NavMesh Rectangles:

After basic setup, Now we need here make a NavMesh, I used Tiled Tool to create it (See guide).

Tiled Tool to make NavMesh

You will get WALKABLE_RECTANGLES from that tool after performing the all steps. Or you can make rectangles manually but it will more time wasting.

Add NavMesh Rectangles:

Now we are ready to add NavMesh in our scene. Check this code How I added in my scene. I am also debugging it to check where my rectangles are going to add.

import Phaser from 'phaser';
import Player from "./player.js";
import { DEBUG_RECTANGLES } from "./settings.js";


const WALKABLE_RECTANGLES = [
{
"height": 96,
"id": 1,
"name": "",
"rotation": 0,
"type": "",
"visible": true,
"width": 364.8,
"x": 83.2,
"y": 64
},
{
"height": 275.2,
"id": 2,
"name": "",
"rotation": 0,
"type": "",
"visible": true,
"width": 83.2,
"x": 83.2,
"y": 160
},
{
"height": 96.0000000000001,
"id": 3,
"name": "",
"rotation": 0,
"type": "",
"visible": true,
"width": 300.8,
"x": 140.8,
"y": 435.2
},
{
"height": 64.0000000000001,
"id": 4,
"name": "",
"rotation": 0,
"type": "",
"visible": true,
"width": 294.4,
"x": 441.6,
"y": 467.2
}
]

class MainScene extends Phaser.Scene {
constructor() {
super("MainScene");

this.ImagesJSON = {
"bg": "assets/images/bg.jpeg",
"profile1": "assets/images/profile (1).png",
"profile2": "assets/images/profile (2).png",
"profile3": "assets/images/profile (3).png",
}

this.players = [];
this.backgroundColliders = [];
this.objectLayer = null;
this.navMesh = null;
}

preload() {
// load images
Object.keys(this.ImagesJSON).forEach((key) => {
this.load.image(key, this.ImagesJSON[key]);
});
}

create() {
const bg = this.add.image(0, 0, "bg").setOrigin(0, 0);

// add rectangles
WALKABLE_RECTANGLES.forEach((rectangle) => {
const rect = this.add.rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, 0x000000);
rect.setOrigin(0, 0);
rect.setAlpha(DEBUG_RECTANGLES ? 0.5 : 0);
});

// add players
const p1 = new Player(this, 200, 100, "user1", "profile1", true);
this.players.push(p1);
const p2 = new Player(this, 120, 200, "user2", "profile2", false);
this.players.push(p2);

// createObjectLayer and add to navMesh
this.objectLayer = this.createObjectLayer();
this.navMesh = this.navMeshPlugin.buildMeshFromTiled("navmesh", this.objectLayer, 32); // name, objectLayer, TileSize

// world bounds
this.matter.world.setBounds(0, 0, bg.width, bg.height);
this.matter.world.disableGravity();

// camera bouunds
this.cameras.main.setBounds(0, 0, bg.width, bg.height);
}

update() {
this.players.forEach((player) => {
player.update();
});
}

createObjectLayer() {
let objectLayer = {
name: "navmesh",
objects: [],
opacity: 1,
properties: {},
propertyTypes: {},
type: "objectgroup",
visible: true,
};
WALKABLE_RECTANGLES.forEach((rect) => {
objectLayer.objects.push(rect);
});
return objectLayer;
}
}


export default MainScene;

Output is here you can check it, my rectangles are now added and also I am getting on the screen due to debuggin enabled.

Rectangles of NavMesh

Find Path:

To find the Path between two points, you need to use the function findPath in navmesh. See below.

const path = this.navMesh.findPath({ x: 200, y: 300 }, { x: 400, y: 345});

Path variable will be the array of points or null. Now you have done the path finding, you can follow your AI Enemy to on that path to catch the Player.

Real-World Examples:

Enhancing RPG Gameplay:

  • Explore how Phaser3-NavMesh can be applied to improve pathfinding in RPGs.
  • Discuss scenarios like navigating towns, dungeons, and complex terrains.

Optimizing Performance:

  • Provide tips on optimizing pathfinding performance for larger game worlds.
  • Discuss strategies for efficiently handling multiple characters with unique navigation needs.

Conclusion:

Phaser3-NavMesh opens up a world of possibilities for 2D game developers, simplifying the implementation of advanced pathfinding and allowing for the creation of immersive and dynamic gameplay experiences. As you embark on your journey with Phaser3-NavMesh, may your game characters navigate seamlessly through the intricacies of your imaginative worlds. Happy coding!

--

--

Tajammal Maqbool

🌐 Website & Game Developer | 🎓 CS Graduate | ✍️ Writer | 💻 Freelancer | 📚 Motivated to Teach | 🎙️ Speaker | 🔧 Engineer | 🚀 Visit www.tajammalmaqbool.com