Clearance-based Pathfinding and Hierarchical Annotated A* Search

来源:互联网 发布:什么是php的面向对象 编辑:程序博客网 时间:2024/05/20 23:56

origin URL:

http://aigamedev.com/open/article/clearance-based-pathfinding/

 

 

This article was originally published as part of AiGameDev.com Premium (re-opening on May 6th) and written by Daniel Harabor,Ph.D. researcher at the NICTA and The Australian National University,specializing in pathfinding and game AI. You can contact him by emailat <daniel.harabor at nicta.com.au>

Real-time strategy (RTS) games often feature a wide number unittypes for the player to control. One of my favourite titles from thepast, Westwood’s seminal Red Alert,had many classes of differently sized units: small infantry soldiers,medium-sized Jeeps and large tanks. In Red Alert 3, the most recentincarnation of the series, the diversity is increased even further bythe introduction of units with terrain-specific movement capabilities(Figure 1). From a pathfinding perspective this introduces aninteresting question: how can we efficiently search for valid routesfor variable-sized agents in rich environments with many types ofterrain?

This was the topic of a recent paper [1] I co-wrote with Adi Botea and which I presented at CIG’08. In the talkI outlined Hierarchical Annotated A* (HAA*), a path planner which isable to efficiently address this problem by first analysing the terrainof a game map and then building a much smaller approximaterepresentation that captures the essential topographical features ofthe original. HAA* works by using a distance-to-obstacle metric tocalculate the amount of clearance (or free space) at each tile in agrid environment. This simple method is the basis for a hierarchicalclearance-based pathfinding approach that is able to answer queries formany different types of units with distinct sizes and terrain traversalcapabilities. HAA* is shown to be an order of magnitude faster thanlow-level A* search, produces near-optimal solutions and requireslittle memory overhead in practice.

Figure 1: EA’s Red Alert 3 features a wide variety ofland-based, aquatic and amphibious units. Each class has distinctiveshape and size characteristics.

In this article I want to outline the two major aspects of HAA*.First, I’ll discuss how one can analyse a grid map to automaticallyextract clearance-related topographical information. Second, I’llexplain how HAA* is able to use this information to buildspace-efficient abstractions that allow a range of agents withdifferent sizes and terrain traversal capabilities to very quickly finda high quality path through a static multi-terrain environment.

Clearance Values and the Brushfire Algorithm

Simply put, a clearance value is a distance-to-obstacle metric whichis concerned with the amount of traversable space at a discrete pointin the environment. Clearance values are useful because they allow usto quickly determine which areas of a map are traversable by an agentof some arbitrary size. The idea of measuring distances to obstacles inpathfinding applications is not a new one. The Brushfire algorithm [2]for instance is particularly well known to robotics researchers (thoughfor different reasons than those motivating this article). This simplemethod, which is applicable to grid worlds, proceeds as so:

First, to each traversable tile immediately adjacent to a staticobstacle in the environment (for example, a large rock or along theperimeter of a building) assign a value of 1. Next, each traversableneighbour of an assigned tile is itself assigned a value of 2 (unless asmaller value has already been assigned). The process continues in thisfashion until all tiles have been considered; Figure 2 highlights thisidea; here white tiles are traversable and black tiles representobstacles (NB: The original algorithm actually assigns tiles adjacentto obstacles a value of 2; I use 1 here because it makes more sense forour purposes).

Figure 2: A small toy map annotated with values computed by the Brushfire algorithm. Black tiles are not traversable.

Figure 3: A 1×1 agent finds a path to the goal. All traversable tiles are included in the search space.


Figure 4: A 2×2 agent finds a path to the goal. Only tiles with clearance > 1 are considered.

Figure 5: A 2×2 agent fails to find a path due to incorrectclearance values near the goal. Notice that the highlighted tiles areinfact traversable by this agent.


Brushfire makes use of a minimum obstacle distance metricto compute clearances which works reasonably well in many situations.If we assume our agents (I use the term agent and unit interchangeably)are surrounded by a square bounding box we can immediately use thecomputed values to identify traversable locations from non-traversableones by comparing the size of an agent with the corresponding clearanceof particular tile. Figure 3 shows the search space for an agent ofsize 1×1; in this case, any tile with clearance equal to at least 1 istraversable. Similarly, in Figure 4 the search space is shown for anagent of size 2×2. Notice that the bigger agent can occupy much fewerlocations on the map; only tiles with clearance values at least equalto 2. Because this approach is so simple it has seen widespread use,even in video games. At GDC 2007 Chris Jurney (from RelicEntertainment) described a pathfinding system [3]for dealing with variable-sized agents in Company of Heroes — whichhappens to make use of a variant of the Brushfire algorithm (NB: thiswork actually takes a similar approach to HAA* but a direct comparisonis difficult because the method is not outlined in great detail;nevertheless, it’s quite a nice presentation.).

Unfortunately, clearances computed using minimum obstacle distancedo not accurately represent the amount of traversable space at eachtile. Consider the example in Figure 5; Here our 2×2 agent incorrectlyfails to find a path because all tiles in the bottleneck region areassigned clearance values less than 2. To overcome this limitation wewill focus on an alternative obstacle-distance metric: true clearance.

The True Clearance Metric

The process of measuring true clearance for a given map tile is verystraightforward: Surround each tile with a clearance square (boundingbox really) of size 1×1. If the tile is traversable, assign it aninital clearance of 1. Next, expand the square symmetrically down andto the right, incrementing the clearance value each time, until nofurther expansions are possible. An expansion is successful only if alltiles within the square are traversable. If the clearance squareintersects with an obstacle or with the edge of the map the expansionfails and the algorithm selects another tile to process. The algorithmterminates when all tiles on the map have been considered. Figure 6highlights the process and Figure 7 shows the result on our runningexample.

Figure 6: After selecting a tile (a) the square is expanded twice (b, c) before intersecting an obstacle (d).

Figure 7: The toymap from Figure 2, annotated with true clearance values.


Notice that by using true clearance the example from Figure 5 nowsucceeds in finding a solution. Infact, one can prove that using thetrue clearance metric it is always possible to find a solution for anyagent size if a valid path exists to begin with (i.e. the method iscomplete; see [1] for details).

Dealing With Multiple Terrain Types

Until now the discussion has been limited to a single type oftraversable terrain (white tiles). As it turns out however, it isrelatively easy to apply any clearance metric to maps involvingarbitrarily many terrain types. Given a map with n terraintypes we begin by first identifying the set of possible terraintraversal capabilities an agent may possess. A capability is simply adisjunction of terrains used to specify where each agent can traverse.So, on a map with 2 terrains such as {Ground, Water} the corresponding list of all possible capabilities is given by a set of sets; in this case {{Ground}, {Water}, {Ground, Water}}.Note that, for simplicity, I assume the traveling speed across allterrains is constant (but this constraint is easily lifted).

Next, we calculate and assign a clearance value to each tile forevery capability. Figures 8-10 show the corresponding clearance valuesfor each capability on our toy map; notice that we’ve converted some ofthe black (obstacle) tiles to blue to represent the Water terrain type(which some agents can traverse).

Figure 8: True clearance annotations for the {Ground} capability (only white tiles are traversable).

Figure 9: True clearance annotations for the {Water} capability (only blue tiles are traversable).


Figure 10: True clearance annotations for the {Ground, Water} capability (both white and blue tiles are traversable).


Theoretically this means that, at most, each tile will store 2n-1 clearance value annotations (here n corresponds to the number of terrains; see [1]for details). I suspect this overhead can probably be improved withclever use of compression optimisations though I did not attempt morethan a naive implementation. Alternatively, if memory is very limited(as is the case with many robot-related applications) one can simplycompute true clearance on demand for each tile, thus trading off alittle processing speed for more space.

Annotated A*

In order to actually find a path for an agent with arbitrary size and capability we can use the venerable A* algorithm [4]albeit with some minor modifications. First, we must pass two extraparameters to A*’s search function: the agent’s size and capability.Next, we augment the search function slightly so that before a tile isadded to A*’s open list we first verify that it is infact traversablefor the given size and capability; everything else remains the same. Atile is traversable only if its terrain type appears in the set ofterrains that comprise the agent’s capability and if the correspondingclearance value is at least equal to the size of the agent. Toillustrate these ideas I’ve put together a simplified pseudocodeimplementation of the algorithm, Annotated A*:

Function: getPath
Parameters: start, goal, size, capability

push start onto open list.
for each node on the open list
if current node is the goal,
return path.
else,
for each neighbour of the newly opened node
if neighbour is on the closed list, skip it
else,
if neighbour is already on the open list, update weights
else,
if clearance(neighbour, capability) > size,
push neighbour on the open list
else, skip neighbour
push current node on closed list
if openlist is null, return failure

 

If you’re interested in playing with a working implementation of Annotated A* you can check out the source code I wrote to evaluate it. It’s written in C++ and based on the University of Alberta’s freely available pathfinding library, Hierarchical Open Graph(or HOG). HOG compiles on most platforms; I’ve personally tested it onboth OSX and Linux and I’m told it works on Windows too. The classes ofmost interest are probably AnnotatedMapAbstraction, which deals with computing true clearance values for a map, and AnnotatedAStar which is the reference implementation of the search algorithm described here.

Hierarchical Abstraction

Having described a simple clearance-based pathfinding system we can now turn our attention to speeding it up through the use of hierarchical abstraction.The main problem here is that a multi-terrain map annotated withclearance values contains lots of topographical information butabstraction methods can only hope to approximate the original. Thus,the goal is to build an abstraction which is representationally completei.e. if a path between two points can be found on the originalannotated map, we should be able to also find it using only theabstract map. To achieve this we’re going to attack the problem in 3steps:

  1. First, we divide our annotated map into a set of adjacent Clusters connected by Entrances. Wewill show that the resultant graph produced by this process is infactrepresentationally complete but contains redundant and duplicatedinformation.

  2. Second, we compact the graph produced in the previous step usingdominance techniques which identify and prune unnecessary nodes andedges. The resultant abstraction is shown to contain a minimal set ofnodes and edges yet still retains the representational completenessproperties of the original map.

  3. Third, we describe the Hierarchical Annotated A* algorithm (HAA*)which we use to efficiently answer queries for a wide variety of agentswith different sizes and terrain traversal capabilities. HAA* is shownto produce very high quality (i.e. near optimal) paths withcomparatively little search effort vs. Annotated A*.

Clusters and Entrances

In order to create an an abstract representation of an annotated map we follow Botea et al [5]and divide the environment into a series of discrete square-sized areascalled clusters. Figure 11 shows the result of this step on our runningexample using clusters of size 5×5.

Figure 11. The map is divided into four 5×5 clusters.

Figure 12. (a) Three entrances are identified betweenclusters C1 and C3, one for each possible capability. (b) Eachtransition point (denoted by a strong dark line) maximises clearancefor a particular capability.

Next, we identify entrances between each pair of adjacent clusters.An entrance is defined as an obstacle-free area of maximal size thatexists along the border between two clusters (Figure 12a). Eachentrance has associated with it a transition point which reflects thefact that an agent can traverse from one cluster to the other. To thisend we select from each entrance a pair of adjacent tiles, one fromeach cluster, which maximise clearance (Figure 12b). Each transitionpoint is represented in the abstract graph by two nodes connected witha single inter-edge of weight 1.0. The inter-edge is alsoannotated with the corresponding capability and clearance value thatreflect the traversability requirements of the transition point.

Figure 13. A complete initial abstraction.

Finally, we complete the abstraction by finding all possible ways totraverse each cluster. We achieve this by running Annotated A* (AA*)between each pair of abstract nodes inside a cluster; one search foreach combination of possible agent sizes and capabilities. Every timeAA* successfully finds a path we add a new intra-edge betweenthe start and goal nodes. The weight of the edge is equal to the lengthof the path and we further annotate it with the size and capabilityparameters used by AA* to reflect the traversability requirements ofthe path. This approach is highly effective at capturing all pertinenttopographical details of the original map. Infact, it is easy to seethat the resultant graph (which is termed an initial abstraction)is representationally complete since we’ve identified all possibletransitions between each pair of adjacent clusters and all possibleways to traverse each cluster (Figure 13).

Compacting the abstract graph

An interesting observation made during the abstraction-buildingprocess was that on many maps the same path was often returned by AA*when searching between the same pair of points with different sizes andcapability parameters. This indicates that our abstract graph actuallycontains unnecessary or duplicated information (and is also needlesslylarge as a result). To solve this problem we’re going to apply two edgedominance approaches to prune unnecessary nodes an edges. I want toavoid describing these ideas formally (the details are in [1]) and instead focus on the intuition behind each one.

The first, termed strong dominance, states that if two edges, bothof identical length, connect the same pair of nodes and both aretraversable by the same capability then we need only retain the onewith the largest clearance. Figure 14 illustrates this idea. It is easyto see that using this approach preserves representationalcompleteness; any agent able to traverse the edge with smallerclearance is also able to traverse the one with larger clearance. Theresultant graph is termed a high-quality abstraction because we discard only duplicate information fromt the graph.

Figure 14: (a) Part of the initial abstraction for clusterC1. (b) Strong dominance removes edges E5 (dominated by E3) and E6(dominated by E4).

Figure 15. (a) A graph with two inter-edges, E2 and E5. Anagent traveling from "u" to "x" via E2 must both swim and walk whereastraveling via E5 only requires walking. (b) The dominated inter-edge,E2, and its endpoints, are removed.


The second approach, termed weak dominance, is focused on minimisingthe number of transitions between clusters. To achieve this thealgorithm analyses pairs of inter-edges that connect the same twoclusters and attempts to prove that if one is removed therepresentational completeness of the graph is maintained. The effect isthat only transitions which are traversable by the largest number ofagents are retained. This is similar to the way motorists frequentlyprefer to travel between locations via freeways, which are traversableby many kinds of vehicles, instead of opting for more direct offroadtravel. Figure 15 illustrates this idea; again, it is easy to see thatthe application of weak dominance also preserves representationalcompleteness. The resultant graph is termed a low-quality abstraction,to reflect the fact that some connectivity information is lost in theprocess (Figure 16).

Figure 16: The abstract graph after weak dominance is applied. Note that the graph is almost half the size compared to Figure 13.

Choosing which dominance technique to use will depend on the exactrequirements of the target application. Empirical results have shownthat in both cases the amount of memory required to store the abstractgraph can be a small fraction of that required by the original map.(though the exact number depends on a range of factors which arediscussed in [1]).Comparatively speaking, low quality abstractions can be more than 50%smaller than their high quality counterparts but there is a smalltradeoff. In particular, high quality abstractions produce, on average,paths with lengths 3-5% longer than optimal while low qualityabstractions are in the 6-10% range.

Hierarchical Annotated A*

The process of finding a path using an abstract graph is astraightforward one that will be familiar to anyone who has come acrossthe HPA* algorithm [5]:

  1. Insert two temporary nodes into the abstract graph to represent thestart and goal locations. Connect these nodes to the rest of the graphby attempting to find a path to from the start/goal positions to everytransition point in the local cluster.

  2. Using A*, find a shortest path from the start to the goal in theabstract graph. At the end of the search, remove the two temporarynodes.

As with Annotated A*, the search algorithm from Step 2 is modifiedslightly to accept two extra parameters: the agent’s size andcapability. In addition, the search function is also also augmented sothat before a node is added to A*’s open list we first verify that itis infact reachable. In this case, a node is reachable only if the edgeconnecting it to the current node is traversable for the given size andcapability parameters. The resultant algorithm is termed HierarchicalAnnotated A* (HAA* for short).

As with other hierarchical planners, HAA* is shown to be very fast.I analysed its performance on a large set of problems (over 140K) usingboth small and large maps from Bioware’s popular RPG Baldur’s Gate.Since there are no similar pathfinding algorithms to measure against,it was contrasted with Annotated A*. In short, HAA* is an order ofmagnitude faster and, even with my naive, non-optimised implementation,it was able to find solutions to most problems in ~6ms on average(tested on my Core2 Duo 2.16GHz MacBook, running OSX 10.5.2 with 2GB ofmemory).

If you’d like to play with a working implementation of HAA*, you can download the source code I wrote to evaluate the algorithm. The classes most relevant to the preceeding few sections are probably AnnotatedCluster and AnnotatedClusterAbstraction which together are responsible for generating the abstract graph. Meanwhile, AnnotatedHierarchicalAStar provides a reference implementation of the HAA* algorithm.

原创粉丝点击