A* is great for pathfinding with a few dozen units, but if you have thousands of units (like in Total War or Supreme Commander), calculating individual paths will crush your CPU. Flow Fields solve this by calculating a “navigation map” for the entire world once per frame.
Instead of a “Path” (a sequence of nodes), a Flow Field is a Vector Field. Every tile in the world contains a vector pointing in the optimal direction toward the goal.
Generating a flow field happens in three distinct stages:
A grid where each cell stores the “weight” of the terrain.
Using Dijkstra’s Algorithm, we start at the Goal (cost 0) and propagate outward. Each cell calculates its cumulative “distance-to-goal” by adding its cost to the lowest neighbor’s integration value.
For every cell, we look at its 8 neighbors and find the one with the lowest integration value. We then store a normalized vector pointing from the current cell toward that neighbor.
public void UpdateFlowField(Vector2Int target) {
// 1. Reset and run Dijkstra for Integration Field
integrationGrid.Fill(float.MaxValue);
integrationGrid[target.x, target.y] = 0;
// ... Dijkstra propagation here ...
// 2. Generate Vectors
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Vector2Int bestNeighbor = FindLowestNeighbor(x, y);
flowField[x, y] = (bestNeighbor - new Vector2Int(x, y)).normalized;
}
}
}
// In Unit Update:
void FixedUpdate() {
Vector2 direction = globalFlowField.GetDirectionAt(transform.position);
rb.velocity = direction * speed;
}