{"id":19441544,"url":"https://github.com/antix-development/flow-field-generator","last_synced_at":"2026-06-10T01:31:16.754Z","repository":{"id":91497759,"uuid":"566235628","full_name":"Antix-Development/Flow-Field-Generator","owner":"Antix-Development","description":"Single destination Flow-Field Generator for grid based games","archived":false,"fork":false,"pushed_at":"2022-11-15T09:11:56.000Z","size":12,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-25T07:46:12.206Z","etag":null,"topics":["breadth-first-search","flow-field","flow-field-navigation","javascript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Antix-Development.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-15T08:48:26.000Z","updated_at":"2024-08-24T19:24:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"93871c72-a274-4da6-b656-f11fb58291cf","html_url":"https://github.com/Antix-Development/Flow-Field-Generator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Antix-Development/Flow-Field-Generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antix-Development%2FFlow-Field-Generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antix-Development%2FFlow-Field-Generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antix-Development%2FFlow-Field-Generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antix-Development%2FFlow-Field-Generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Antix-Development","download_url":"https://codeload.github.com/Antix-Development/Flow-Field-Generator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Antix-Development%2FFlow-Field-Generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34133404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["breadth-first-search","flow-field","flow-field-navigation","javascript"],"created_at":"2024-11-10T15:36:11.256Z","updated_at":"2026-06-10T01:31:16.698Z","avatar_url":"https://github.com/Antix-Development.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flow-Field Generator\n\n## About\n\nThe `FlowFieldGenerator` class can be used to create single source 2 dimensional flow-fields for grid based games from one target node in a graph, to all other nodes in the same graph that are deemed \"passable\". \n\nThis type of flow-field is useful in games where many actors are trying to find the shortest path to a single actor (many sources, one destination). \n\nThe `FlowFieldGenerator` class is based on the Python code found at [Flow Field Pathfinding for Tower Defense](https://www.redblobgames.com/pathfinding/tower-defense/#diagram-parents), and I would highly recommend reading that article as it contains a very good explanation about Breadth First Searching and how to use the technique to create flow-fields. \n\nThere are a number of files in this repository...\n- **grid2d.js** - A simple class for creating and manipulating 2 dimensional arrays of numbers. It is used to create a grid which is then passed to the FlowFieldGenerator class to be converted into a graph of nodes suitable for building flow-fields from. This file can be ignored. \n\n- **util.js** - Some dirty code to display the graph and allow some basic interaction with it. This file can also be ignored. \n\n- **index.html** - Contains an interactive demo of the FlowFieldGenerator class. \n\n- **test.html** - A small performance test for a graph 1000 x 1000 in size. Dumps results to the console, so open your dev tools. \n\n- **node.js** - A sparse graph node class.\n\n- **flowfieldgenerator.js** - The `FlowFieldGenerator` class. It should be fairly easy to follow and modify for your own applications. \n\nPlease open an issue or contact me (antix.development@gmail.com) if you have questions or suggestions on how to improve the performance of the `FlowFieldGenerator` class. \n\n\u003cbr\u003e\n\n## Properties\nThe `FlowFieldGenerator` class encapsulates the following properties:\n\n### `graph`\n*{[node] A 2 dimensional array of nodes*\n\n### `passableFilter`\n*{function} Called by `isPassable` to determine if a graph node is passable.*\n\n### `reached`\n*{number} Incremental counter used to identify graph nodes that have been reached during queries.*\n\n### `w`\n*Width of the graph.*\n\n### `h` \n*{number} Height of the graph.*\n\n\n### `deltas`\n*{[array]} an array offsets used when determining a graph nodes adjacent neighbors.*\n\n\n\u003cbr\u003e\n\n## Methods\nThe `FlowFieldGenerator` class encapsulates the following methods:\n\n\u003cbr\u003e\n\n### `graphFromArray(arr, convert = false)`\n*Create graph from the given 2 dimensional array.*\n\n@param {[number]} arr\n\n@convert {boolean} convert\n\nreturns {[node]} graph\n\n\u003cbr\u003e\n\nIf a an array of values is passed to `graphFromArray()`, you can also specify whether or not you want to convert the passed array into an array of nodes (mutated). By default, `graphFromArray()` will remain unchanged (not mutated).\n\n\u003cbr\u003e\n\n### `buildFlowField(x, y)`\n*Build (or rebuild) the flow-field wherein all passable nodes point towards the target node at the given coordinates.*\n\n@param {number} x\n\n@param {number} y\n\nThe target node located at the given x,y coordinates `distance` property will be set to 0. All other nodes in the graph that are \"reachable\" will have their `distance` property set to their distance from the target node.\n\n\u003cbr\u003e\n\n### `buildPathToTarget(x, y, trim = false)`\n*Build a path of nodes from the node at the given coordinates to the target node.*\n\n@param {number} x\n\n@param {number} y\n\n@param {boolean} trim\n\n@returns {[node]} path\n\nIf the node at the given x, y coordinates was able to be reached during the latest query, an array of nodes will be created (and returned) by back-tracking through its parent node property until it arrives at the target node.\n\nIf you choose to trim the path, it will not contain the nodes containing the source or destination coordinates.\n\n\u003cbr\u003e\n\n### `enableDiagonalMovement(state = true)`\n*Enable or disable the use of diagonal movement according to the given state.*\n\n@param {boolean} state\n\nNew instances of the `FlowFieldGenerator` class will have diagonal movement disabled.\n\nNOTE: If the given state is different than the current state, then the graph will be rebuilt.\n\n\u003cbr\u003e\n\n### `setPassableFilter(f)`\n*Set passible filter, called by `isPassable()`*\n\n@param {function} f \n\nYou can also set the passable filter by directly poking the `FlowFieldGenerator` instances `passableFilter` property.\n\n\u003cbr\u003e\n\n### `isPassable(x, y)`\n*Determine if the node at the given coordinates is passable.*\n\n@param {number} x\n\n@param {number} y\n\n@returns {boolean} passable\n\ncalls the current `passableFilter` function, passing it the graph node at the given x, y coordinates.\n\n\u003cbr\u003e\n\n### `defaultPassableFilter(node)`\n*Default filter called by `isPassable()`, determines whether the given node is passable*\n\n@param {node} node\n@returns {boolean}\n\nThe default function to determine if a node is deemed to be passable is\n\n```\ndefaultPassableFilter(node) {\n  return node.value === 0;\n}\n```\n\n\u003cbr\u003e\n\n### `getGraph()`\n*Get graph (a 2 dimensional array of node).*\n\n@returns {[node]} graph\n\nYou can also access graph by peeking the `FlowFieldGenerator` instances `graph` property.\n\n\u003cbr\u003e\n\n### `buildGraph()`\n*Connect nodes in the graph by creating neighboring node lists for every node contained within it.*\n\n\u003cbr\u003e\n\n### `buildNeighborsFor(node)`\n*Build neighbors list for the given node.*\n\n@param {node} node \n\n\u003cbr\u003e\n\n### `disconnect(node)`\n*Disconnect the given node from the graph.*\n\n@param {node} node \n\n\u003cbr\u003e\n\n### `reconnect(node)`\n*Reconnect a previously disconnected node to the graph.*\n\n@param {node} node \n\n\u003cbr\u003e\n\n## Usage\n\nUsing the `FlowFieldGenerator` class in your own projects should be fairly straightforward.\n\n```\n  // You will need to include the following \n  // two scripts in your code..\n\n  \u003cscript src=\"node.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"flowfieldgenerator.js\"\u003e\u003c/script\u003e\n\n  // Create a 2d grid 20 wide and 10 high  \n  let grid = [];\n  for (let y = 0; y \u003c 10; y++) {\n    let row = [];\n    for (let x = 0; x \u003c 20; x++) {\n      row.push(0);\n    }\n    grid.push(row);\n  }\n\n  // Create a new instance of the class\n  const ffg = new FlowFieldGenerator();\n\n  // Set the filter called when `isPassable()` is \n  // called by the class instance\n  ffg.setPassableFilter((v) =\u003e (v === 0));\n\n  // Enable diagonal movement\n  ffg.enableDiagonalMovement(true);\n\n  // Create the graph from our 2d array of values\n  graph = ffg.graphFromArray(grid);\n\n  // Create a flow-field with all empty nodes \n  // pathing to 10, 5\n  ffg.buildFlowField(10, 5);\n\n  // Build a path from 16, 8 to 10, 5\n  let path = ffg.buildPathToTarget(16, 8);\n\n  // Output the result\n  console.log(path);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantix-development%2Fflow-field-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantix-development%2Fflow-field-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantix-development%2Fflow-field-generator/lists"}