2013-09-23 2 views
0

A 지점에서 B 지점까지 최단 경로를 찾는 코드가 있습니다. 이렇게하려면 A 성급 변형을 사용하고 있습니다. 2 차원 배열을 사용하여 2 차원 그리드를 사용하고 있지만 경로가 대각선 바로 가기를 사용하지 않고 왼쪽, 오른쪽, 위, 아래 만 사용합니다. 지금까지 가능한 한 최단 경로를 항상 찾지 않는다는 것을 제외하고는 모든 것이 잘 작동합니다. 무엇이 잘못되고, 왜 잘못되고, 어떻게 해결할 수 있는지 알고 싶습니다. 미리 감사드립니다.최단 경로 문제가 발견되지 않는 별표 구현

BTW : 수학 벡터는 내 코드 (경로 찾는 클래스는 다음의 헬퍼 클래스, 첫 번째) 여기

A-Star gone wrong example

과 : 여기

정확히 무슨 일이 일어나고 있는지 설명하는 그림입니다 기하학적 포인트 클래스 이상은 아닙니다. playerTileLocation과 enemyTileLocation은 모두 그리드의 시작과 끝 노드에 해당하는 포인트입니다. 또한 정규 객체 대신 맵의 모든 타일 노드로 AStarNode 클래스를 사용합니다.

package { 
import src.Characters.Character; 
import src.InGame.Map; 
import src.Maths.MathVector; 

public final class BaseAI { 
// REPRESENTS UP, DOWN, RIGHT, AND LEFT OF ANY ONE NODE 
    private static const bordersOfNode:Array = new Array(
     new MathVector(-1, 0), new MathVector(1, 0), new MathVector(0, -1), new MathVector(0, 1)); 


    private var _player:Character; 
    private var map:Map; 

    private var playerTileLocation:MathVector; 



    private var openList:Array; 
    private var closedList:Array; 
// 2D ARRAY OF MAP TILES (I DON'T USE HERE, BUT I PLAN TO IN FUTURE) 
    private var mapArray:Array; 
    private var originNode:AStarNode; 
    private var complete:Boolean; 


    public function BaseAI(_player:Character,map:Map):void { 
     this._player = _player; 
     this.map = map; 

     openList = new Array(); 
     closedList = new Array(); 
     mapArray = map.tiles; 
    } 
    public function get player():Character { 
     return this._player; 
    } 

    public function calculatePlayerTileLocation():void { 
     playerTileLocation = map.worldToTilePoint(player.groundPosition); 
    } 
//WILL EVENTUAL RETURN A DIRECTION FOR THE ENEMY TO TAKE THAT ITERATION (EVERY 1-2 SECONDS) 
    public function getDirection(enemy:Character):String { 
     var enemyTileLocation:MathVector = map.worldToTilePoint(enemy.groundPosition); 


     originNode = new AStarNode(enemyTileLocation, playerTileLocation); 
     originNode.setAsOrigin(); 

     openList = [originNode]; 
     closedList = []; 

     complete = false; 
     var currentNode:AStarNode; 
     var examiningNode:AStarNode; 

     while (!complete) { 

      openList.sortOn("F", Array.NUMERIC); 
      currentNode = openList[0]; 
      closedList.push(currentNode); 
      openList.splice(0, 1); 

      for (var i in bordersOfNode) { 
       examiningNode = new AStarNode(new MathVector(currentNode.X + bordersOfNode[i].x, currentNode.Y + bordersOfNode[i].y),playerTileLocation); 

       if (map.isOpenTile(map.getTile(examiningNode.X, examiningNode.Y)) && !examiningNode.isThisInArray(closedList)) { 
        if (!examiningNode.isThisInArray(openList)) { 
         openList.push(examiningNode); 
         examiningNode.parentNode = currentNode; 
        }else { 

        } 
        if (examiningNode.X == playerTileLocation.x && examiningNode.Y == playerTileLocation.y) { 
         complete = true; 
         var done:Boolean = false; 
         var thisNode:AStarNode; 
         thisNode = examiningNode; 
         while (!done) { 
          if (thisNode.checkIfOrigin()) { 
           done = true; 
          }else { 
           thisNode = thisNode.parentNode; 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 

}이 코드를 통해

package { 
import src.Maths.MathVector; 

internal final class AStarNode { 
    private var _X:int; 
    private var _Y:int; 

    private var _G:int; 
    private var _H:int; 
    private var _F:int; 
    private var _parentNode:AStarNode; 

    private var _isOrigin:Boolean; 

    public static const VERTICAL:uint = 10; 

    public function AStarNode(thisNodeLocation:MathVector, targetNodeLocation:MathVector) { 
     X = thisNodeLocation.x; 
     Y = thisNodeLocation.y; 
     H = Math.abs(X - targetNodeLocation.x) + Math.abs(Y - targetNodeLocation.y); 
     G = 0; 
     F = H + G; 
    } 

    public function set X(newX:int):void { 
     this._X = newX; 
    } 
    public function get X():int { 
     return this._X; 
    } 

    public function set Y(newY:int):void { 
     this._Y = newY; 
    } 
    public function get Y():int { 
     return this._Y; 
    } 

    public function set G(newG:int):void { 
     this._G = newG; 
    } 
    public function get G():int { 
     return this._G; 
    } 

    public function set H(newH:int):void { 
     this._H = newH; 
    } 
    public function get H():int { 
     return this._H; 
    } 

    public function set F(newF:int):void { 
     this._F = newF; 
    } 
    public function get F():int { 
     return this._F; 
    } 

    public function set parentNode(newParentNode:AStarNode):void { 
     this._parentNode = newParentNode; 
    } 
    public function get parentNode():AStarNode { 
     return this._parentNode; 
    } 

    public function setAsOrigin():void { 
     _isOrigin = true; 
    } 
    public function checkIfOrigin():Boolean { 
     return _isOrigin; 
    } 

    public function isThisInArray(arrayToCheck:Array):Boolean { 
     for (var i in arrayToCheck) { 
      if (arrayToCheck[i].X == this.X && arrayToCheck[i].Y == this.Y) { 
       return true 
      } 
     } 
     return false 
    } 
} 
enter code here 

}

답변

1

순간적 잘못된 추론의 아이디어를 제기한다. 노드에서 G 값은 항상 0입니다. 임대시 변경할 수있는 위치가 표시되지 않습니다. 그러나 장애물이있는 최단 경로를 찾는 작업에 대한 A-star 알고리즘에서는 이미 셀에 도달하는 단계 수를 나타내야합니다. 그러면 알고리즘이 긴 경로를 더 짧은 경로로 대체 할 수 있습니다.

+0

와우, 나는 별의 그 부분에 대해 완전히 잊어 버렸고, 이제 왜 이상하게 행동했는지 알 수 있습니다. – Xiler

0

내가 한 번 '별'알고리즘을 코딩 했으므로 그리드에 대해 2 차원 배열을 사용했다. 검색을 시작할 때 각 그리드 위치의 'searched'속성이 false로 설정되었습니다. 각 그리드 위치에는 연결 방향 배열이 있습니다. 플레이어가 이동할 수있는 옵션 - 일부는 열려있을 수도 있고, 일부는 차단되거나 액세스 할 수 없을 수도 있습니다.
얼마나 많은 방향 옵션이 있는지에 대한 시작 격자 위치를 확인하여 검색을 시작합니다. 각 옵션에 대해 '경로'배열을 _paths 배열로 푸시합니다. 각 '경로'배열은 '이동'시퀀스를 포함하게됩니다 (위쪽 0, 오른쪽 1, 아래쪽 2, 왼쪽 3). 그래서 각각의 초기 경로에 대해, 나는 해당 시작 동작을 밀어 넣을 것이다. 또한 격자 위치의 'searched'속성을 true로 설정합니다.
그런 다음 각 경로를 반복하여 가장 최근에 추가 된 위치로 이동하는 일련의 이동을 실행합니다. 해당 위치가 대상 위치인지 확인합니다. 그렇지 않은 경우 검색된 위치를 표시 한 다음 사용 가능한 경로를 확인하고 이미 검색 한 위치는 무시합니다. 사용 가능하지 않은 경우 경로가 닫히고 경로 배열에서 '연결'됩니다.
그렇지 않으면 현재 경로 배열의 ByteArray '전체 복사본'이 첫 번째 이동 옵션을 초과하여 사용 가능한 각 이동 옵션에 대해 만들어졌습니다. 한 방향으로의 이동이 현재 경로와 새 경로에 각각의 방향으로 추가되었습니다.
경로 수가 0에 도달하면 두 위치 사이에 경로가 없습니다. 나는 그것에 관한 것이라고 생각한다. 그게 도움이되기를 바랍니다.
검색이 대상을 향해 '지시'될 필요는 없습니다. 내가 제안한 것은 가능한 모든 경로를 검색하고 이미 검색된 위치를 확인하려고하는 경로를 죽이는 방식으로 가장 직접적인 경로를 찾는 '일어난다'는 것입니다. 즉, 다른 경로가 먼저 있으므로 더 짧습니다.

+0

Sayonji Nakate가 내 질문에 대답 한 것처럼 보였습니다. 그러나이 접근법 역시 흥미 롭습니다. 어떤 접근 방식이 가장 빠르지는 모르지만 경로 찾기에 있어서는 매우 중요합니다. 아이디어를 가져 주셔서 감사합니다. – Xiler