Need some pathfinding help

Discussion in 'Plugin Development' started by tips48, Mar 23, 2012.

Thread Status:
Not open for further replies.
  1. S0, I need some pathfinding help for a bot I'm making. Currently, it takes *really* long and times out the server.
    Main pathfinding code:
    Note: Ignore the println's ^_^
    Code:java
    1.  
    2.  
    3. System.out.println("Starting");
    4. nodes.clear();
    5.  
    6. MovementNode start = createNode(startLoc);
    7. MovementNode goal = createNode(goalLoc);
    8. if (start.getLocation().equals(goal.getLocation())) {
    9. return constructPath(start);
    10. }
    11.  
    12. Queue<MovementNode> queue = new PriorityQueue<MovementNode>();
    13. queue.add(start);
    14.  
    15. List<MovementNode> bestPath = null;
    16.  
    17. System.out.println("Stage 1");
    18. while (!queue.isEmpty()) {
    19. if (logged < 10) {
    20. System.out.println("Get MovementNode");
    21. }
    22. MovementNode current = queue.poll();
    23. if (current.wasVisited()) {
    24. if (logged < 10) {
    25. System.out.println("Visited");
    26. }
    27. continue;
    28. }
    29.  
    30. if (current.isBlocked()) {
    31. if (logged < 10) {
    32. System.out.println("Blocked");
    33. }
    34. continue;
    35. }
    36.  
    37. if (current == goal) {
    38. bestPath = constructPath(goal);
    39. break;
    40. }
    41.  
    42. for (MovementNode neighbor : current.getNeighbors()) {
    43. if (logged < 10) {
    44. System.out.println("Got neighbor");
    45. }
    46. if (neighbor.wasVisited()) {
    47. if (logged < 10) {
    48. System.out.println("Visited");
    49. }
    50. continue;
    51. }
    52. if (neighbor.isBlocked()) {
    53. if (logged < 10) {
    54. System.out.println("Blocked");
    55. }
    56. continue;
    57. }
    58.  
    59. int distance = current.getPathDistance()
    60. + (int) current.getLocation().distance(
    61. neighbor.getLocation());
    62. if (neighbor.getParent() != null
    63. && distance >= neighbor.getPathDistance()) {
    64. if (logged < 10) {
    65. System.out.println("Neighbor != null");
    66. }
    67. continue;
    68. }
    69.  
    70. neighbor.setPathDistance(distance);
    71. neighbor.setHeuristicDistance((int) neighbor.getLocation()
    72. .distance(goal.getLocation()) + distance);
    73. if (neighbor.getParent() == null) {
    74. if (logged < 10) {
    75. System.out.println("Parent is null");
    76. }
    77. neighbor.setPriority(neighbor.getHeuristicDistance());
    78. queue.add(neighbor);
    79. } else {
    80. if (logged < 10) {
    81. System.out.println("Parent isn't null");
    82. }
    83. neighbor.setPriority(neighbor.getHeuristicDistance());
    84. }
    85. neighbor.setParent(current);
    86. if (logged < 10) {
    87. System.out.println("Done with that node");
    88. logged++;
    89. }
    90. }
    91. }
    92.  
    93. System.out.println("Done!");
    94.  
    95. return bestPath == null ? null : bestPath;
    96.  
    97.  

    MovementNode:
    Code:java
    1.  
    2. public class MovementNode implements Comparable<MovementNode> {
    3. private final Location loc;
    4.  
    5. private MovementNode parent = null;
    6.  
    7. private Set<MovementNode> neighbors;
    8.  
    9. private final MovementPathfinder pathfinder;
    10.  
    11. private int pathDistance;
    12. private boolean visited;
    13. private int heuristicDistance;
    14.  
    15. private int priority = 0;
    16.  
    17. public MovementNode(MovementPathfinder pathfinder, Location loc) {
    18. this.pathfinder = pathfinder;
    19. this.loc = loc;
    20. }
    21.  
    22. public MovementNode getParent() {
    23. return parent;
    24. }
    25.  
    26. public void setParent(MovementNode parent) {
    27. this.parent = parent;
    28. }
    29.  
    30. public boolean wasVisited() {
    31. return visited;
    32. }
    33.  
    34. public void setVisited(boolean visited) {
    35. this.visited = visited;
    36. }
    37.  
    38. public Location getLocation() {
    39. return loc;
    40. }
    41.  
    42. /*
    43. * public boolean isTouching(MovementNode other) { Location otherLoc =
    44. * other.getLocation(); int x = otherLoc.getBlockX() - loc.getBlockX(); int
    45. * y = otherLoc.getBlockY() - loc.getBlockY(); int z = otherLoc.getBlockZ()
    46. * - loc.getBlockZ(); return ((x == 0 || x == 1 || x == -1) && (y == 0 || y
    47. * == 1 || y == -1) && (z == 0 || z == 1 || z == -1)); }
    48. *
    49. * public boolean isDiagonal(MovementNode other) { Location otherLoc =
    50. * other.getLocation(); int x = Math.abs(otherLoc.getBlockX() -
    51. * loc.getBlockX()); int z = Math.abs(otherLoc.getBlockZ() -
    52. * loc.getBlockZ()); return x == z; }
    53. */
    54.  
    55. public boolean isBlocked() {
    56. Block block = loc.getBlock();
    57. if (!(BlockUtils.canOccupy(block))) {
    58. // System.out.println("Not air");
    59. // Must be air
    60. return true;
    61. }
    62. Block above = block.getRelative(BlockFace.UP);
    63. if (!(BlockUtils.canOccupy(above))) {
    64. // System.out.println("Above not air");
    65. // Must be air
    66. return true;
    67. }
    68. Block below = block.getRelative(BlockFace.DOWN);
    69. if (!(BlockUtils.canStandOn(below))) {
    70. // System.out.println("Below cannot be stood on");
    71. return true;
    72. }
    73. return false;
    74. }
    75.  
    76. public Set<MovementNode> getNeighbors() {
    77. if (neighbors != null) {
    78. return neighbors;
    79. }
    80. neighbors = new HashSet<MovementNode>(24);
    81. //System.out.println("Creating neighbors");
    82. for (Block b : BlockUtils.getHollowCube(getLocation(), 1)) {
    83. //System.out.println("neighbor: " + b.toString());
    84. Location loc = b.getLocation();
    85. neighbors.add(pathfinder.getNode(loc));
    86. }
    87. return neighbors;
    88. }
    89.  
    90. /*
    91. * public int getCostFromStart() { if (costFromStart == -1) { costFromStart
    92. * = MovementNode.getEstimatedCostTo(helper.getStart(), this); } return
    93. * costFromStart; }
    94. */
    95.  
    96. public int getPathDistance() {
    97. return pathDistance;
    98. }
    99.  
    100. public void setPathDistance(int pathDistance) {
    101. this.pathDistance = pathDistance;
    102. }
    103.  
    104. public int getHeuristicDistance() {
    105. return heuristicDistance;
    106. }
    107.  
    108. public void setHeuristicDistance(int heuristicDistance) {
    109. this.heuristicDistance = heuristicDistance;
    110. }
    111.  
    112. public static int getEstimatedCostTo(MovementNode node, MovementNode other) {
    113. Validate.notNull(node, "Node cannot be null!");
    114. Validate.notNull(other, "Other cannot be null!");
    115.  
    116. Location loc = node.getLocation();
    117. Location otherLoc = other.getLocation();
    118.  
    119. return (int) Math.sqrt(Math.pow(loc.getBlockX() - otherLoc.getBlockX(),
    120. 2)
    121. + Math.pow(loc.getBlockY() - otherLoc.getBlockY(), 2)
    122. + Math.pow(loc.getBlockZ() - otherLoc.getBlockZ(), 2));
    123. }
    124.  
    125. public static String getHash(Location loc) {
    126. StringBuilder builder = new StringBuilder(5);
    127. return builder.append(loc.getBlockX()).append("_")
    128. .append(loc.getBlockY()).append("_").append(loc.getBlockZ())
    129. .toString();
    130. }
    131.  
    132. public int getPriority() {
    133. return priority;
    134. }
    135.  
    136. public void setPriority(int priority) {
    137. this.priority = priority;
    138. }
    139.  
    140. @Override
    141. public int compareTo(MovementNode node) {
    142. if (node.getPriority() == priority) {
    143. return 0;
    144. }
    145. return node.getPriority() < priority ? -1 : 1;
    146. }
    147.  
    148. }
    149.  

    And the actual tick method, called every tick.
    Code:java
    1.  
    2. public void tick() {
    3. // if (to == null) {
    4. // return;
    5. // }
    6. if (toMove == null) {
    7. return;
    8. }
    9. if (!(++ticks % 20 == 0)) {
    10. return;
    11. }
    12. Iterator<MovementNode> it = toMove.iterator();
    13. if (sprint) {
    14. for (int i = 0; i <= 5 && it.hasNext(); i++) {
    15. MovementNode node = it.next();
    16. Location loc = node.getLocation();
    17. npc.setPosition(loc.getX(), loc.getY(), loc.getZ());
    18. npc.lookAtPoint(loc);
    19. it.remove();
    20. }
    21. } else {
    22. for (int i = 0; i <= 4 && it.hasNext(); i++) {
    23. MovementNode node = it.next();
    24. Location loc = node.getLocation();
    25. npc.setPosition(loc.getX(), loc.getY(), loc.getZ());
    26. npc.lookAtPoint(loc);
    27. it.remove();
    28. }
    29. }
    30. if (toMove.isEmpty()) {
    31. toMove = null;
    32. }
    33. }
    34.  

    Tell me if you need any code, and thanks in advance!
     
  2. Offline

    JayEffKay

    tips48
    Pathfinding is one of the basics of game AI, there should be tons of documentation about it out there. I personally don't have much experience with it, but I'm willing to help out a bit.
    But first I'd like you to explain what algorithm you're making here (I do see something with heuristics) and where are you exactly using it for. What would also help is reposting the code with proper indentation (not sure if that fell away when copying, else you really need to start using it).
     
  3. The code seems to lose it's indentation when it's pasted, unfortunately.
    I'm attempting the use A* to move a custom NPC class (Which extends net.minecraft.server.EntityPlayer) to a given Location. Each NPC has a MovementHelper, and the movement helper's tick() method get's called every tick.
     
  4. Offline

    JayEffKay

    tips48
    Ok, this goes a bit over my head. If we were in the same room you could take me through your code, and you might even find an error yourself then. Right now I can't really make much out of this, probably also because of the lack of indentation and comments. Actually even the relationship of the first two pastes are not totally clear to me.
    Your tick method seems pretty simple and since it only works once a second it seems unlikely that that part is causing the lag (unless it's called for like 100ths of NPC's at the same time pherhaps), so something might be wrong with the pathfinder.
    If I read it right, your heuristic is a straight line. This is safe, because it's impossible to get a shorter path, but I do know A* is more efficient when the heuristic is as high as possible. When it's too high, you risk selecting a path that's not the shortest, but this might not be a big problem. Seems unlikely that a inefficient heuristic would time out your server, though.
     
  5. JayEffKay Through those println's, I have found it is something with the pathfinder, but for the life of me I can't figure out what :/
     
Thread Status:
Not open for further replies.

Share This Page