//find path from point A to point B public Vector2[] FindPath(Vector2 from, Vector2 to, PathfindingConfig2D config) { Clear(); List <Tile> OpenList = new List <Tile> (); //list of tiles to check List <Tile> ClosedList = new List <Tile> (); //list of tiles to ignore Tile CurrentTile = grid.GetTileFromWorldPosition(from); //current check tile, that to beginning of path searching equal start tile Tile toTile = grid.GetTileFromWorldPosition(to); //end tile if (!toTile.isWalkable) { return(null); } OpenList.Add(CurrentTile); CurrentTile.State = Tile.listState.Open; while (toTile.State != Tile.listState.Close) { if (OpenList.Count == 0) { Debug.Log("Path not found!"); return(null); } OpenList.Remove(CurrentTile); //delete current from the open list ClosedList.Add(CurrentTile); //add current tile to closed list CurrentTile.State = Tile.listState.Close; CalculateTilesAround(CurrentTile, toTile, OpenList, config); //calculate tile parameters around current tile int minF = int.MaxValue; //minimum F value //searching tile with minimum F value in open list foreach (Tile t in OpenList) { if (t.F < minF) { minF = t.F; //current tile equal tile with minimum F value CurrentTile = t; } } } return(PathRecovery(from, to)); }
//calculate tile parameters around ceterTile void CalculateTilesAround(Tile centerTile, Tile toTile, List <Tile> OpenList, PathfindingConfig2D config) { //loop that ckecks tiles around the central tile for (int y = centerTile.y - 1; y <= centerTile.y + 1; y++) { for (int x = centerTile.x - 1; x <= centerTile.x + 1; x++) { //loop values should not be greater than grid size if (x >= 0 && x < grid.GridWidth && y >= 0 && y < grid.GridHeight) { Tile current = grid.tile[x, y]; if (!config.DiagonalMovement) { if (x != centerTile.x && y != centerTile.y) { continue; } } if (!current.isWalkable || !ConnerManager(centerTile, current, config)) { continue; } //current checked tile should not to be in the closed list if (current.State != Tile.listState.Close) { //if current tile is not in any list if (current.State == Tile.listState.Empty) { current.ParentTile = centerTile; //set central tile as parent tile for current tile CalculateTileValues(current, centerTile, toTile); //add current tile to open list OpenList.Add(current); current.State = Tile.listState.Open; } //if tile is already in open list, we should check the shortest path across this tile //compare the already calculated G value and new G value if (current.State == Tile.listState.Open) { //save the already calculated values of G, H and ParentTile int oldG = current.G; int oldH = current.H; Tile oldParentTile = current.ParentTile; //calculate new values of G and H current.ParentTile = centerTile; CalculateTileValues(current, centerTile, toTile); //compare old values and new values //if the new value of G is greater than the old G value, then the path is not shorter if (current.G >= oldG) { //return old values current.ParentTile = oldParentTile; current.G = oldG; current.H = oldH; current.F = oldH + oldG; } } } } } } }
//returns false if angular movement or angle cut is impossible bool ConnerManager(Tile centerTile, Tile current, PathfindingConfig2D config) { bool canWalk = true; //if rule the catting conners is off, then forbid cutting corner C - centerTile * - current X - unwalkable tile if (!config.IgnoreCorners) { if (centerTile.x + 1 == current.x && centerTile.y + 1 == current.y) //0 X * //0 C 0 { if (!grid.tile [current.x - 1, current.y].isWalkable) //O O O { canWalk = false; } } if (centerTile.x - 1 == current.x && centerTile.y - 1 == current.y) //0 X C //0 * 0 { if (!grid.tile [current.x, current.y + 1].isWalkable) //O O O { canWalk = false; } } if (centerTile.x - 1 == current.x && centerTile.y + 1 == current.y) //* X 0 //0 C 0 { if (!grid.tile [current.x + 1, current.y].isWalkable) //O O O { canWalk = false; } } if (centerTile.x + 1 == current.x && centerTile.y - 1 == current.y) //C X 0 //0 * 0 { if (!grid.tile [current.x, current.y + 1].isWalkable) //O O O { canWalk = false; } } if (centerTile.x + 1 == current.x && centerTile.y - 1 == current.y) //0 0 0 //0 C 0 { if (!grid.tile [current.x - 1, current.y].isWalkable) //O X * { canWalk = false; } } if (centerTile.x - 1 == current.x && centerTile.y + 1 == current.y) //0 0 0 //0 * 0 { if (!grid.tile [current.x, current.y - 1].isWalkable) //0 X C { canWalk = false; } } if (centerTile.x - 1 == current.x && centerTile.y - 1 == current.y) //0 0 0 //0 C 0 { if (!grid.tile [current.x + 1, current.y].isWalkable) //* X 0 { canWalk = false; } } if (centerTile.x + 1 == current.x && centerTile.y + 1 == current.y) //0 0 0 //0 * 0 { if (!grid.tile [current.x, current.y - 1].isWalkable) //C X 0 { canWalk = false; } } } //if rule the catting conners is on, then check possibility of cutting conner else { if (centerTile.x + 1 == current.x && centerTile.y + 1 == current.y) //0 X * - in this case, the angle cut is impossible //0 C X { if (!grid.tile [current.x - 1, current.y].isWalkable) //0 0 0 { if (!grid.tile [current.x, current.y - 1].isWalkable) { canWalk = false; } } } if (centerTile.x - 1 == current.x && centerTile.y + 1 == current.y) //* X 0 - in this case, the angle cut is impossible //X C 0 { if (!grid.tile [current.x + 1, current.y].isWalkable) //0 0 0 { if (!grid.tile [current.x, current.y - 1].isWalkable) { canWalk = false; } } } if (centerTile.x - 1 == current.x && centerTile.y - 1 == current.y) //0 0 0 - in this case, the angle cut is impossible //X C 0 { if (!grid.tile [current.x + 1, current.y].isWalkable) //* X 0 { if (!grid.tile [current.x, current.y + 1].isWalkable) { canWalk = false; } } } if (centerTile.x + 1 == current.x && centerTile.y - 1 == current.y) //0 0 0 - in this case, the angle cut is impossible //0 C X { if (!grid.tile [current.x - 1, current.y].isWalkable) //0 X * { if (!grid.tile [current.x, current.y + 1].isWalkable) { canWalk = false; } } } } return(canWalk); }
void OnEnable() { config = (PathfindingConfig2D)target; }