unity using the A * pathfinding algorithm 2D

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!

 

Guess you like

Origin www.cnblogs.com/JinT-Hwang/p/11141202.html