| |
|
|
||||
![]() |
||||||
| |
|
|||||
|
GDC 2002: Polygon Soup for the Programmer's Soul: 3D Pathfinding Anatomy of a Sector class
CPathfindSector As you can
see, the sector is really just a spatial portal linkage; most of the interesting
data is contained in the portal. class
CPathfindPortal As you can see all the connection information is stored in the portal and is therefore the "key" to solving a path. Solving the Path Luckily for Bob, we can use his (X,Y,Z) location to lookup the pathfind sector he's washing socks in. This sector contains a list of portals he can use to get to other sectors, which contain their own portal lists, which can be used to get to yet more sectors, and so on and so forth. At this point any number of best-path algorithms can be applied to get Bob to the UN building. We found a modified A-star algorithm solves the problem nicely. A simple implementation would use the accumulated distance between portals as the traversal cost, and the straight-line distance to the goal as the heuristic cost. Now pretend that Bob and twenty of his closest buddies need to get to the UN building at the same time. Twenty different requests for complex paths can well exceed the amount of CPU your game devotes to AI each frame. Luckily for us, it is not very noticeable if we distribute the processing of these paths over a few frames. For example, if Bob sits and thinks for a half second before getting up and walking out the door, is anyone likely to notice? On the flip side, a half a second (500 milliseconds, ~1 billion clock cycles) is more then sufficient for a pathfinding system to solve a few simultaneous paths. To distribute path solves over multiple frames you could use an algorithm like the one outlined in the following pseudo-code. while
(Time_Has_Not_Elapsed () && CurrentPathSolver != NULL) This is a simple time slice manager which allows the current path to process a little bit each frame. When the path is solved, a new path is processed until either it finishes or time has elapsed. To distribute the path solve itself over multiple frames, consider the following pseudo-code. CPathSolver::Process
(float time) if
(sector == NULL) This algorithm will process as many sectors as necessary until its time-slice has elapsed. Loosen Up Dude!
Avoiding Robotic Paths To make our path appear a little more natural we'd like to use splines. In layman's terms, splines are basically curved lines that follow a set of points. Different types of splines follow their points in different ways. Some splines pass through their control points, whereas other splines act like magnets and are either attracted or repulsed by their control points. To see the advantage of splining the path, consider the following diagram.
Looks great, right? Unfortunately, there is a problem. Since the spline doesn't know anything about the sectors and portals that define the "safe" area for a unit to walk, it is likely that a curve on the spline will leave these volumes causing the unit to walk into desk corners, doorways, trash cans, or even meander off the edge of a cliff! Luckily we can take advantage of a mathematical property of Bezier curves (a type of spline): if the control points of the Bezier curve lie inside a volume, then the curve itself will lie inside the volume. A Bezier curve is a cubic spline defined by a start point, an end point and a series of control points. The control points act like magnets to "pull" the curve away from the line segment defined by the start and end points. Given this, our organic post process algorithm would function as follows: Build a Bezier curve from the points on the final path. Build a list of the sectors and portals that the AI will pass through on its path. For each control point on the Bezier curve, clip it to the sector volumes. To clip a control point, form a line from the control point to the corresponding point on the un-splined path. Test this line segment to see if it passes through the side of any of the sector boxes in the list. If it does, check to see if the area of intersection is a portal. If the point intersects a sector wall, and it does not pass through a portal, then clip the control point to the sector wall; otherwise leave the point alone - it is valid.
This algorithm will allow the AI to follow a nicely curved path without ever leaving the safe pathfind sectors. Using Innate Waypaths Innate waypaths are another powerful solution that integrates well with our pathfind system. A waypath is a manually created series of waypoints which form a path. This waypath can be rigid or splined. Each waypoint on the waypath can encode specific information, such as crouch here, speed up, slow down, or even jump to the next waypoint. To integrate this information into our path solver, consider the following algorithm. Run a normal pathfind flood fill to generate sectors and portals. For each innate waypath, create a "dummy" sector (a sector without size or position), and add it to the system. For every waypoint in the waypath, find which pathfind sector the waypoint intersects. Create a two-way portal from the pathfind sector to the dummy waypath sector at the location of the waypoint. Add this new portal to both the pathfind sector and the dummy waypath sector. During the run-time path solve, the algorithm's heuristic should bias toward these waypath sectors (i.e. multiply the cost of using a waypath sector by 0.75). This will cause AIs to "tend" to follow innate waypaths. Given this system, to enable vehicle AIs to drive along the right side of the street, a level designer would simply draw a one-way, vehicle only, innate waypath along each side of the road.
Follow the Leader There are many different ways to approach this problem, so let's choose the simplest. We know where the player jumped from and we know where the player landed. If both points are inside the pathfind data, why not add a temporary one-way "jump" portal between these two sectors? All we need to do is encode a little information about the jump such as orientation, velocity, and time. Depending on the physics system, this may be enough for the AI to replicate the player's mighty leap. We can even keep a FIFO "bucket" of these temporary portals so other AIs can follow.
|
||||||||||||||||||||||||||||||||||||||||||||
|
|