Skip to content

Instantly share code, notes, and snippets.

@AlexiyOrlov
Created December 8, 2023 17:45
Show Gist options
  • Save AlexiyOrlov/601878f1e2c38f0d6bc0cc3ad94d1451 to your computer and use it in GitHub Desktop.
Save AlexiyOrlov/601878f1e2c38f0d6bc0cc3ad94d1451 to your computer and use it in GitHub Desktop.
A* pathfinding
public class NavigationGrid
{
public int width, height;
public Cell[,] cells;
public NavigationGrid(int width, int height)
{
this.width = width;
this.height = height;
cells = new Cell[width, height];
}
public List<Cell> FindPath(int startX,int startY,int endX,int endY)
{
Cell start = cells[startX,startY];
Cell end= cells[endX,endY];
List<Cell> openList = new List<Cell>() { start };
HashSet<Cell> closedList = new HashSet<Cell>();
for(int x=0;x<width; x++)
{
for(int y=0;y<height; y++)
{
Cell cell= cells[x,y];
cell.gCost = int.MaxValue;
cell.CalculateFCost();
cell.previous = null;
}
}
start.gCost = 0;
start.hCost = CalculateDistanceCost(start, end);
start.CalculateFCost();
while(openList.Count > 0)
{
Cell currentCell=GetLowestFCostNode(openList);
if (currentCell==end)
{
return CalculatePath(end);
}
openList.Remove(currentCell);
closedList.Add(currentCell);
foreach(Cell neighbor in GetNeighbors(currentCell))
{
if (closedList.Contains(neighbor))
continue;
int tentativeCost=currentCell.gCost+CalculateDistanceCost(currentCell, neighbor);
if (tentativeCost < neighbor.gCost)
{
neighbor.previous = currentCell;
neighbor.gCost= tentativeCost;
neighbor.hCost=CalculateDistanceCost(neighbor, end);
neighbor.CalculateFCost();
if (!openList.Contains(neighbor))
{
openList.Add(neighbor);
}
}
}
}
return null;
}
int CalculateDistanceCost(Cell a,Cell b)
{
int distanceX=Mathf.Abs(a.x-b.x);
int distanceY=Mathf.Abs(a.y-b.y);
int remaining=Mathf.Abs(distanceX-distanceY);
return 14*Mathf.Min(distanceX,distanceY)+10*remaining;
}
Cell GetLowestFCostNode(List<Cell> cellList)
{
Cell cheapest = cellList[0];
for (int i = 1; i < cellList.Count; i++)
{
if (cellList[i].fCost < cheapest.fCost)
{
cheapest = cellList[i];
}
}
return cheapest;
}
List<Cell> CalculatePath(Cell end)
{
List<Cell> path = new()
{
end
};
Cell current = end;
while(current.previous!=null)
{
path.Add(current.previous);
current = current.previous;
}
path.Reverse();
return path;
}
List<Cell> GetNeighbors(Cell of)
{
List<Cell> neighbors = new List<Cell>();
if(of.x-1>=0)
{
Cell left = GetCell(of.x - 1, of.y);
if (left.walkable)
{
neighbors.Add(left);
}
if (of.y - 1 >= 0)
{
Cell lowerLeft = GetCell(of.x - 1, of.y - 1);
if (lowerLeft.walkable)
{
neighbors.Add(lowerLeft);
}
}
if (of.y + 1 < height)
{
Cell upperLeft = GetCell(of.x - 1, of.y + 1);
if (upperLeft.walkable)
{
neighbors.Add(upperLeft);
}
}
}
if (of.x + 1 < width)
{
Cell right = GetCell(of.x + 1, of.y);
if (right.walkable)
{
neighbors.Add(right);
}
if(of.y-1>=0)
{
Cell lowerRight = GetCell(of.x + 1, of.y - 1);
if (lowerRight.walkable)
{
neighbors.Add(lowerRight);
}
}
if (of.y + 1 < height)
{
Cell upperRight = GetCell(of.x + 1, of.y + 1);
if (upperRight.walkable)
{
neighbors.Add(upperRight);
}
}
}
if (of.y - 1 >= 0)
{
Cell lower = GetCell(of.x, of.y - 1);
if (lower.walkable)
{
neighbors.Add(lower);
}
}
if(of.y+1 < height)
{
Cell upper = GetCell(of.x, of.y + 1);
if (upper.walkable)
{
neighbors.Add(upper);
}
}
return neighbors;
}
public Cell GetCell(float x,float y)
{
return cells[Mathf.RoundToInt(x),Mathf.RoundToInt(y)];
}
}
public class Cell
{
public bool walkable=true;
public int x;
public int y;
public int hCost, gCost, fCost;
public Cell previous;
public Cell(int x,int y)
{
this.x = x;
this.y = y;
}
public void CalculateFCost()
{
fCost = hCost + gCost;
}
public override string ToString()
{
return "X " + x + " Y " + y;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment