A* 寻路
A* 寻路
先来看图吧
其中 左上角的 绿色 为起始点 右下角的绿色为 终点。蓝色为 障碍物,红色 为要走的路, 灰色为 探索的路。
A*方法总结
路径评分
选择路径中经过哪个方格的关键是下面这个等式:
F = G + H
这里:
* G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。
* H = 从网格上那个方格移动到终点B的预估移动耗费。这经常被称为启发式的,可能会让你有点迷惑。这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长度,因为路上可能存在各种障碍(墙,水,等等)。
每一步的操作写在一起:
1,把起始格添加到开启列表。
2,重复如下的工作:
a) 寻找开启列表中F值最低的格子。我们称它为当前格。
b) 把它切换到关闭列表。
c) 对相邻的8格中的每一个?
* 如果它不可通过或者已经在关闭列表中,略过它。反之如下。
* 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节
点。记录这一格的F,G,和H值。
* 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低
的G值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,并且重新
计算这一格的G和F值。如果你保持你的开启列表按F值排序,改变之后你可能需要重
新对开启列表排序。
d) 停止,当你
* 把目标格添加进了开启列表,这时候路径被找到,或者
* 没有找到目标格,开启列表已经空了。这时候,路径不存在。
3.保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是
你的路径。
----------------------------------前一阵没事写的 代码--------------------------------------------
//============================================================ class AstarNode { public int g = 0; public int h = 0; public int x=0; public int y = 0; int f = 0; public int F { get { return g + h; } } public AstarNode parent = null; } class AStarAnalisys { List<AstarNode> openList = new List<AstarNode>(); List<AstarNode> closeList = new List<AstarNode>(); Point bPoint=new Point(0,0); Point ePoint=new Point(0,0); byte[,] map = new byte[20, 20]; AstarNode CurNode = null; Point[] directionP = new Point[8] { new Point(-1,-1), new Point(-1,0), new Point(-1,1), new Point(0,-1), new Point(0,1), new Point(1,-1), new Point(1,0), new Point(1,1) }; public int costG(AstarNode pnode, int g) { AstarNode p = pnode.parent; return p.g + g; } public void prepare(Point bP, Point eP, byte[,] maps) { map = maps; bPoint = bP; ePoint = eP; CurNode = new AstarNode(); CurNode.x = bP.X; CurNode.y = bP.Y; CurNode.g = 0; CurNode.parent = null; CurNode.h = (Math.Abs(eP.X - bP.X) + Math.Abs(eP.Y - bP.Y))*10; openList.Add(CurNode); Analisys(CurNode); } public void Analisys( AstarNode cuNode) { List<AstarNode> lis = (from item in openList orderby item.F ascending select item).ToList<AstarNode>(); if (lis.Count > 0) { AstarNode newCurNode = lis[0]; cuNode = newCurNode; // openList.Remove(newCurNode); RemoveNode(openList, new Point(newCurNode.x, newCurNode.y)); closeList.Add(newCurNode); if (newCurNode == null) { MessageBox.Show("这儿没有路可走了"); Form1.maparray = map; return; } //------------------------------------------ foreach (Point p in directionP) { int x = cuNode.x + p.X; int y = cuNode.y + p.Y; if (x >= 0 && x < 20 && y >= 0 && y < 20) { if (Math.Abs(p.X) + Math.Abs(p.Y) == 2) { if (p.X == 1 && p.Y == 1) { if (map[x - 1, y] == 4 || map[x, y - 1] == 4) continue; } if (p.X == -1 && p.Y == -1) { if (map[x, y + 1] == 4 || map[x + 1, y] == 4) continue; } if (p.X == 1 && p.Y == -1) { if (map[x - 1, y] == 4 || map[x, y + 1] == 4) continue; } if (p.X == -1 && p.Y == 1) { if (map[x + 1, y] == 4 || map[x, y - 1] == 4) continue; } } if (map[x, y] == 4)//如果是障碍物 { continue; } else { AstarNode exits = isExits(closeList, new Point(x, y)); if (exits != null) {// 如果在关闭列表里 continue; } else { // 如果不在关闭列表里,也不是障碍物 map[x, y] = 6; //再看看是不是在 开放列表里 AstarNode open = isExits(openList, new Point(x, y)); if (open == null) { AstarNode tempNode = new AstarNode(); tempNode.x = x; tempNode.y = y; tempNode.parent = cuNode; tempNode.h = (Math.Abs(ePoint.X - x) + Math.Abs(ePoint.Y - y)) * 10; if (Math.Abs(p.X) + Math.Abs(p.Y) == 2) tempNode.g = costG(tempNode, 14); else { tempNode.g = costG(tempNode, 10); } openList.Add(tempNode); } else { //如果在开放列表里 AstarNode tempNode = new AstarNode(); tempNode.x = x; tempNode.y = y; tempNode.parent = cuNode; tempNode.h = (Math.Abs(ePoint.X - x) + Math.Abs(ePoint.Y - y)) * 10; if (Math.Abs(p.X) + Math.Abs(p.Y) == 2) tempNode.g = costG(tempNode, 14); else { tempNode.g = costG(tempNode, 10); } if (tempNode.g > open.g) { //如果有更好的路 // open.parent = cuNode; if (Math.Abs(p.X) + Math.Abs(p.Y) == 2) open.g = costG(tempNode, 14); else { open.g = costG(tempNode, 10); } openList.Add(tempNode); continue; } } } } } else { //如果点不在地图中 continue; } if ((x == ePoint.X && y == ePoint.Y)) { AstarNode wst = cuNode; List<AstarNode> temp = new List<AstarNode>(); AstarNode tempCurNode = new AstarNode(); tempCurNode.x = x; tempCurNode.y = y; temp.Add(tempCurNode); // MessageBox.Show(closeList.Count.ToString()); while (wst != null) { temp.Add(wst); wst = wst.parent; } string ss = ""; foreach (AstarNode i in temp) { ss += "(" + i.x + "," + i.y + ")\n"; map[i.x, i.y] = 5; } // MessageBox.Show(" 找到的路径是:\n" + ss); Form1.maparray = map; return; } } //--------------------------------------------------------------- Analisys(cuNode); } else { MessageBox.Show("没有路可走了"); Form1.maparray = map; return; } } AstarNode isExits(List<AstarNode> list, Point p) { foreach(AstarNode item in list ) { if(item.x==p.X && item.y==p.Y) { return item; } } return null; } void RemoveNode(List<AstarNode> list, Point p) { List<AstarNode> templist = (from item in list where item.x == p.X && item.y == p.Y select item).ToList(); foreach (AstarNode item in templist) { list.Remove(item); } } }
附:
A* 算法的详解
http://data.gameres.com/message.asp?TopicID=25439
源代码: