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
源代码: