Skip to main content

A* Pathfinding

AStarPathfinder uses the A* algorithm to find the shortest path between two points on a grid. It supports 4-directional and diagonal (8-directional) movement with a binary min-heap for efficient traversal.

Quick Start

1. Auto-scan the scene with AStarGridBaker

A component that automatically builds a grid by scanning Collider2D objects in the scene.

  1. Add the A* Grid Baker component to an empty GameObject
  2. Set the grid size and obstacle layer in the Inspector
  3. Verify the result in the Scene view — green (walkable) / red (blocked)
var baker = GetComponent<AStarGridBaker>();

// World position → grid coordinate
Vector2Int start = baker.WorldToCell(player.position);
Vector2Int end = baker.WorldToCell(targetPosition);

// Find path (diagonal movement enabled)
var path = AStarPathfinder.FindPath(baker.Grid, start, end, diagonal: true);

// Grid coordinate → world position
foreach (var cell in path)
{
Vector3 worldPos = baker.CellToWorld(cell);
// move logic... (see the [AchMover integration] section below)
}

Returns an empty List<Vector2Int> when no path exists.

AchFollower integration

For simple chasing, use AchFollower — call SetTarget() and you're done.

For waypoint-by-waypoint A* path following, drive it in code:

var follower = GetComponent<AchFollower>();

foreach (var cell in path)
{
Vector2 waypoint = baker.CellToWorld(cell);
follower.SetTarget(/* a Transform at the waypoint position */);

while (Vector2.Distance(transform.position, waypoint) > 0.05f)
await Task.Yield();
}

follower.ClearTarget();

If you have no waypoint Transform, manipulate transform.position directly instead.

2. Build a grid manually

var grid = new AStarGrid(20, 20);

// Set obstacle
grid.SetWalkable(5, 3, false);

// High-cost terrain (swamp, sand, etc.)
grid.SetCost(4, 4, 3f);

// Find path
var path = AStarPathfinder.FindPath(
grid,
start: new Vector2Int(0, 0),
end: new Vector2Int(19, 19),
diagonal: false);

AStarGridBaker Inspector

FieldDescription
Width / HeightNumber of grid cells
CellSizeSize of one cell in Unity units
OriginTransform for the grid's bottom-left origin (defaults to the GameObject's position)
ObstacleLayerLayer mask used to detect obstacles
DetectionRadiusObstacle detection radius per cell (cellSize * 0.4 recommended)
CostZonesArray of Collider2D + cost value pairs for terrain weighting
DrawGizmosToggle Scene view grid visualization

Cost Zones

Raise the movement cost in specific areas to guide paths around them.

// Set via Inspector, or rescan after dynamic changes
baker.Bake();
ScenarioApproach
Walls with Collider2DSet ObstacleLayer on AStarGridBaker
Unity TilemapAttach TilemapCollider2D on the obstacle layer
Dynamic obstacles (doors, etc.)Call baker.Bake() after the change

AStarGrid API

var grid = new AStarGrid(width: 20, height: 20);

// Initialize from a bool array
var grid2 = new AStarGrid(walkableMap: myBoolArray);

grid.SetWalkable(x, y, false); // mark as obstacle
grid.SetCost(x, y, 3f); // movement cost (minimum 1)
bool ok = grid.IsWalkable(x, y);
float cost = grid.GetCost(x, y);
bool inRange = grid.IsInBounds(x, y);

AStarPathfinder API

List<Vector2Int> path = AStarPathfinder.FindPath(
grid: grid,
start: new Vector2Int(0, 0),
end: new Vector2Int(10, 10),
diagonal: true // false = 4-way, true = 8-way
);
ParameterDescription
gridThe AStarGrid to search
startStart grid coordinate
endTarget grid coordinate
diagonalAllow diagonal movement (default false)

Returns: List<Vector2Int> from the first step after start to end (inclusive), in movement order. Empty list if no path exists.

Algorithm Details

ItemDetail
SearchA* with binary min-heap open set
HeuristicManhattan (4-way) / Chebyshev (8-way)
Diagonal cost√2 ≈ 1.414
Cell weightingPer-cell cost via AStarGrid.SetCost()
ComplexityO((W×H) log(W×H))

⚠️ Corner cutting: With diagonals enabled, the path may slip through a diagonally open cell even when both adjacent orthogonal cells are blocked. Disable diagonal movement or add a custom neighbor check if this matters for your game.