Search code examples
javapath-finding2d-games

A* Pathfinding - Stop moving diagonal through tiles


I'm trying to get my head around the A* search algorithm and I got a square moving through a maze but the square will travel through two tiles that are touching by the corners. Here is an example:

Image - Click here

Is there anyway of stopping the algorithm from adding this to the path

public List<Node> findPath(Vector2i start, Vector2i goal){

    List<Node> openList = new ArrayList<Node>();
    List<Node> closeList = new ArrayList<Node>();

    Node current = new Node(start, null, 0, getDistance(start, goal));
    openList.add(current);
    while(openList.size() > 0){
        Collections.sort(openList, nodeSorter);
        current = openList.get(0);
        if(current.tile.equals(goal)){
            List<Node> path = new ArrayList<Node>();
            while(current.parent != null){
                path.add(current);
                current = current.parent;
            }
            openList.clear();
            closeList.clear();
            return path;
        }
        openList.remove(current);
        closeList.add(current);
        for(int i = 0; i < 9; i++){
            if(i == 4) continue;
            int x = current.tile.getX();
            int y = current.tile.getY();
            int xi = (i % 3) - 1;
            int yi = (i / 3) - 1;
            Tile at = getTile(x + xi, y + yi);
            if(at == null || at == Tile.voidTile) continue;
            if(at.isSolid()) continue;

            Vector2i a = new Vector2i(x + xi, y + yi);
            double gCost = current.gCost + getDistance(current.tile, a);
            double hCost = getDistance(a, goal);
            Node node = new Node(a, current, gCost, hCost);
            if(vecInList(closeList, a) && gCost >= current.gCost) continue;
            if(!vecInList(openList, a) || gCost < node.gCost) openList.add(node);
        }
    }
    closeList.clear();
    return null;
}

Solution

  • Small off-topic: If you do not want to add such tiles to open list, then they must not be considered as neighbors. So the basic question that you should answer creating a pathfinding algorithm - what nodes are considered to be neighbors in my graph.

    In your case, your current tile is not neighbor of diagonal tile if their both common neighbors are not passable. For example, for tile {+1, +1} those neighbors will be {0, +1} and {+1, 0}. And so on. So, lets check for it:

    // code here...
    if(at.isSolid()) continue;
    
    if (Math.abs(xi * yi) == 1) {
      // this is true if we're checking diagonal tile
      if ( !isPassable(getTile(x + xi, y)) && !isPassable(getTile(x, y + yi))  {
        // Both common neigbors are not passable
        // So we won't add this tile as neighbor
        continue;
      }
    }
    

    And method isPassable:

    private boolean isPassable(Tile tile) {
      return tile != Tile.voidTile && !tile.isSolid();
    }
    

    Common neigbors always exist if you deal with diagonal tile, so you shouldn't check them for null.