{"id":14963967,"url":"https://github.com/mikewesthad/navmesh","last_synced_at":"2025-04-05T23:08:03.243Z","repository":{"id":32672690,"uuid":"93898108","full_name":"mikewesthad/navmesh","owner":"mikewesthad","description":"A plugin for path-finding in JS using navmeshes, with wrappers for Phaser 3 and Phaser 2","archived":false,"fork":false,"pushed_at":"2023-11-01T08:47:01.000Z","size":12406,"stargazers_count":355,"open_issues_count":26,"forks_count":40,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-10-30T00:42:50.352Z","etag":null,"topics":["pathfinding","phaser"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikewesthad.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-06-09T21:27:55.000Z","updated_at":"2024-10-10T08:59:38.000Z","dependencies_parsed_at":"2024-01-16T14:03:52.454Z","dependency_job_id":"46303f08-bbb0-4f9a-aafc-11d85401de48","html_url":"https://github.com/mikewesthad/navmesh","commit_stats":{"total_commits":372,"total_committers":6,"mean_commits":62.0,"dds":"0.034946236559139754","last_synced_commit":"7606d96bac0b374329a11ff9c071cf7c40cd9755"},"previous_names":["mikewesthad/phaser-navmesh-plugin"],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikewesthad%2Fnavmesh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikewesthad%2Fnavmesh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikewesthad%2Fnavmesh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikewesthad%2Fnavmesh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikewesthad","download_url":"https://codeload.github.com/mikewesthad/navmesh/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247037498,"owners_count":20873169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pathfinding","phaser"],"created_at":"2024-09-24T13:32:24.293Z","updated_at":"2025-04-05T23:08:03.217Z","avatar_url":"https://github.com/mikewesthad.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Navigation Meshes Overview \u003c!-- omit in toc --\u003e\n\nA JS plugin for fast pathfinding using [navigation meshes](https://en.wikipedia.org/wiki/Navigation_mesh), with optional wrappers for the Phaser v2 and Phaser v3 game engines.\n\n[\u003cimg src=\"./doc-source/single-following-agent.gif\" width=\"400\"\u003e](https://www.mikewesthad.com/navmesh/demo/)\n\n[Interactive demo](https://www.mikewesthad.com/navmesh/demo/)\n\n(Note: if you are viewing this on GitHub or NPM, you might want to check out the HTML documentation [here](https://www.mikewesthad.com/navmesh/docs/).)\n\nTable of Contents:\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n  - [As a Script](#as-a-script)\n  - [As a Module](#as-a-module)\n- [Creating a Navigation Mesh](#creating-a-navigation-mesh)\n- [Usage](#usage)\n  - [navmesh (API reference)](#navmesh-api-reference)\n  - [phaser-navmesh (API reference)](#phaser-navmesh-api-reference)\n  - [phaser2-navmesh (API reference)](#phaser2-navmesh-api-reference)\n- [Performance Comparison](#performance-comparison)\n- [Community Examples](#community-examples)\n- [Development](#development)\n- [Changelogs](#changelogs)\n- [References](#references)\n- [To Dos](#to-dos)\n\n## Introduction\n\nPathfinding is essentially the problem of solving a maze, finding a path between points while avoiding obstacles. When pathfinding in games, we need to:\n\n1.  Represent the game world in a way that defines what areas are walkable.\n2.  Search that representation for the shortest path.\n\nWhen it comes to 2D pathfinding, a common approach is to represent the world using [tiles](https://developer.mozilla.org/en-US/docs/Games/Techniques/Tilemaps) (a grid) and then search for a path using the [A\\* algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm) (e.g. [Phaser AStar](https://github.com/photonstorm/phaser-plugins/tree/master/AStar)). If you have a 50 x 50 tile world, searching for a path involves searching through a representation of the world with up to 2500 locations/nodes (50 x 50 = 2500).\n\nThis plugin uses navigation meshes to simplify that 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.\n\nThe 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).\n\n\u003cimg src=\"./doc-source/combined.png\" width=\"700\"\u003e\n\n## Installation\n\nThis repository contains 3 related JS packages:\n\n- `navmesh` - core logic, game-engine agnostic, usable outside of Phaser.\n- `phaser-navmesh` - Phaser v3 wrapper around `navmesh` that creates a Phaser 3 Scene plugin. Phaser 3 is expected to be a dependency in your project.\n- `phaser2-navmesh` - Phaser v2 wrapper around `navmesh` that creates a Phaser 2 game plugin. Phaser 2 or Phaser-ce is expected to be in the global scope.\n\nYou can use any of them as a script or as a module in your bundler of choice.\n\n### As a Script\n\nYou can drop in any of the transpiled code into your project as a standalone script. Download the version that you want from the [GitHub release](https://github.com/mikewesthad/navmesh/releases/tag/2.1.0).\n\nE.g. if you wanted phaser-navmesh, you would add this to your HTML:\n\n```html\n\u003cscript src=\"phaser-navmesh.min.js\"\u003e\u003c/script\u003e\n```\n\nInside of your own script, you can now use the global variable `PhaserNavMeshPlugin` (see library name in the above table), e.g.\n\n```js\nconst game = new Phaser.Game({\n  type: Phaser.AUTO,\n  width: 750,\n  height: 750,\n  plugins: {\n    scene: [\n      { key: \"NavMeshPlugin\", plugin: PhaserNavMeshPlugin, mapping: \"navMeshPlugin\", start: true }\n    ]\n  }\n});\n```\n\nSee [usage](#usage) for more information on how to use each of the three modules in this repository.\n\n### As a Module\n\nInstall the appropriate dependency:\n\n- `npm install --save navmesh` for usage outside of Phaser\n- `npm install --save phaser-navmesh` for Phaser 3\n- `npm install --save phaser2-navmesh` for Phaser 2\n\nTo use the transpiled and minified distribution of the library (recommended for most users):\n\n```js\n// Phaser 3\nimport { PhaserNavMeshPlugin } from \"phaser-navmesh\";\n\n// Phaser 2\nimport { Phaser2NavMeshPlugin } from \"phaser2-navmesh\";\n\n// NavMesh (commonjs or es import)\nconst { NavMesh } = require(\"navmesh\");\nimport { NavMesh } from \"navmesh\";\n```\n\nTo use the raw TypeScript source code so you can optimize the bundle yourself:\n\n```js\nimport { PhaserNavMeshPlugin } from \"phaser-navmesh/src\";\n```\n\n## Creating a Navigation Mesh\n\nCreating a navigation mesh is the process of defining the walkable areas within you world as a series of polygons. If you are using a tilemap, then you can probably get away with just auto-generating the mesh using [buildMeshFromTilemap](https://www.mikewesthad.com/navmesh/docs/classes/phaser_navmesh.phasernavmeshplugin.html#buildmeshfromtilemap) in Phaser 3 (or if you are using NavMesh without the Phaser wrapper, see [buildPolysFromGridMap](https://www.mikewesthad.com/navmesh/docs/modules/navmesh.html#buildpolysfromgridmap)).\n\nIf you've got a more complex situation, you can use a tilemap editor like Tiled to create your mesh\nand load it into the game. See\n[guide](https://github.com/mikewesthad/navmesh/blob/master/tiled-navmesh-guide.md).\n\n(Note: the current version of the library only supports [convex polygons](https://www.sparknotes.com/math/geometry1/polygons/section2/). There are libraries like [poly-decom.js](https://github.com/schteppe/poly-decomp.js/) for decomposing a concave polygon into easier to manage convex polygons. It's on the to do list to handle any polygon, but I've found that automatically decomposing polygons leads to worse performance than hand-mapping the levels with convex polygons.)\n\n## Usage\n\nYou can find code snippets for the different use cases below. You can also jump directly to a few example projects in this repository for:\n\n- [phaser 3](https://github.com/mikewesthad/navmesh/tree/master/packages/examples-phaser3)\n- [phaser 2](https://github.com/mikewesthad/navmesh/tree/master/packages/examples-phaser2)\n- [navmesh in a node environment](https://github.com/mikewesthad/navmesh/tree/master/packages/examples-node)\n\n### navmesh ([API reference](https://www.mikewesthad.com/navmesh/docs/modules/navmesh.html))\n\nIf you don't need the Phaser wrappers, you can construct navmeshes directly from points using the navmesh package:\n\n```js\nimport { NavMesh } from \"navmesh\";\n\n/*\n  Imaging your game world has three walkable rooms, like this:\n\n    +-----+-----+\n    |     |     |\n    |  1  |  2  |\n    |     |     |\n    +-----------+\n          |     |\n          |  3  |\n          |     |\n          +-----+\n*/\n\n// The mesh is represented as an array where each element contains the points for an indivdual\n// polygon within the mesh.\nconst meshPolygonPoints = [\n  [{ x: 0, y: 0 }, { x: 10, y: 0 }, { x: 10, y: 10 }, { x: 0, y: 10 }], // Polygon 1\n  [{ x: 10, y: 0 }, { x: 20, y: 0 }, { x: 20, y: 10 }, { x: 10, y: 10 }], // Polygon 2\n  [{ x: 10, y: 10 }, { x: 20, y: 10 }, { x: 20, y: 20 }, { x: 10, y: 20 }] // Polygon 3\n];\nconst navMesh = new NavMesh(meshPolygonPoints);\n\n// Find a path from the top left of room 1 to the bottom left of room 3\nconst path = navMesh.findPath({ x: 0, y: 0 }, { x: 10, y: 20 });\n// ⮡  [{ x: 0, y: 0 }, { x: 10, y: 10 }, { x: 10, y: 20 }]\n```\n\nIf your world is a grid (e.g. a tilemap), NavMesh also has a utility [buildPolysFromGridMap](https://www.mikewesthad.com/navmesh/docs/modules/navmesh.html#buildpolysfromgridmap) that can automatically generate meshPolygonPoints from a 2D array. \n\n### phaser-navmesh ([API reference](https://www.mikewesthad.com/navmesh/docs/modules/phaser_navmesh.html))\n\nIf you are working with Phaser 3, you can use the phaser-navmesh package, which provides a Scene plugin. Play with a live example on CodeSandbox [here](https://codesandbox.io/s/zq1wvozxll?fontsize=14), or peek at the [examples](https://github.com/mikewesthad/navmesh/tree/master/packages/examples/src) in this repository for more complete usage.\n\n```js\nimport Phaser from \"phaser\";\nimport { PhaserNavMeshPlugin } from \"phaser-navmesh\";\n\nconst game = new Phaser.Game({\n  type: Phaser.AUTO,\n  parent: \"game-container\",\n  width: 750,\n  height: 750,\n  plugins: {\n    scene: [\n      {\n        key: \"PhaserNavMeshPlugin\", // Key to store the plugin class under in cache\n        plugin: PhaserNavMeshPlugin, // Class that constructs plugins\n        mapping: \"navMeshPlugin\", // Property mapping to use for the scene, e.g. this.navMeshPlugin\n        start: true\n      }\n    ]\n  },\n  scene: {\n    preload: preload,\n    create: create\n  }\n});\n\nfunction preload() {\n  this.load.tilemapTiledJSON(\"map\", \"tilemaps/map.json\");\n  this.load.image(\"tiles\", \"tilemaps/tiles.png\");\n}\n\nfunction create() {\n  // Set up a tilemap with at least one layer\n  const tilemap = this.add.tilemap(\"map\");\n  const tileset = tilemap.addTilesetImage(\"tiles\", \"tiles\");\n  const wallLayer = tilemap.createStaticLayer(\"walls\", tileset);\n  wallLayer.setCollisionByProperty({ collides: true }); // Or, however you set tiles to collide.\n\n  // Automatically generate mesh from colliding tiles in a layer or layers: \n  const navMesh = this.navMeshPlugin.buildMeshFromTilemap(\"mesh\", tilemap, [wallLayer]);\n  const path = navMesh.findPath({ x: 0, y: 0 }, { x: 300, y: 400 });\n  // ⮡  path will either be null or an array of Phaser.Geom.Point objects\n\n  // Alternatively, you can load a navmesh created by hand in Tiled that is stored in an object \n  // layer. See the creating a navmesh guide for more info on this.\n  // const objectLayer = tilemap.getObjectLayer(\"navmesh\");\n  // const navMesh = this.navMeshPlugin.buildMeshFromTiled(\"mesh1\", objectLayer, 12.5);\n}\n```\n\nThe plugin comes with some methods for visually debugging your navmesh:\n\n```js\nnavMesh.enableDebug(); // Creates a Phaser.Graphics overlay on top of the screen\nnavMesh.debugDrawClear(); // Clears the overlay\n// Visualize the underlying navmesh\nnavMesh.debugDrawMesh({\n  drawCentroid: true,\n  drawBounds: false,\n  drawNeighbors: true,\n  drawPortals: true\n});\n// Visualize an individual path\nnavMesh.debugDrawPath(path, 0xffd900);\n```\n\n### phaser2-navmesh ([API reference](https://www.mikewesthad.com/navmesh/docs/modules/phaser2_navmesh.html))\n\nIf you are working with Phaser 2, you can use the phaser2-navmesh package, which provides a game plugin. See this [example](https://github.com/mikewesthad/navmesh/tree/master/packages/examples-phaser2/src) for more complete usage. You can also look at the [previous section](#phaser-navmesh) for Phaser usage.\n\n## Performance Comparison\n\n_(Note: these comparisons were done in any earlier verison of the repo before Phaser v3 was released. The plugins tested haven't been released in v3 versions yet, so this section could use an update. That said, the results should be the same.)_\n\nComparing this navmesh plugin against:\n\n- [Phaser's grid-based A\\* plugin](https://github.com/photonstorm/phaser-plugins). Navmesh is approximately 5x - 150x faster.\n- A faster, grid-based A\\* search, [EasyStar.js](https://github.com/prettymuchbryce/easystarjs). Navmesh is approximately 5x - 20x faster.\n\nPerformance depends on the size of the area that needs to be searched. Finding for a path between points that are 50 pixels away is (generally) going to be much faster than finding a path between points that are 5000 pixels away.\n\nDetails (see [src/library/performance](https://github.com/mikewesthad/navmesh/tree/master/src/examples/performance)):\n\n```\nPerformance Comparison, 100000 iterations, 30x30 tilemap\n\nShort paths (150 - 500 pixel length)\n\n    Average time per iteration:\n        AStart Plugin: 0.02470ms\n        EasyStar Plugin: 0.02876ms\n        NavMesh Plugin: 0.00575ms\n\n    Comparison:\n        NavMesh is 4.30x faster than Phaser AStar\n        NavMesh is 5.00x faster than EasyStar\n\nLong paths (600 pixels and greater length), average time per iteration:\n\n    Average time per iteration:\n        AStart Plugin: 1.38710ms\n        EasyStar Plugin: 0.15977ms\n        NavMesh Plugin: 0.00738ms\n\n    Comparison:\n        NavMesh is 187.95x faster than Phaser AStar\n        NavMesh is 21.65x faster than EasyStar\n```\n\n## Community Examples\n\n- [TypeScript Server Example](https://colyseus-unity3d-navmesh.firebaseapp.com) - Right click to move the agent, see discussion thread [here](https://github.com/mikewesthad/navmesh/issues/11#issuecomment-595211483) with links to source code.\n\n## Development\n\nPull requests are welcome (see [todos](#to-dos))! If you want to run this repo locally, make sure you have [node](https://nodejs.org/en/) installed. Download the repo, open a terminal in the repo folder and run:\n\n```\nnpm i -g yarn\nyarn\nyarn bootstrap\n```\n\nThis project uses [lerna](https://github.com/lerna/lerna) and [yarn workspaces](https://yarnpkg.com/lang/en/docs/workspaces/) to manage multiple packages within one repository. `npx yarn` will pull the root dependencies (and install yarn if needed) and `npm run bootstrap` will use lerna \u0026 yarn to pull and link dependencies within \"packages/\". This project has the following packages:\n\n- `navmesh` - core logic, game-engine agnostic\n- `phaser-navmesh` - Phaser Plugin v3 wrapper around `navmesh`\n- `phaser2-navmesh` - Phaser Plugin v2 wrapper around `navmesh`\n\nThe project is controlled via npm scripts. The main ones to use:\n\n- `yarn build:libs` - will build production versions of the three libraries within \"packages/\".\n- `yarn test` - will run the automated tests against the libraries.\n- `serve:examples` - will build, serve and watch the three examples. Phaser 3 examples are at [localhost::8080](http://localhost:8080/), Phaser 2 examples at [localhost::8081](http://localhost:8081/) and node examples at [localhost::8082](http://localhost:8082/).\n- `yarn dev` - watch the libraries \u0026 serve the examples.  If you are working on the library, this is the easiest way to do \"functional testing\" by using the library in a game environment.\n- `yarn dev:phaser3`, `yarn dev:phaser2`, `yarn dev:node` - these will watch the relevant libraries and serve one the corresponding example. Useful for dev on a specific library.\n\nA few tips, because Lerna + Yarn is complicated, and I keep forgetting these:\n\n- Running a command in a workspace:\n  - `yarn workspace \u003cworkspace_name\u003e \u003ccommand\u003e` \n  - Example: `yarn workspace navmesh add typescript --dev`\n- Running a command in a set of workspaces:\n  - `lerna run --parallel watch --scope \u003cscope\u003e`\n  - Example: `lerna run --parallel build --scope '{navmesh,phaser-navmesh,phaser-navmesh}'`\n- Add a dev dependency to the root:\n  - `yarn add \u003cdependency\u003e --dev -W`\n- Running a command in all workspaces:\n  - `yarn workspaces \u003ccommand\u003e` \n  - Example: `yarn workspaces build`\n  - `lerna run --parallel watch`\n\n## Changelogs\n\n- [Phaser NavMesh (for Phaser v3)](https://github.com/mikewesthad/navmesh/blob/master/packages/phaser-navmesh/README.md)\n- [Phaser 2 NavMesh](https://github.com/mikewesthad/navmesh/blob/master/packages/phaser2-navmesh/README.md)\n- [NavMesh](https://github.com/mikewesthad/navmesh/blob/master/packages/navmesh/README.md)\n\n## References\n\nHelpful resources used while building this plugin:\n\n- Inspired by [PatrolJS](https://github.com/nickjanssen/PatrolJS), an implementation of navmeshes for threejs\n- Navmesh path-finding algorithm explanations:\n  - [Game Path Planning by Julian Ceipek](http://jceipek.com/Olin-Coding-Tutorials/pathing.html)\n  - [Simple Stupid Funnel Algorithm](http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html)\n- [Advice on astar heuristics](http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html)\n\n## To Dos\n\n- Features\n  - Allow non-square navmesh polygons from Tiled - ideally, any convex shape.\n  - Reimplement the autotessalation version of the lib \u0026 try libtess in quad mode.\n  - The astar heuristic \u0026 cost functions need another pass. They don't always produce the shortest path. Implement incomplete funneling while building the astar path?\n  - The navmesh assumes any polygon can reach any other polygon. This probably should be extended to put connected polygons into groups like patroljs.\n  - Better warnings for devs - warn on empty map, warn on disconnected map, warn if polygons are malformed.\n  - Factor in the layer position / scale / rotation\n- Testing\n  - Check against tilemap that is larger than the screen\n- Research\n  - There are probably optimization tricks to do when dealing with certain types of shapes. E.g. we are using axis-aligned boxes for the polygons and it is dead simple to calculate if a point is inside one of those...\n  - Investigate [Points-of-Visibility](http://www.david-gouveia.com/portfolio/pathfinding-on-a-2d-polygonal-map/) pathfinding to compare speed\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikewesthad%2Fnavmesh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikewesthad%2Fnavmesh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikewesthad%2Fnavmesh/lists"}