After looking for a new job, busy dying, no time to tinker with the blog, feel deeply capitalist exploitation, even the Dragon Boat Festival dumplings are not, too tired to work every day with the same article salted fish (probably).
Just recently I sneak on to write AStar pathfinding unity in 2D under.
Map of tilemap to stick with untiy.
Probably the effect did not go to nice pictures, will get some color, he said:
Black indicates obstacles, green for green path, is the beginning and end of use, good lazy o (╥﹏╥) o
Principles and detailed explanation, or reference of the big foreign god:
https://www.redblobgames.com/pathfinding/a-star/introduction.html
Commentary follows:
A * algorithm can actually be understood as a greedy algorithm and a combination of breadth-first search algorithm.
Breadth-first search algorithm, each can find the shortest path, every step will write down a few steps to the starting point of the current point, the advantage is definitely able to find the shortest path, the greater the amount of calculation drawback is that the map will become very huge.
Greedy algorithm, each time the current point away from the end nearest the grid, in the absence of barriers situation is very efficient, but if there is an obstacle, then it is a detour.
A * algorithm is a combination of both, the current count steps walked and the current point to the end point and the distance of the grid as a basis to go, the advantage is that when there are obstacles, to find the shortest distance and calculates the amount of no great breadth-first search, when there are no obstructions, as efficient and greedy algorithms.
In fact, the amount of code does not have much direct posted out, no specific explanation, see the comments now, I'm so lazy.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; public class MapBehaviour : MonoBehaviour { public Vector2Int mapSize; // Map Size public Tilemap tilemap; public Tile normalTile;//白色tile public Tile obstacleTile;//黑色tile public Tile pathTile; // green tile // number of obstacles to be generated; public int obstacleCount public Vector3Int startPos; // starting point public Vector3Int endPos; // end private bool hasStartPosSet; // whether a starting point private bool hasEndPosSet; // whether the end point is set private Dictionary <Vector3Int, int> search = new Dictionary <Vector3Int, int> (); // find the task to be carried out private Dictionary <Vector3Int, int> cost = new Dictionary <Vector3Int, int> (); // start point to the current point of consumption private Dictionary <Vector3Int, Vector3Int> pathSave = new Dictionary <Vector3Int, Vector3Int> (); // save path backtracking private List <Vector3Int> hadSearch = new List <Vector3Int> (); // look through the coordinates have been private List <Vector3Int> obstacle = new List <Vector3Int> (); // coordinate obstacle private void Start() { CreateNormalTiles(); CreateObstacleTiles(); } private void Update() { if (Input.GetMouseButtonDown(0)) { if (! hasStartPosSet) // set the starting point for the first click { startPos = tilemap.WorldToCell(Camera.main.ScreenToWorldPoint(Input.mousePosition)); tilemap.SetTile (startPos, pathTile); hasStartPosSet = true; } else if (! hasEndPosSet) // second click to set the end point { endPos = tilemap.WorldToCell(Camera.main.ScreenToWorldPoint(Input.mousePosition)); tilemap.SetTile (endPos, pathTile); hasEndPosSet = true; AStarSearchPath(); } else // Reset { hasStartPosSet = false; hasEndPosSet = false; foreach (var item in pathSave) { tilemap.SetTile(item.Key, normalTile); } search.Clear(); cost.Clear(); pathSave.Clear(); hadSearch.Clear(); } } } // Create White Map public void CreateNormalTiles() { for (int i = 0; i < mapSize.x; i++) { for (int j = 0; j < mapSize.y; j++) { Vector3Int position = new Vector3Int(i, j, 0); tilemap.SetTile(position, normalTile); } } } // create barriers to black public void CreateObstacleTiles() { List<Vector3Int> blankTiles = new List<Vector3Int>(); for (int i = 0; i < mapSize.x; i++) { for (int j = 0; j < mapSize.y; j++) { blankTiles.Add(new Vector3Int(i, j, 0)); } } for (int i = 0; i < obstacleCount; i++) { int index = Random.Range(0, blankTiles.Count); Vector3Int obstaclePos = blankTiles[index]; blankTiles.RemoveAt(index); obstacle.Add(obstaclePos); tilemap.SetTile(obstaclePos, obstacleTile); } } // AStar algorithm to find public void AStarSearchPath() { //initialization search.Add(startPos, GetHeuristic(startPos, endPos)); cost.Add(startPos, 0); hadSearch.Add(startPos); pathSave.Add(startPos, startPos); while (search.Count > 0) { Vector3Int current = GetShortestPos (); // get the coordinates of the task list of minimum consumption if (current.Equals(endPos)) break; List <Vector3Int> neighbors = GetNeighbors (current); // Get current coordinates neighbor foreach (var next in neighbors) { if (!hadSearch.Contains(next)) { cost.Add (next, cost [current] + 1); // calculate the current consumption of the lattice, the lattice is actually a step plus 1 search.Add (next, cost [next] + GetHeuristic (next, endPos)); // add the task to find, plus the current consumption value of the current consumed by the distance-to-destination pathSave.Add (next, current); // save path hadSearch.Add (next); // add this point has been queried } } } if (pathSave.ContainsKey(endPos)) ShowPath(); else print("No road"); } // Get the neighbors Available private List<Vector3Int> GetNeighbors(Vector3Int target) { List<Vector3Int> neighbors = new List<Vector3Int>(); Vector3Int up = target + Vector3Int.up; Vector3Int right = target + Vector3Int.right; Vector3Int left = target - Vector3Int.right; Vector3Int down = target - Vector3Int.up; //Up if (up.y < mapSize.y && !obstacle.Contains(up)) { neighbors.Add(up); } //Right if (right.x < mapSize.x && !obstacle.Contains(right)) { neighbors.Add(target + Vector3Int.right); } //Left if (left.x >= 0 && !obstacle.Contains(left)) { neighbors.Add(target - Vector3Int.right); } //Down if (down.y >= 0 && !obstacle.Contains(down)) { neighbors.Add(target - Vector3Int.up); } return neighbors; } // Get the current position to the end point of consumption my private int GetHeuristic (Vector3Int Bosa, Vector3Int posB) { return Mathf.Abs (posA.x - posB.x) + Mathf.Abs (posA.y - posB.y); } // Get the dictionary coordinate tasks consumed the least private Vector3Int GetShortestPos() { KeyValuePair<Vector3Int, int> shortest = new KeyValuePair<Vector3Int, int>(Vector3Int.zero, int.MaxValue); foreach (var item in search) { if (item.Value < shortest.Value) { shortest = item; } } search.Remove(shortest.Key); return shortest.Key; } // display Pathfinder completed private void ShowPath() { print(pathSave.Count); Vector3Int current = endPos; while (current != startPos) { Vector3Int next = pathSave[current]; tilemap.SetTile (current, pathTile); current = next; } } }
In fact, no difficulty, mainly to understand, each taking out the next point calculation, there is a dictionary that consume the least point value, then the consumption value of each point is the starting point to the current number of steps and the distance to the end of the current (professional term called Manhattan from Manhattan distance2333) sum.
end.
Welcome to the exchange, reproduced indicate the source!