【Unity开发】A星算法(怪物终点反复改变的解决办法)

//定义格子的枚举类型
public enum GridType
{

    Normal, Obstacle, Start, End
}

定义格子类
public class Grid : IComparable
{
    public int x;
    public int y;

    public int f;//总消耗  G+H
    public int g;//到起点消耗
    public int h;//到终点消耗

    public GridType type;
    public Grid fatherNode;

    //重写CompareTo 方法,用于取出F值最小的格子
    public int CompareTo(object obj)
    {
        Grid grid = (Grid)obj;
        if (this.f < grid.f)
        {
            return -1;
        }
        if (this.f > grid.f)
        {
            return 1;
        }
        return 0;
    }
}

public class AStar : MonoBehaviour
{

    //设置行列数和格子大小
    public int row = 5;
    public int col = 10;
    public int size = 70;

    public Grid[,] grids;

    //开数组,闭数组,和寻路路径
    public ArrayList openList;
    public ArrayList closeList;
    public ArrayList lujing;

    //假定起点和终点X,Y值
    private int xStart = 2;
    private int yStart = 1;
    private int xEnd = 2;
    private int yEnd = 5;

    //初始化寻路格子
    void Init()
    {
        grids = new Grid[row, col];
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                grids[i, j] = new Grid();
                grids[i, j].x = i;
                grids[i, j].y = j;
            }
        }
        //起始点
        grids[xStart, yStart].type = GridType.Start;
        grids[xStart, yStart].h = Manhattan(xStart, yStart);
        //结束点
        grids[xEnd, yEnd].type = GridType.End;

        //设置障碍物
        for (int i = 1; i <= 3; i++)
        {
            grids[i, 3].type = GridType.Obstacle;
        }

        closeList = new ArrayList();
        lujing = new ArrayList();
        openList = new ArrayList();
        openList.Add(grids[xStart, yStart]);

    }

    int Manhattan(int x, int y)   //用于计算到终点的H
    {
        return (int)(Mathf.Abs(xEnd - x) + Mathf.Abs(yEnd - y)) * 10;
    }
    void Start()
    {
        Init();
    }
    void Update()
    {

    }
    //绘制格子便于观察
    void DrawGrid()
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                Color color;
                if (grids[i, j].type == GridType.Start)
                {
                    color = Color.green;
                }
                else if (grids[i, j].type == GridType.End)
                {
                    color = Color.red;
                }
                else if (grids[i, j].type == GridType.Obstacle)
                {
                    color = Color.blue;
                }
                else if (closeList.Contains(grids[i, j]))
                {
                    color = Color.yellow;
                }
                else
                {
                    color = Color.gray;
                }
                GUI.backgroundColor = color;
                GUI.Button(new Rect(j * size, i * size, size, size), FGH(grids[i, j]));
            }
        }
    }

    //显示F G H值
    string FGH(Grid grid)
    {
        string str = "F" + " " + grid.f + "\n";
        str += "G" + " " + grid.g + "\n";
        str += "H" + " " + grid.h + "\n";
        str += "(" + grid.x + "," + grid.y + ")";
        return str;
    }
    void OnGUI()
    {
        DrawGrid();
        //显示出开数组,闭数组和行走路径
        for (int i = 0; i < openList.Count; i++)
        {
            GUI.Button(new Rect(i * size, (row + 1) * size, size, size),FGH((Grid)openList[i]));
        }
        for (int i = 0; i < closeList.Count; i++)
        {
            GUI.Button(new Rect(i * size, (row + 2) * size, size, size),FGH((Grid)closeList[i]));
        }
        for (int i = 0; i < lujing.Count; i++)
        {
            GUI.Button(new Rect(i * size, (row + 3) * size, size, size),FGH((Grid)lujing[i]));
        }

        if (GUI.Button(new Rect(col * size, size, size, size), "NEXT"))
        {
            NextStep();//一步一步走
        }
    }

    //获取每个格子的父节点,用于从终点往回查询路径
    void getFatherNode(Grid grid)
    {
        if (grid.fatherNode != null)
        {
            lujing.Add(grid.fatherNode);
            getFatherNode(grid.fatherNode);
            // return getFatherNode(grid.fatherNode);
        }
        //else
        //lujing.Add(grid);
        //return grid;
    }
    void NextStep()
    {
        //当开数组为空时,寻路结束
        if (openList.Count == 0)
        {
            print("Over!");

            return;
        }
        //把F值最小的grid取出来
        Grid grid = (Grid)openList[0];
        //当寻到终点的时候
        if (grid.type == GridType.End)
        {
            print("Over");
            lujing.Add(grid);
            //打印路线
            getFatherNode(grid);
            //因为路径是从后往前查找父节点,所以需要reverse则为正确路径
            lujing.Reverse();
            return;
        }
        //遍历处自己外的周围8个格子
        for (int i = -1; i <= 1; i++)
        {
            for (int j = -1; j <= 1; j++)
            {
                //如果只想遍历上下左右4个格子可加个条件 (i==0||j==0)
                if (!(i == 0 && j == 0))
                {
                    int x = grid.x + i;
                    int y = grid.y + j;
                    //不超过边界,不是障碍物,不在closeList数组里
                    if (x >= 0 && x < row && y >= 0 && y < col && grids[x, y].type != GridType.Obstacle && !closeList.Contains(grids[x, y]))
                    {
                        //计算G
                        int g = grid.g + (int)(Mathf.Sqrt(Mathf.Abs(i) + Mathf.Abs(j)) * 10);
                        if (grids[x, y].g == 0 || grids[x, y].g > g)
                        {
                            grids[x, y].g = g;
                            grids[x, y].fatherNode = grid;
                        }
                        grids[x, y].h = Manhattan(x, y);
                        grids[x, y].f = grids[x, y].g + grids[x, y].h;
                        if (!openList.Contains(grids[x, y]))
                        {
                            openList.Add(grids[x, y]);
                        }
                        //重新从小到大排序;
                        openList.Sort();
                    }
                }
            }
        }

        //走过的点关闭
        closeList.Add(grid);
        //关闭的点从OPEN里移除
        openList.Remove(grid);
    }


注意:当频繁更换终点,或反复进行多次寻路时

需要清除计算过的格子的FGH值,并且清空开闭数组

你可能感兴趣的:(Unity3D)