6

I am writing a fairly simple top down, 2D game. It uses an evenly spaced 2D grid of tiles for all collision data. Each tile in the grid is either solid or empty.

For path finding I am using A* (A Star), and have tried both Manhattan and Diagonal (aka Chebyshev distance) heuristics.

It works well in most cases, but becomes quite expensive when trying to path find to a target sitting in the recess of a concave shape (eg. a U shape).

For example, in the picture below, the guy on the right will path find to the guy on the left. All the grass (green, dark green and yellow) is empty space. The only solid tiles are the brown "wood" tiles, and grey "Stone" tiles, making the shape of a sideways "U".

Unsolved example

Now here is the results of the path search (in this case A* with Manhattan Heuristics):

Solved example

The red and green debug draw squares show which tiles were visited during the A* search. Red are in the "Closed" list and green are in the "Open" list (as per A* specifications). The blue line in the final path chosen (which is correct).

As you can see, the search has been fairly exhaustive, visiting lots of tiles, creating an almost perfect circle.

I understand why this is happening based on the A* algorithm, and my chosen heuristics (as you move passed the target along the wall, the tiles further away begin to have better F values, causing them to be explored before coming back to the correct path). What I don't know is how to make this better :)

Any suggestions on possible improvements? Possibly a different heuristic? Maybe a different path searching algorithm all together?

Thanks!


Based on some suggestions, I am leaning towards updating my A* implementation to include the improvements found in HPA*. Based on some initial reading, it seems that it will address cases like the one above quite well, given the right amount of granularity in the hierarchy. I'll update once I finish looking into this.

Goose
  • 1,268
  • 1
  • 14
  • 27
  • 1
    You could try to implement a speed-up-technique described here http://web.cs.du.edu/~sturtevant/papers/highlevelpathfinding.pdf and implemented in Java here https://github.com/graphhopper/graphhopper – Karussell Feb 08 '13 at 19:24
  • Very interesting read, thanks! I am leaning towards some sort of nav mesh, and this had some interesting ideas. – Goose Feb 09 '13 at 04:33

2 Answers2

4

You need to break ties towards the endpoint.

Without breaking ties towards endpoint
(Without breaking ties towards endpoint)

With breaking ties towards endpoint
(With breaking ties towards endpoint)

Example with an obstacle
(Example with an obstacle)

BlueRaja - Danny Pflughoeft
  • 75,675
  • 28
  • 177
  • 259
  • 1
    The illustrations are very handy! – user1306322 Feb 08 '13 at 06:34
  • Thanks of the information, but unfortunately I don't think this is what I am looking for. In the case of a concave shape, the issue isn't that there are a lot of tiles with equal H values, but rather, that the correct path requires that you pass through tiles which are seemingly worse, before coming back around the end. You must get further away, before you can start getting closer again (similar to the "example with obstacle" which has the issue I am seeing). – Goose Feb 08 '13 at 07:11
  • @Goose I don't understand, what the problem is then. The method described in this answer makes path finding faster. The best path to the target in your case will always make distance delta positive at some point. – user1306322 Feb 08 '13 at 07:31
  • @Goose: This is exactly the solution to your problem - in your example above, it should cut the number of tiles examined by about half. I don't believe there is any more efficient way to do it, without losing the optimality guarantee. If it is still too slow, you are probably running the pathfinder too often - for 99% of games, you don't need to run it every frame, once or twice a second is more than enough. (cont.) – BlueRaja - Danny Pflughoeft Feb 08 '13 at 08:18
  • 1
    (cont.) Also, if you're running this algorithm on multiple units, sharing pathfinding info between them can often speed things up drastically. Finally, if that is **still** too slow, you may want to look into an approximation algorithm such as [HPA*](http://gamedev.stackexchange.com/questions/32813/32831#32831) or [A*-Epsilon](http://stackoverflow.com/questions/13075199) (aka. [Anytime A*](http://www.cs.cmu.edu/~maxim/files/ara_nips03.pdf)). – BlueRaja - Danny Pflughoeft Feb 08 '13 at 08:20
  • This can actually be optimized so that it runs exactly as many times as necessary, which might be only once every tilemap (or any other blocking game object) change. – user1306322 Feb 08 '13 at 11:03
  • I must be misunderstanding; maybe you can help clarify. My understanding is that the "break ties" technique reduces the number of nodes visited by putting a strong emphasis on H (cost to destination). However, in my problem, once you go passed the destination (trying to move around the wall), cost-to-destination starts increasing. It is the same reason the "Example with Obstacle" still performs poorly before passing the obstacle. It does not cut my nodes in half; the results are identical. All the open nodes in a circle have the same cost-to-destination (even when artificially bumped). – Goose Feb 08 '13 at 18:21
  • (cont.) I should also mention that I don't have the issues shown in the first example you posted, so it is possible my Heuristics solving the basic issues to begin with (or maybe it has to do with the fact that I allow diagonal movement). I am thinking that I need to either look into an approximation algorithm (as suggested) or try generating a navmesh dynamically to make large open areas less punishing. – Goose Feb 08 '13 at 18:26
1

I ended up using Dynamic HPA*. I have written details on the solution here:

http://www.matthughson.com/2013/03/05/dynamic-hpa-part-1/

Goose
  • 1,268
  • 1
  • 14
  • 27