您的位置:首页 > 移动开发 > Unity3D

关于A*算法的研究

2015-12-03 21:31 369 查看
最近朋友写了一篇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值,并且清空开闭数组,不然就会寻错路。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  A 算法 unity3d enum