Godot pathfinding / 2026-07-08 / 13 min read
Verified as of Godot 4.7 stable docs and runnable Dijkstra-map proof scene checked on 2026-07-08
Dijkstra maps for roguelike AI in Godot
Build Dijkstra maps in Godot for roguelike AI: pursuit fields, shared maps for many actors, source bias, flee maps, autoexplore, hazards, and INF-safe scoring.
What a Dijkstra map is
A Dijkstra map is a grid where every cell holds its cheapest distance to a goal, computed with Dijkstra's algorithm over non-negative step costs. Seed the goal cells at 0, flood the distances outward, and you have a field any number of actors can read at once - no per-actor pathfinding.
It turns up in roguelikes, grid AI, and procedural systems because it makes smart movement a lookup instead of a search. Godot 4 ships none of it natively, so this page builds it from scratch. The everyday shapes:
- Chase: an actor steps toward the lowest neighboring value.
- Avoid: it steps the other way - though the naive highest value rule hugs corners, which this page fixes later.
- Fire, smell, or sound spread: distance values can be transformed into intensity.
- Safe-spot AI: pick a high value on a danger map.
The direct answer
A Dijkstra map is a distance field for grid AI. Build one field from the player, a goal, gold, exits, hazards, or any set of sources; then each actor looks at neighboring cells and steps toward the lowest value.
That flips the usual pathfinding question. A* answers what path should this one actor take to this one target? A Dijkstra map answers what is the best direction from every reachable cell? For roguelike AI, that means one solve can guide pursuit, flee behavior, autoexplore, hazard escape, and source-biased desire maps.
A useful Godot rule is this: store the field as a dense PackedFloat32Array, mark unreachable cells as INF, seed one or more cells with starting scores, then rescan the finite cells through Dijkstra relaxation.
- Build the walkable grid from your TileMapLayer or board data.
- Seed the field: player = 0, exits = 0, gold = negative bias, hazards = safe cells, or any mix that fits the behavior.
- Relax the field through walkable neighbors with terrain costs.
- For each actor, inspect four neighboring cells and step to the lowest score.
- Recompute only when sources, terrain, blockers, or revealed cells change.
Why roguelikes use maps, not only paths
Roguelike AI is usually grid-native. Actors move one cell at a time, turns advance in discrete steps, and the same map facts are read by many systems: pursuit, fleeing, exploration, sound, hazards, tactical safety, and item desire.
If ten actors all chase the same player, ten A* queries are wasteful. A single Dijkstra map from the player gives every actor a downhill direction. When the player moves, rebuild the field. Until then, every actor can read the same array.
This is also why Dijkstra maps compose well with flow fields and influence maps. They are all grid-wide fields. The difference is what the cell values mean and how actors interpret them.
The field representation
The proof scene uses one flat PackedFloat32Array. A cell at (x, y) maps to y * width + x. That keeps the field compact, easy to serialize, and easy to scan in a headless verification run.
INF is the sentinel for blocked or unreachable. Do not use null for every unreachable cell in a hot grid loop; keep the array dense and reserve dictionaries for sparse facts such as blockers or terrain overrides.
Rescan seeded fields
The important implementation detail is the rescan. A basic solver can wipe the field, seed a goal at zero, and expand from there. But source bias and flee behavior need something stronger: a function that starts from every finite value already in the field.
That is what rescan_field() does. It accepts a pre-filled field, pushes every finite non-blocked cell into the frontier, and relaxes outward with terrain costs. Positive edge costs keep the Dijkstra loop valid even when some source cells start at negative values.
Build the standard pursuit map
A pursuit map is the simplest case. Seed the player cell at zero, rescan, then every actor walks downhill. Terrain costs make slower cells more expensive, so the field naturally bends around mud, doors, or hazard tiles if you model them as higher entry cost.
This version uses a sorted array frontier for readability. For large maps or frequent rebuilds, swap it for a real priority queue. The algorithmic contract stays the same; only the frontier implementation changes.
Actors read downhill
Once the field exists, movement is cheap. The actor checks each walkable neighbor and picks the cell with the lowest value. This is the shareable part: the expensive search happened once; each actor's turn is just a local read.
Keep occupancy separate from the field. The field describes terrain and goals. Runtime blockers, reservations, and other actors are usually a second layer applied during step selection.
Multiple sources and source bias
Multiple sources are where Dijkstra maps start to feel like AI instead of only pathfinding. Seed the player at zero and treasure at a negative value, then rescan. Cells near the treasure become more attractive without writing a separate target-switching system.
The negative number is not magic. It is an explicit preference. A source at -4 says this source is four cost units more attractive than a neutral source at 0. The rescan propagates that preference through the map.
Flee maps need the second pass
Naive flee behavior often gets stuck in local corners: multiply the approach map by -1, then step downhill away from the player. The actor runs toward the locally highest distance, which may be a dead end.
The useful roguelike trick is to multiply the approach field by a stronger negative coefficient, usually around -1.2, then rescan. That creates a new safety field. The rescan rewards cells that are far from the player but still connected through useful exits, so the actor can head toward a doorway instead of hugging the nearest corner.
Compose desires without INF poisoning
A richer actor can score a cell against several maps: approach the player, prefer treasure, avoid hazard, seek unexplored cells. The pitfall is INF. If one optional map is unreachable at a cell, you do not want that one value to poison an otherwise valid score.
The proof scene handles this by skipping INF maps during composition. If no finite map contributes at all, the score is INF and the cell is not attractive.
Behavior recipes
The same solver covers several common roguelike behaviors. What changes is the seed set and how the actor interprets the result.
| Behavior | Sources | Actor read | When to rebuild |
|---|---|---|---|
| Pursuit | Player cell at 0 | Step to the lowest neighboring value | When the player moves or blockers change |
| Many actors, one target | Shared target at 0 | Every actor reads the same field | When target or terrain changes |
| Greed | Player at 0, gold at negative bias | Step toward the lowest score | When gold, player, or bias changes |
| Flee | Approach map multiplied by a negative coefficient, then rescanned | Step to the lowest safety value | When player or blocker state changes |
| Autoexplore | Unseen/frontier cells at 0 | Step toward the nearest unrevealed frontier | When visibility changes |
| Hazard escape | Safe cells at 0, hazard cells as high terrain cost | Step toward lower danger distance | When hazard or safe-state changes |
Update policy matters more than the first demo
The Dijkstra map should not rebuild just because an actor takes a step. Rebuild when the facts that define the field change: the player source moves, treasure is collected, a door opens, a wall appears, a cell is revealed, or the selected behavior changes.
For small roguelike maps, a full field rebuild is often fine. For larger maps, split the work: keep terrain and blocker data explicit, use dirty regions where possible, and move repeated field builds into a scheduled budget. The related frame-spike scheduling guide covers the production side of that decision.
Measurement-gap: the attached artifact is a correctness proof, not a throughput benchmark. Its verification JSON confirms six behavior contracts on Godot 4.7: source/wall values, downhill movement, seeded source bias, flee rescan, INF-safe scoring, and hazard escape distance.
Try the proof scene
The browser demo attached above is there because this concept is easier to trust when it moves. Drag the player and the field bends immediately; switch to greed or flee and the same grid starts answering a different AI question.
The downloadable Godot mini project includes the shared solver and headless verification runner. The current receipt is dijkstra-maps-for-roguelike-ai-verification.json, generated from a Godot 4.7-stable run.
Frequently asked questions
What is a Dijkstra map in roguelike AI?
A Dijkstra map is a grid-wide distance or cost field. Seed one or more source cells, compute the cheapest cost to every reachable cell, then let actors inspect neighboring cells and step toward the lowest value.
Does Godot have a built-in Dijkstra map?
No native one. AStarGrid2D returns paths, not a reusable distance field, and NavigationServer is navmesh-oriented. The best-known addon, Dijkstra Map for Godot, targets Godot 3 and needs a port to Godot 4, so in Godot 4 you build the field yourself - which, as this article shows, is a short script.
When should I use a Dijkstra map instead of A* in Godot?
Use A* for one actor going to one target. Use a Dijkstra map when many actors share the same target, when every cell needs a score, or when AI should combine pursuit, flee, exploration, hazard, and desire fields.
How do I make actors chase the player with a Dijkstra map?
Seed the player's cell at zero, build the Dijkstra field, and have each actor move to the neighboring walkable cell with the lowest field value. Rebuild the field when the player or blocker state changes.
How do flee maps work?
Build an approach map from the player, multiply finite values by a negative coefficient such as -1.2, then rescan the seeded field. Actors then move downhill on the rescanned safety field instead of simply hugging the nearest high-distance corner.
Can Dijkstra maps use terrain costs?
Yes. Add the movement cost of entering each neighbor during relaxation. Higher-cost terrain raises the field value and naturally changes the directions actors prefer.
Is this a performance benchmark?
No. The attached Godot scene is a correctness proof for the article code. It verifies six behavior contracts on Godot 4.7; throughput claims need a separate benchmark scene and repeated measurements.