Created
December 8, 2023 17:45
-
-
Save AlexiyOrlov/601878f1e2c38f0d6bc0cc3ad94d1451 to your computer and use it in GitHub Desktop.
A* pathfinding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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