{"id":15722595,"url":"https://github.com/selimanac/defold-astar","last_synced_at":"2025-04-12T02:25:33.129Z","repository":{"id":44100781,"uuid":"196403206","full_name":"selimanac/defold-astar","owner":"selimanac","description":"Pathfinder and A* solver (astar or a-star) native extension for Defold Engine build on MicroPather.","archived":false,"fork":false,"pushed_at":"2024-12-09T09:02:37.000Z","size":2884,"stargazers_count":86,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T02:25:28.640Z","etag":null,"topics":["a-star","astar","astar-algorithm","astar-pathfinding","defold","defold-game-engine","defold-library","micropather","pather","pathfinder","pathfinding"],"latest_commit_sha":null,"homepage":"https://selimanac.github.io/","language":"C++","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/selimanac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"selimanac"}},"created_at":"2019-07-11T13:45:40.000Z","updated_at":"2025-04-05T08:56:14.000Z","dependencies_parsed_at":"2024-05-16T09:00:41.501Z","dependency_job_id":"2fc8b4d1-31bc-4d99-921a-a09eb3063970","html_url":"https://github.com/selimanac/defold-astar","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selimanac%2Fdefold-astar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selimanac%2Fdefold-astar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selimanac%2Fdefold-astar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selimanac%2Fdefold-astar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/selimanac","download_url":"https://codeload.github.com/selimanac/defold-astar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248506382,"owners_count":21115423,"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":["a-star","astar","astar-algorithm","astar-pathfinding","defold","defold-game-engine","defold-library","micropather","pather","pathfinder","pathfinding"],"created_at":"2024-10-03T22:08:36.813Z","updated_at":"2025-04-12T02:25:33.113Z","avatar_url":"https://github.com/selimanac.png","language":"C++","funding_links":["https://github.com/sponsors/selimanac"],"categories":["Libraries","Python"],"sub_categories":["Programming Language"],"readme":"![A*](/.github/defoldheader.png?raw=true)\n\nThis is a pathfinder and A* solver (astar or a-star) native extension for the [Defold Engine](https://www.defold.com/), built using [MicroPather](https://github.com/leethomason/MicroPather).  \n\n## Installation\n\nYou can use the A* extension in your own project by adding this project as a [Defold library dependency](https://defold.com/manuals/libraries/#setting-up-library-dependencies).  \nOpen your `game.project` file, select  `Project ` and add a  `Dependencies ` field:\n\n\u003ehttps://github.com/selimanac/defold-astar/archive/master.zip\n\nor you can add stable versions from [releases](https://github.com/selimanac/defold-astar/releases).  \n\n## Examples\n\nHexagon example: https://github.com/selimanac/defold-astar-hex-example    \nBasic tilemap example: https://github.com/selimanac/defold-astar-tilemap-example\n\nOld examples: https://github.com/selimanac/defold-astar-examples\n\n\n## Forum\n\nhttps://forum.defold.com/t/a-native-extension/\n\n## Toss a Coin to Your Witcher\nIf you find my [Defold Extensions](https://github.com/selimanac) useful for your projects, please consider [supporting](https://github.com/sponsors/selimanac) it.  \nI'd love to hear about your projects! Please share your released projects that use my native extensions. It would be very motivating for me.\n\n\n## Release Notes\n\n### 1.1.1\n\n- Minor edge case fix on Micropather core. \n- Minor code refactoring. \n\n### 1.1.0\n\nThis is a major release. Consider it a Beta version. New examples on the way.  \nFeel free to open an [issue](https://github.com/selimanac/defold-astar/issues) if you encounter any problems.\n\n\n- Now support odd-r, even-r, odd-q and even-q [hexagonal grids](https://www.redblobgames.com/grids/hexagons/#coordinates-offset). \n- Entities: You can now target entities like potions, chests, or enemies, which were not possible to solve on the map before. You can toggle `astar.use_entities()` before calling the `astar.solve()` and `astar.solve_near()` methods. \n- Partial code refactoring(nearly %30) for better readability, performance improvement(minimal) and Defold compatibility. I'll continue to improve it. Almost everything is now preallocated. You may hit the limits. If so, feel free to open an [issue](https://github.com/selimanac/defold-astar/issues)\n- `astar.print_map()` added. You can print the latest map state for debug purposes.\n- `astar.solve()` and `astar.solve_near()` now also returns tile content ID.\n- `astar.map_vflip()` and `astar.map_hflip()` added. You can now flip the map.\n- `astar.reset()` added. It cleans up everything. \n- Optional vertically flip map added to astar.setup(). \n- API Documentation updated.\n\n**!! BREAKING CHANGE !!** \n\nThe default value for tables and tile positions starts at 1. For backward compatibility, you can simply toggle it in `astar.setup()` or by using `astar.use_zero(true)`.\n\n\n1.0.3  \n\n- No changes. This is the final release before v1.1.\n\n1.0.2  \n\n- astar.set_at and astar.get_at added.\n- astar.toogle_zero added. \n\n1.0.1  \n\nSmall bug fixes. [More details](https://forum.defold.com/t/a-native-extension/60405/9?u=selimanac) \n\n1.0  \ninitial\n \n---\n\n# API\n\n## astar.setup(map_width, map_height, direction, allocate, typical_adjacent, [cache], [use_zero], [map_vflip] )\n\nInitial setup. You have to setup the astar before calling any other methods.   \n\n**PARAMETERS**. \n\n* ```map_width``` (int) - Width of your map. This is generally width of your tilemap.  \n* ```map_height``` (int) - Height of your map. This is generally width of your tilemap. \n* ```direction``` (enum) - Movement direction (astar.DIRECTION_FOUR or astar.DIRECTION_EIGHT)\n\n\t**astar.DIRECTION_FOUR**: On a square grid that allows 4 directions of movement using [Manhattan distance](http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#manhattan-distance)  \n\t**astar.DIRECTION_EIGHT**: On a square grid that allows 8 directions of movement using [Euclidean distance](http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#euclidean-distance)\n\n* ```allocate``` (int) - How many states should be internally allocated at a time. This can be hard to get correct. The higher the value, the more memory Patfinder will use.\n\n\t- If you have a small map (a few thousand states?) it may make sense to pass in the maximum value. This will cache everything, and MicroPather will only need one main memory allocation. For a chess board, allocate  would be set to 8x8 (64)\n\t- If your map is large, something like 1/4 the number of possible states is good.\n\t- If your state space is huge, use a multiple (5-10x) of the normal path. \"Occasionally\" call `astar.reset_cache()` to free unused memory.\n\n* ```typical_adjacent``` (int) - Used to determine cache size. The typical number of adjacent states to a given state. (On a chessboard, 8.) Higher values use a little more memory.\n\n* ```cache``` (bool)[optional] - Turn on path caching. Uses more memory (yet again) but at a huge speed advantage if you may call the pather with the same path or sub-path, which is common for pathing over maps in games.  Default is `true`\n\n*  ```use_zero``` (bool)[optional] - Toggle start index 0 or 1 for tables and tile positions. Also you can set it by call `astar.use_zero()`.  Default is `false`\n\n* ```map_vflip``` (bool)[optional] - Flips the map vertically. This doesn't flip the coordinates. Also you can set it by call `astar.map_vflip()`. Default is `false`\n\n**EXAMPLE**\n\n```lua\n\nlocal map_width = 5\nlocal map_height = 4\nlocal direction = astar.DIRECTION_EIGHT\nlocal allocate = map_width * map_height\nlocal typical_adjacent = 8\nlocal cache = true     -- Optional. Default is true\nlocal use_zero = false -- Optional. Default is false = 1 based\nlocal flip_map = false -- Optional. Default is false\n\nastar.setup(map_width, map_height, direction, allocate, typical_adjacent, cache, use_zero, flip_map)\n\n```\n\n\n## astar.use_zero(toggle)\n\nToggle start index 0 or 1 for tables and tile positions.\n\nIf set to `false`, [astar.solve](#astarsolvestart_x-start_y-end_x-end_y), [astar.solve_near](#astarsolve_nearstart_x-start_y-max_cost), [astar.get_at](#astarget_atx-y), [astar.set_at](#astarset_atx-y-value) methods expect positions start with 1 and returns table indexes from **1**.   \n\nDefault is `false` = 1\n\n**PARAMETERS**\n\n* ```toggle``` (bool) - true/false\n\n**EXAMPLE**\n\n```lua\n\nastar.use_zero(false)\n\n\n```\n\n\n\n\n## astar.set_map_type(type)\n\nYou can set different type of map coordinates. Default is `astar.GRID_CLASSIC`.\n\nMore information about hexagonal grid offset coordinates systems: [Red Blob Games](https://www.redblobgames.com/grids/hexagons/#coordinates-offset)\n\n**PARAMETERS**\n\n* ```type``` (enum) - Type of the map coordinates.\n\n\t**astar.GRID_CLASSIC** : classic grid.  \n\t**astar.HEX_ODDR** : odd-r hexagonal grid.  \n\t**astar.HEX_EVENR** : even-r hexagonal grid.  \n\t**astar.HEX_ODDQ** : odd-q hexagonal grid.  \n\t**astar.HEX_EVENQ** : even-q hexagonal grid.  \n\t\n\n**EXAMPLE**\n\n```lua\n\nastar.set_map_type(astar.HEX_ODDR)\n\n```\n\n## astar.set_map(world)\n\nSet your map data.  \n0.0 or 1.1 is top-left.  \n\n*Setting new map data reset the current cache.  \n\n**PARAMETERS** \n\n* ```world``` (table) - Your tilemap data. Keep it simple as much as you can.\n\n**EXAMPLE**  \n\n```lua\n\nlocal world = {\n\t2, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0,\n\t0, 0, 1, 0, 0,\n\t1, 0, 0, 0, 2,\n}\n\nastar.set_map(world)\n\n```\n\n## astar.map_vflip()\n\nEvery time you call this function, it flips the map vertically. This does not flip the coordinates\n\n*Flipping the map reset the current cache.  \n\n\n**EXAMPLE**  \n\n```lua\n\nlocal world = {\n\t2, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0,\n\t0, 0, 1, 0, 0,\n\t1, 0, 0, 0, 2,\n}\n\nastar.set_map(world)\nastar.map_vflip()\nastar.print_map()\n```\n\n\n## astar.map_hflip()\n\nEvery time you call this function, it flips the map horizontally. This does not flip the coordinates\n\n*Flipping the map reset the current cache.  \n\n\n**EXAMPLE**  \n\n```lua\n\nlocal world = {\n\t2, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0,\n\t0, 0, 1, 0, 0,\n\t1, 0, 0, 0, 2,\n}\n\nastar.set_map(world)\nastar.map_hflip()\nastar.print_map()\n```\n\n\n\n\n## astar.set_costs(costs)\n\nSet costs for your passable tiles on your `world` table. This table keys determines the passable area. In this example only numbered \"0\" tiles are passable.   \n\nTable's sum must be the `astar.DIRECTION_FOUR` (4) or `astar.DIRECTION_EIGHT` (8). In this example we want to move 8 direction. \n\n*Setting new cost data reset the current cache.\n\n**PARAMETERS**. \n\n* ```costs``` (table) - Your tile cost data.  \n\n**EXAMPLE**\n\n```lua\n\n-- For astar.DIRECTION_EIGHT\nlocal costs = {\n    [0] = {\n        1.0, -- E\n        1.0, -- N\n        1.0, -- W\n        1.0, -- S\n        1.41, -- NE\n        1.41, -- NW\n        1.41, -- SW\n        1.41 -- SE\n    }\n}\n\nastar.set_costs(costs)\n-- OR\n-- For astar.DIRECTION_FOUR\nlocal costs = {\n    [0] = {\n        1.0, -- E\n        1.0, -- N\n        1.0, -- W\n        1.0 -- S\n    }\n}\n\nastar.set_costs(costs)\n\n\n```\n\n## astar.set_entities(entities)\n\nEntities are usally not passible items like enemies or chests. You might want to target those tiles but also want to keep them not passable. You can set those entity ids as table. Your world table should contain those entities. \n\nYou have to toggle `astar.get_entities()` before calling `astar.solve()` or `astar.solve_near()`. \n\n\n**PARAMETERS**  \n\n* ```entities``` (table) - Your entities data.\n\n\n**EXAMPLE**  \n\n```lua\n\n-- IDs of the entities\nlocal entities = {\n\t1, 2\n}\n\nastar.set_entities(entities)\n\n```\n\n\n## astar.use_entities(toogle).\n\nIf you want to include your entities to your solve operations, you have to set it true before calling `astar.solve()` or `astar.solve_near()`.   \n\nIf set the `true`:   \n\n`astar.solve()` only includes the end/last target tile to the path result. Other entities along the path stays as not passable.\n\n`astar.solve_near()` includes all entities from entities table.\n\n*When you call the `astar.use_entities()`, the current cache will be reset.\n\n**PARAMETERS** \n\n* ```toogle``` (boolean) - Toogle true or false. Default is false\n\n\n**EXAMPLE**\n\n```lua\n\n-- IDs of the entities\nlocal entities = {\n\t1, 2\n}\n\nastar.set_entities(entities)\nastar.use_entities(true)\n\n```\n\n## astar.get_at(x, y)\n\nReturns the value from the map array by coordinates.\n\n**PARAMETERS**\n\nX, Y of the tile possition on array not the screen position.\n\n* ```x``` (int) - Tile X\n* ```y``` (int) - Tile Y\n\n\n**RETURN**\n\n* ```value``` (int)\n\n\n**EXAMPLE**\n\n```lua\n\nlocal value = astar.get_at(1, 1)\n\nprint(value)\n\n```\n\n\n## astar.set_at(`x`, `y`, `value`)\n\nSet your value to the map array by coordinates.\n\n*Setting new data reset the current cache.\n\n**PARAMETERS**\n\nX, Y of the tile possition on array not the screen position.\n\n* ```x``` (int) - Tile X\n* ```y``` (int) - Tile Y\n* ```value``` (int) \n\n\n**EXAMPLE**\n\n```lua\n\nastar.set_at(1, 1, 0) \n\n```\n\n\n## astar.print_map()\n\nPrints the map state for debug purposes.\n\n**EXAMPLE**\n\n```lua\n\nastar.print_map()\n\n```\n\n\n```text\n\ncols/x:\n1\t2\t3\t4\t5\t\n-\t-\t-\t-\t-\t\n2\t0\t0\t0\t0\t\t- row/y: 1\n0\t0\t0\t0\t0\t\t- row/y: 2\n0\t0\t1\t0\t0\t\t- row/y: 3\n1\t0\t0\t0\t2\t\t- row/y: 4\n\n```\n\n## astar.solve(start_x, start_y, end_x, end_y)\n\nSolves the path.   \n\n**PARAMETERS**\n\nX, Y of the tile possition on array not the screen position.\n\n* ```start_x``` (int) - Start tile X\n* ```start_y``` (int) - Start tile Y\n* ```end_x``` (int) - End tile X\n* ```end_y``` (int) - End tile Y\n\n**RETURN**\n\n* ```status``` (enum) -\n\n\t**astar.SOLVED**: Path solved  \n\t**astar.NO_SOLUTION**: Can't find the path  \n\t**astar.START_END_SAME**: Start and End is the same \n\n* ```size``` (int) - Size of the path.\n* ```total_cost``` (int) - Total cost of the path\n* ```path``` (table) -  Table with x, y coordinates and tile ID. First value is the given start point.\n\n**EXAMPLE**\n\n```lua\n\nlocal start_x = 1\nlocal start_y = 1\nlocal end_x = 3\nlocal end_y = 3\n\nlocal status, size, total_cost, path = astar.solve(start_x, start_y, end_x, end_y)\n\nif status == astar.SOLVED then\n\tprint(\"SOLVED\")\n\tprint(\"Path Size\", size)\n\tprint(\"Total Cost:\", total_cost)\n\n\tfor _, tile in ipairs(path) do\n\t\tprint(\"x:\", tile.x, \"y: \", tile.y, \"tile ID: \", tile.id)\n\tend\nelseif status == astar.NO_SOLUTION then\n\tprint(\"NO_SOLUTION\")\nelseif status == astar.START_END_SAME then\n\tprint(\"START_END_SAME\")\nend\n\n```\n\n## astar.solve_near(start_x, start_y, max_cost)\n\nFinds the neighbours according to given cost.   \n\n**PARAMETERS** \n\n* ```start_x``` (int) - Start tile X\n* ```start_y``` (int) - Start tile Y\n* ```max_cost``` (float) - Maximun cost for finding neighbours\n\n**RETURN**\n\n* ```near_status``` (enum) - \n\n\t**astar.SOLVED**: Path solved  \n\t**astar.NO_SOLUTION**: Can't find the path  \n\t**astar.START_END_SAME**: Start and End is the same \n\n* ```near_size``` (enum) - Size of the found neighbours.\n* ```nears``` (enum) - Table with x and y coordinates. First value is the given start point.  \n\n**EXAMPLE**\n\n```lua\n\nlocal start_x = 1\nlocal start_y = 1\nlocal max_cost = 3.0 -- near\n\nlocal near_status, near_size, nears = astar.solve_near(start_x, start_y, max_cost)\n\nif near_status == astar.SOLVED then\n\tprint(\"NEAR SOLVED\")\n\tprint(\"Near Size:\", near_size)\n\tfor _, tile in ipairs(nears) do\n\t\tprint(\"x:\", tile.x, \"y: \", tile.y, \"tile ID: \", tile.id)\n\tend\nelseif near_status == astar.NO_SOLUTION then\n\tprint(\"NO_SOLUTION\")\nelseif near_status == astar.START_END_SAME then\n\tprint(\"START_END_SAME\")\nend\n\n```\n\n\n## astar.reset_cache()\n\nIf your state space is huge, occasionally call astar.reset_cache() to free unused memory.\n\n**EXAMPLE**\n\n```lua\n\nastar.reset_cache()\n\n```\n\n## astar.reset()\n\nThis method removes everything releated to astar library and frees the memory. It may be used when the player completes/exits the level/game.\n\n**EXAMPLE**\n\n```lua\n\nastar.reset()\n\n```\n\n\n\n---\n\n## Games using A-Star\n\n### Skull Horde\n\n![Skull Horde](/.github/skull_horde.png?raw=true)\n\n**Developer:** [8BitSkull](https://www.8bitskull.com/)  \n**Publisher:** [8BitSkull](https://www.8bitskull.com/)   \n**Release Date:** TBA  \n**Steam:** https://store.steampowered.com/app/3199360/Skull_Horde/  \n\n\n\n### Misland\n\n![Misland](/.github/misland.png?raw=true)\n\n**Developer:** [Seal Unicron Games](https://sealunicorn.com)  \n**Release Date:** 11 Nov, 2023  \n**Poki:** https://poki.com/en/g/misland  \n**Google Play:** https://play.google.com/store/apps/details?id=com.sealunicorngames.misland    \n\n\n\n\n### Monkey Mart\n\n![Monkey Mart](/.github/monkey_mart.jpg?raw=true)\n\n**Developer:** [Tiny Dobbins](http://tinydobbins.com/)  \n**Release Date:** 8 Dec, 2022  \n**Poki:** https://poki.com/en/g/monkey-mart  \n**Google Play:** https://play.google.com/store/apps/details?id=com.tinydobbins.monkeymart   \n**App Store:** https://apps.apple.com/tr/app/monkey-mart/id6480208265  \n\n### Xfire\n\n![Xfire](/.github/xfire.png?raw=true)\n\n**Developer:** [171Dev](https://www.171dev.uk)  \n**Release Date:** 28 May, 2024  \n**itch.io:** https://benjames171.itch.io/xfire  \n**Source:** https://github.com/benjames-171/xfire \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselimanac%2Fdefold-astar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselimanac%2Fdefold-astar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselimanac%2Fdefold-astar/lists"}