Skip to content

Instantly share code, notes, and snippets.

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