【发布时间】:2014-08-12 12:51:52
【问题描述】:
我正在尝试为大学工作实施 A 星搜索方法,所以我需要从头开始,但我在让它以正确的方式工作时遇到了一些麻烦。 这是我的问题的图片:
如您所见,它确实找到了一条路径,但不是最简单的路径。
这是我的工具:
public List<node> updateAstar(){
//clear all the lists
openedNodes.Clear();
closedNodes.Clear();
nodesToLook.Clear();
//check if starpos and endpos are okay
if(startPos!=null && endPos!=null){
float F;
node currentNote=Grid.getNodeAtPos(startPos);
openedNodes.Add(currentNote);
int i = 0;
int size = 100;
while(currentNote.type!=tilesType.END){
if(i<=size){ //debugging purpose. prevent infinite loop
nodesToLook.Clear();
foreach(node nearNode in currentNote.getNearestTiles()){
if(closedNodes.Find(r => ((r.pos.x==nearNode.pos.x)&&(r.pos.y==nearNode.pos.y)))==null){
nodesToLook.Add(nearNode);
}
}
float bestValue=float.PositiveInfinity;
node bestNode=new node();
foreach(node lookingNode in nodesToLook){
//check if current node is not on the closed list
if((closedNodes.Find(r => ((r.pos.x==lookingNode.pos.x)&&(r.pos.y==lookingNode.pos.y)))==null)
&&(openedNodes.Find(r => ((r.pos.x==lookingNode.pos.x)&&(r.pos.y==lookingNode.pos.y)))==null)
&& lookingNode.type!=tilesType.BLOCK){
//calculate F=G+H
//assume path number is 0 for the question purpose
F=lookingNode.G[pathNumber]+lookingNode.H[pathNumber];
if(F<bestValue){
bestValue=F;
bestNode=lookingNode;
}else
closedNodes.Add(lookingNode);
}
}
openedNodes.Add(bestNode);
currentNote=bestNode;
i++;
}else{
Debug.Log("Error getting better path");
break;
}
}
}else Debug.Log("Current path does not have an startpos nor endpos");
return openedNodes;
}
这是我实例化每个节点的方式(我将其保存在矩阵中):
coordinate posAux=new coordinate();
this.myNodes=new node[columnNumber,lineNumber];
this.lineNumber=lineNumber;
this.columnNumber=columnNumber;
for(int y=0;y<lineNumber;y++){ // Y Desce = linhas
for(int x=0; x<columnNumber; x++){ // X vai pro lado = colunas
//create a node based on matrix position
posAux.Set(x, y);
tilesType type;
node current=new node(posAux);
//update up and left nodes
//"nodeDireita" means rightNode and "nodeEsquerda" means left node
if(x-1>=0){
current.nodeEsquerda=myNodes[x-1, y];
myNodes[x-1, y].nodeDireita=current;
}
if(y-1>=0){
current.nodeAcima=myNodes[x, y-1];
current.nodeAcima.nodeAbaixo=current;
}
//UNity stuff to set type of node visually based on what object is in it
Collider[] colliders;
if((colliders = Physics.OverlapSphere(coordinate.gridToUnity(posAux), 3f)).Length >0){
foreach(Collider collider in colliders){
objScript obj = collider.gameObject.GetComponent<objScript>();
current.type=obj.type;
if(current.type==tilesType.START){
path Path = new path (obj.pos, obj.posEnd, this);
addPath (Path);
Path.numeroPath=paths.IndexOf(Path);
}
}
}
myNodes[x,y]=current;
}
}
//adicionar vetor[] para H e G com numero de paths nos nodes
//create a vector for multiple paths in each node
int numeroPaths = paths.Count;
for (int y = 0; y < lineNumber; y++) {
for (int x = 0; x < columnNumber; x++) {
myNodes [x, y].H=new float[numeroPaths];
myNodes [x, y].G=new float[numeroPaths];
}
}
//adicionar Heuristica e G para cada node em cada path
//calculate heuristic and G for each node in each path
foreach (path Path in paths) {
coordinate start=Path.startPos, end=Path.endPos;
int numeroPath=paths.IndexOf(Path);
for (int y = 0; y < lineNumber; y++) {
for (int x = 0; x < columnNumber; x++) {
coordinate pos = myNodes [x, y].pos;
//G e H as manhattan distance
/*Mathf.Sqrt(Mathf.Pow((start.x - pos.x), 2) + Mathf.Pow((start.y - pos.y), 2)); euclidian-does not apply x.x */
myNodes [x, y].H[numeroPath]=Mathf.Abs(pos.x-end.x) + Mathf.Abs(pos.y-end.y);
myNodes [x, y].G[numeroPath]=Mathf.Abs(start.x-pos.x) + Mathf.Abs(start.y-pos.y);
}
}
}
代码参考:
--node 是一个自定义类,包含我使用曼哈顿公式定义的“G”和“H”,“x”、“y”、“BLOCK”或“NORMAL” (职位空缺)
--openedNodes 是一个列表,我为路径放置了正确的节点
--closedNodes 是我检查的节点,但有更大的“F”值;
--nodesToLook 是要检查的邻居节点。
感谢您的帮助。 谢谢。
【问题讨论】:
-
您是否特别需要自己实现这个?对于我最后一年的项目,我只是能够将this实现引用为一个dll,然后只需要一行代码就可以实现
-
正如我所评论的,整个目的是学习如何从头开始编写 IA 路径。
-
我没有看到一条评论说,无论哪种方式,该链接都有可能对您有所帮助的完整源代码。
-
请注意:您应该使用 HashSets 而不是 Lists(更快)甚至是 Bitarrays
-
一方面,您混淆了打开和关闭列表。打开列表包含最终必须检查的节点,而关闭列表包含不再检查的节点(因为它们无法通过更短的路径到达)。那么,如何计算节点的
G和H?我在任何地方都看不到任何成本的更新(这是算法的重要部分)。您对列表的处理总体上有点笨拙。例如。你真的不需要nodesToLook。而是直接将节点添加到打开列表中,或者如果它们已经在此列表中,则更新它们的成本。
标签: c# unity3d artificial-intelligence a-star