我在为大学作业实现A星搜索方法,所以需要从头开始构建,但我在使其正确工作方面遇到了些问题。以下是我问题的图片:
如你所见,它确实找到了一个路径,但不是最简单的路径。
这是我的实现代码:
public List<node> updateAstar(){ //清空所有列表 openedNodes.Clear(); closedNodes.Clear(); nodesToLook.Clear(); //检查起点和终点是否正常 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){ //调试用,防止无限循环 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){ //检查当前节点是否不在关闭列表中 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){ //计算F=G+H //假设路径编号为0,仅为问题说明之用 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 //根据矩阵位置创建节点 posAux.Set(x, y); tilesType type; node current=new node(posAux); //更新上方和左侧节点 //"nodeDireita"表示右节点,"nodeEsquerda"表示左节点 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相关内容,用于根据对象类型视觉设置节点类型 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; }} //为节点添加H和G向量以支持多个路径//为每个节点创建支持多个路径的向量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]; }}//为每个路径的每个节点计算启发式和G//计算每个路径中每个节点的启发式和Gforeach (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和H使用曼哈顿距离 /*Mathf.Sqrt(Mathf.Pow((start.x - pos.x), 2) + Mathf.Pow((start.y - pos.y), 2)); 欧几里得距离 - 不适用于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 是用于检查的邻居节点。
感谢任何帮助。谢谢。
回答: