libgdx / gdx-ai

Artificial Intelligence framework for games based on libGDX or not. Features: Steering Behaviors, Formation Motion, Pathfinding, Behavior Trees and Finite State Machines
Apache License 2.0
1.17k stars 241 forks source link

Subsequent calls to PathFinderRequest.search throw exception #92

Open tomcashman opened 7 years ago

tomcashman commented 7 years ago

Issue details

It seems that once the path is found or not found, subsequent calls to PathFinderRequest.search will throw an exception. I was receiving the exception in my game and it took some time to figure out. I would expect that calling search after the path is found or not found would just immediately return true.

Version of gdx-ai and/or relevant dependencies

1.9.6

Stacktrace

Found path
Exception in thread "LWJGL Application" java.lang.ArrayIndexOutOfBoundsException: -1
    at com.badlogic.gdx.utils.BinaryHeap.remove(BinaryHeap.java:70)
    at com.badlogic.gdx.utils.BinaryHeap.pop(BinaryHeap.java:60)
    at com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder.search(IndexedAStarPathFinder.java:144)
    at com.badlogic.gdx.ai.pfa.PathFinderRequest.search(PathFinderRequest.java:88)
    at com.mygdx.game.BugExample.render(BugExample.java:26)
    at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:225)
    at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:126)
davebaol commented 7 years ago

Glad to see you back again. I'm going to investigate this issue asap. Thanks for the report.

davebaol commented 7 years ago

Not sure how to reproduce your issue, but after a quick glance at the stack trace I guess that replacing the loop do { ... } while (openList.size > 0); with the loop while (openList.size > 0) { ... } should fix the issue.

Can you confirm?

tomcashman commented 7 years ago

I can check this evening but I've attached a quick example I wrote the other day trying to solve the issue. I think the issue may be a documentation problem as I might be using the API wrong?

gdx-ai-bug.zip

davebaol commented 7 years ago

Well, yes, I have to admit that the documentation about interruptible pathfinding is not exhaustive at all. You should not call PathFinderRequest.search() directly. That method should be called for you by the PathFinderRequestControl of the PathFinderQueue. Ideally, with time sliced pathfinding you have to use a queue because a single search may take several frames to complete and there might be new incoming requests in the meantime.

It might be worth adding a check before the above-mentioned loop in order to detect and report possible improper use of the API. I mean, something like

if (openList.size == 0) {
  throw new RuntimeException("The open list is unexpectedly empty. Usually, this means that you're misusing the API.");
}