I have my AI to where it only looks at the 3 tiles in front of it for pathfinding which depends on the direction. However during pathfinding it may check a tile that is a action tile.
An action tile is one that moves you to another tile (changes your position).
The player ships can only go in 3 directions (Forward, Left, Right): the left and right turns move the ship diagonally on the grid.
Basic movement example:
Start:
- Ship position: (4,3)
- Face: North
- Move placed: Forward
End result:
- Ship position: (4,4)
- Face: North
Action movement example: (Action tile at location 4,4)
Start:
- Ship position: (4,3)
- Face: North
- Move placed: Forward
End result:
- Ship position: (4,5) // as shown moves player an extra space
- Face: North
The method to find the next position based on the action tile is given as context.getMap().getNextActionTilePositionForTile(position, tile);
: tile - type of action tile; position - current position
How would I make my algorithm account for the action tiles that change position when calculating a path?
Pathfinding Class:
public class AStarSearch {
private ServerContext context;
private List<AStarNode> openList;
private List<AStarNode> closedList;
public AStarSearch(ServerContext context) {
this.context = context;
}
private Comparator<AStarNode> nodeSorter = new Comparator<AStarNode>() {
@Override
public int compare(AStarNode n0, AStarNode n1) {
if(n1.fCost < n0.fCost) return 1;
if(n1.fCost > n0.fCost) return -1;
return 0;
}
};
public List<AStarNode> findPath(VesselFace startFace, Position start, Position goal){
openList = new ArrayList<AStarNode>();
closedList = new ArrayList<AStarNode>();
List<AStarNode> neighbors = new ArrayList<AStarNode>();
AStarNode current = new AStarNode(start, startFace, null, 0, start.distance(goal));
openList.add(current);
while(openList.size() > 0) {
Collections.sort(openList, nodeSorter);
current = openList.get(0);
if(current.position.equals(goal)) {
List<AStarNode> path = new ArrayList<AStarNode>();
while(current.parent != null) {
path.add(current);
current = current.parent;
}
openList.clear();
closedList.clear();
return path;
}
openList.remove(current);
closedList.add(current);
int x = current.position.getX();
int y = current.position.getY();
switch (current.face) {
case NORTH:
neighbors.add(new AStarNode(new Position(x-1, y+1), VesselFace.WEST,current,0,0));
neighbors.add(new AStarNode(new Position(x, y+1), VesselFace.NORTH,current,0,0));
neighbors.add(new AStarNode(new Position(x+1, y+1), VesselFace.EAST,current,0,0));
break;
case EAST:
neighbors.add(new AStarNode(new Position(x+1, y+1), VesselFace.NORTH,current,0,0));
neighbors.add(new AStarNode(new Position(x+1, y), VesselFace.EAST,current,0,0));
neighbors.add(new AStarNode(new Position(x+1, y-1), VesselFace.SOUTH,current,0,0));
break;
case SOUTH:
neighbors.add(new AStarNode(new Position(x-1, y-1), VesselFace.WEST,current,0,0));
neighbors.add(new AStarNode(new Position(x, y-1), VesselFace.SOUTH,current,0,0));
neighbors.add(new AStarNode(new Position(x+1, y-1), VesselFace.EAST,current,0,0));
break;
case WEST:
neighbors.add(new AStarNode(new Position(x-1, y+1), VesselFace.NORTH,current,0,0));
neighbors.add(new AStarNode(new Position(x-1, y), VesselFace.WEST,current,0,0));
neighbors.add(new AStarNode(new Position(x-1, y-1), VesselFace.SOUTH,current,0,0));
break;
}
for(AStarNode neighborNode : neighbors) {
int at = context.getMap().getTile(neighborNode.position.getX(), neighborNode.position.getY());
if(at > 2){ // special action tiles
//TODO - allow ship to navigate through action tiles by looking ahead
// neighborNode.position = context.getMap().getNextActionTilePositionForTile(neighborNode.position, at);
}
if(at == 1 || at == 2) continue; // ignore rocks
double gCost = current.gCost + current.position.distance(neighborNode.position);
double hCost = neighborNode.position.distance(goal);
AStarNode node = new AStarNode(neighborNode.position, neighborNode.face, current, gCost, hCost);
if(positionInList(closedList, neighborNode.position) && gCost >= node.gCost) continue;
if(!positionInList(openList, neighborNode.position) || gCost < node.gCost) openList.add(node);
}
}
closedList.clear();
return null;
}
private boolean positionInList(List<AStarNode> list, Position position) {
for(AStarNode n : list) {
if(n.position.equals(position)) return true;
}
return false;
}
}
Node class:
public class AStarNode {
public Position position;
public VesselFace face;
public AStarNode parent;
public double fCost, gCost, hCost;
public AStarNode(Position position, VesselFace face, AStarNode parent, double gCost, double hCost) {
this.position = position;
this.face = face;
this.parent = parent;
this.gCost = gCost;
this.hCost = hCost;
this.fCost = this.gCost + this.hCost;
}
}
```