|Terrain Analysis in Realtime Strategy Games
Dave C. Pottinger
Technical Director, Ensemble Studios
What is Terrain Analysis?
Aside from being a neat buzzword in the game industry, terrain analysis is probably in every realtime strategy (RTS) game, whether you know it or not. Terrain analysis can exist in many forms from simple pathfinding to advanced area decomposition. Whatever method is employed, it has the single goal of supplying information about the map to various systems in the game. Typically, the terrain analysis will abstract information about the map into easily digestible chunks of data that other game systems can use to make decisions. Though this paper will focus on the application of terrain analysis in RTS games, several terrain analysis concepts can be applied to other genres of games to improve their AI.
Terrain Analysis Uses
Terrain analysis can be utilized by several systems in an RTS game.
The Computer Player AI (CP AI) is the biggest customer of terrain analysis. The CP AI needs to be able to “look” at the map and make decisions about where to build buildings and walls, where to attack an enemy from, where it can expect an enemy attack to come from, and so on. Good terrain analysis also provides a framework for a location-based knowledge base in the CP AI. A location-based knowledge base simplifies many of the CP AI coding tasks (via a simpler abstraction) and allows the CP AI to push the envelope in terms of features and quality.
Pathfinding is something that every RTS game needs to have. As RTS games evolve and become more sophisticated, the simple one-size-fits all pathfinding solutions that worked a couple of years ago aren’t sufficient anymore. Terrain analysis is a great tool to use to generate the data that a high level pathfinder uses to find coarse paths to move units across an entire map.
Random map generation is still a reasonably difficult thing to do in the RTS domain. Few games have done it well, and even fewer have used formal terrain analysis to improve the quality of the random maps that are generated. However using a simple concept like area size balancing is an easy way to help create balanced random maps.
Several high profile recent games (Starcraft, C&C2: Tiberian Sun, Age of Empires 2: The Age of Kings) have used employed the extensive use of triggers to create a more immersive and interesting single player experience. “Bring object to area” is a commonly used trigger in many scenarios in all three of those games. Dynamic terrain analysis could be employed to allow that area to be moved around or have its shape altered during runtime to create more unique uses of that trigger.
Terrain Analysis Tools: Definitions
Developing a sophisticated terrain analysis system is a lot like developing a good image processing toolbox (as you may notice terrain analysis and image processing share a lot more than that simple analogy). Let’s start with some quick definitions:
Tile-based map. A 2D heightfield map with varying heights in the upward direction. For consistency, we’ll use a 3D coordinate system and say a tile-based map exists in the XZ plane, with the Y direction being up. To date, most terrain-based RTS games typically use a heightfield map for both simulation and graphics (see Figure 2).
Tile. A single cell in a tile-based map.
Arbitrary poly map. A terrain map made up of arbitrary polys. For an RTS game, this presents some larger challenges on the simulation side (compared to a tile-based map). Most often, arbitrary poly maps are the result of an optimization pass to reduce redundant/unnecessary detail or the game’s need to have something other than a single layer heightfield.
Area. A collection of terrain (either in a tile or arbitrary poly map) that shares similar properties (e.g. passability or slope).
Area connectivity. The concept of knowing how areas are connected and being able to traverse that connection network.
Terrain Analysis Tools: Pathfinding
The simplest and most brute force approach to terrain analysis is pathfinding. That may seem a little odd to some, but pathfinding is actually a valid way to do terrain analysis, particularly when employed by the CP AI “canPath” checks (determining if a given unit can find a route to a particular spot on the map).
Terrain analysis by pathfinding suffers from some fairly obvious problems in terms of execution speed and quality of the pathfinding algorithm. Pathfinding is one of the slowest things most RTS games do (e.g. Age of Empires 2 spends roughly 60 to 70% of simulation time doing pathfinding). When pathfinding is relied upon to determine area connectivity, the speed concerns usually force some changes to the algorithm. Those changes usually work against the pathfinding’s need to work well on short, heavily obstructed paths (e.g. the original Age of Empires suffered fairly notably from this problem). Despite those disadvantages, using pathfinding to do dynamic CP AI canPath checks means that the result is always accurate to what the game will actually use. If area connectivity and canPath checks are done with some other method, you can run the risk of getting the area data out of sync (either in data or something such as distance measurement).
Terrain Analysis Tools: Influence Maps
Influence mapping is a common terrain analysis tool. Influence maps are 2D arrays that represent some area of the terrain. The influence map is initialized to an initial value and then attracting and detracting influences are applied to the map based on some game-specific heuristics. A quick example would be a gather site placement. The influence map would “solve” the case of determining whether to place the gather site by a single resource or a group of the same resources because the group would have attracted the gather site to it by a repeated attractor operation on the same area in the influence map (thus raising that area’s value). After the influencing was complete, the gather site placement would look at the map and find the most attractive area to place the site.
Influence maps work well on 2D maps and can be abstracted into 3D influence volumes. Influence maps are still a fairly brute-force approach, though, and can end up being fairly slow as a result. Influence maps are also subject to heuristic overload if too many attracting and detracting influences are used. Imagine a case where an attractor ups the value of a cell in the map and then a detractor knocks it right back down to its original value. In one sense, that’s what you’d like to happen because the tile is both good and bad, but you also lose the fact that it’s good and bad because it looks like any other tile that hasn’t been attracted or detracted at all. Sometimes this is okay, but there are times when it’s not. There are a variety of ways to work around this, but the best is to keep the number of influences during any one influence mapping operation down to a fairly low number.
Terrain Analysis Tools: Areas
Area decomposition is a newer component of the terrain analysis toolbox (at least as far as RTS games go). When humans look at an RTS map, it’s very natural to break that down into areas such as “My Town”, “Good spot to put walls”, “Good spot to put a tower”, etc. CP AIs would really like to have that ability as well. Areas are the way to do it. When a map is fully processed into areas, the CP AI can assign units to a given area for logical lookup later as part of a location-based knowledge base. The CP AI can also track how valuable an area is based on the number of resources in it or how many other areas it is connected to. In addition to mimicking human map analysis, areas are excellent at abstracting large areas of the map into easily usable chunks.
Areas can be difficult to keep updated in a game with dynamic terrain. But, with intelligent notifications and good code to split and merge areas, this problem can be mitigated quite a bit. With the addition of connectivity, the area system becomes a powerful way to enable quick and accurate high-level pathfinding. This is useful to simulation in general and also to the CP AIs. The CP AI can use that high level pathfinding for canPath checks and to make strategic choices about where an enemy attack route is likely to be or where to wall off all access to the CP’s town.
Case Studies and Implementation
The rest of this paper begins with a discussion of concepts and implementations used in two games, Age of Empires and Age of Empires 2: The Age of Kings. Both games were developed by Ensemble Studios and published by Microsoft. The paper will end by taking a look at the new terrain analysis systems currently in development for Ensemble Studios’ new BANG! engine.
Age of Empires Terrain Analysis
Age of Empires didn’t really use terrain analysis as an entire system, but ended up doing terrain analysis through three basic methods: Pathfinding, Zone decomposition, and Influence Maps.
The CP AI in AOE used a lot of pathfinding, most of it in the form of canPath checks. We made that choice because we needed to ensure that the CP AI didn’t assign units to do things (e.g. gather from a gold mine) at places that they couldn’t get to. This worked as a poor man’s terrain analysis because it told us when the target was unreachable due to being in a different zone or if there was a wall in the way. It did a serviceable job. Unfortunately, we had to tweak the quality/heuristics of the basic pathfinding algorithm to make it work effectively for the CP AI canPath checks. As a result, we ended up with a one-size-didn’t-quite-fit-all implementation for the pathfinding. To put it nicely, we got roasted for that.
We did have a nice system in AOE to zone up the map by terrain passability. This worked well for distinguishing islands from water and determining if there was a possible route from one island to the next. The zones were unbounded in size. As a result, an entire, all land map (save for the forests) would end up as one zone. That wasn’t particularly useful. We could also brute force the calculation of distance between zones. This was useful in eliminating some canPath calls that could never succeed (e.g. an archer with a range of 10 trying to attack a target in a different zone that was at least 11 tiles away from the archer’s current zone).
Used as terrain analysis (not its original use), the zone system in Age of Empires suffered from two problems: the unbounded size of the zones and the fact that obstructions were not taken into account. This “lost” most of the useful tactical distinctions between different locations on the map. It was also impossible to differentiate between two sides of the cliff. While we didn’t have these features, the zone system did end up helping performance out quite a bit.
The rest of the terrain analysis that took place in AOE consisted of influence mapping. The influence maps that we used were single layer maps using a bounded byte of data for each cell in the map. The map was memset to some initial value (depending on the use) and then we ran through a dynamically generated set of attractors and detractors (again depending on the use). If we were placing a storage pit to gather gold from, we attracted to gold with a one tile impassable buffer around the gold to help the pathfinding out a bit (Figure 3 shows the same operation, but in the BANG! 3D engine). We also detracted from other buildings to help maximize the CP AI’s visibility coverage. If we were placing a house, we attracted to other houses and research only buildings but didn’t detract from any other buildings since we wanted the houses closer to the center of the town.
The influence mapping system was also used to find group staging points for idle CP troops by attracting to high ground and detracting from all buildings. The most exciting use of influence maps in AOE was to layer them into the pathfinding calculation for the CP’s canPath checks prior to attacks. On higher difficulty levels, we could precalculate an influence map that detracted from previous attack routes and all known enemy buildings in a region. The canPath check would then try to get the units to the target without walking through those detracted areas. This gave us the ability to have the CP units attack from multiple angles without a lot of extra work.
Age of Empires 2: The Age of Kings Terrain Analysis
The goal for AOE2 was to reuse all of the terrain analysis functionality from AOE1. Aside from the pathfinding issues, we were all fairly happy with the way the AOE1 CP played from a tactical standpoint. If you gave the CP some units, he generally did something reasonable with them. However, as a result of a lot of the other features we added to AOE2 (e.g. formations) and the general project slippage, we ended up changing the terrain analysis more than we anticipated.
AOE2 shipped with three distinctly different pathing algorithms. We specifically added a mip-mapped pathfinder to address the problem our units had finding good paths across long distances. We solved this problem by generating successively zoomed out mip-maps of the terrain (including obstructions) with the criteria of subdivision being passability across that mip level. These are kept updated on the fly via a combination of notifications (e.g. when a building is built, it modifies the entire chain that it affects). The other two pathfinders are a short distance polygonal pathfinder and an extremely simple short/medium distance tile-based pathfinder. The polygonal pathfinder dynamically generates convex hulls inside a region and works very well for moving units through any tight situation. Having both the mip-map and polygonal pathfinder allowed us to streamline the tile-based pathfinder from AOE1. Together, all three of the pathfinders gave us a huge win in terms of quality and speed for all of the units.
But, perhaps the biggest benefit was that we could now tailor the CP AI canPath checks to use the appropriate algorithm for a given situation. If we wanted to path a unit across the map, we checked the mip-map pathfinder and could assume that the polygonal pathfinder would solve the problem when the unit got close. As a result, almost all of the CP AI tactical code had to be touched to take advantage of this. But, in the end, the CP AI became much faster (and thus smarter) even though we didn’t fundamentally change the way we used pathfinding to do terrain analysis.
One completely new terrain analysis feature for AOE2 was the CP wall placement. For that, we went back to our old friend pathfinding and used the mip-map pathfinding to generate wall endpoints between land impassabilities. The system for determining the land impassabilities was fairly hardcoded to look for obstructions a certain distance from the CP’s town, but it was more than serviceable as we finally had wall building CPs.
BANG! Terrain Analysis
BANG! is a full 3D engine, but should the terrain be 2D or 3D? That’s a question that reaches much farther than terrain analysis, but that choice can potentially affect how the terrain analysis works. Some of the larger questions to answer are:
Is the terrain used in simulation inherently tile-based? Tile-based simulation does afford some nice quick lookups, but tiles take up a lot of memory.
Do simulation and graphics share the same terrain? If so, then there will be restrictions from both simulation and graphics that limit each other. If the simulation needs to be tile-based and shares terrain data with the graphics, then the graphics system will have a much tougher time doing dynamic LOD or an arbitrary poly terrain system without eventually duplicating data.
What about those flying units? If the game supports flying units, does that automatically mean taking each of these algorithms to 3D? Do all of the areas have to become volumes? Is the two layer approach good enough? Are areas even meaningful if flying units can fly over all of them?
Any given answer to any of those questions isn’t wrong if it’s made in the context of choosing the appropriate tradeoffs for your game design. That doesn’t mean that the decisions can be taken lightly, though:). For BANG!, we’ve chosen to use a tile-based terrain even though the graphics are 3D. This means that a “tile” is really a quad made up of two triangles.
BANG! Terrain Analysis: Influence Maps
Influence mapping still plays a part in any terrain analysis. It’s a simple algorithm that everyone quickly understands and can apply. Given its tile/cell basis, though, it can eat a lot of memory. If there are only a few factors with a small dynamic range, you can save some space by implementing a bit storage mechanism where multiple tiles are bit shifted into the same space that one tile used to take. Practically, most single layer uses will want at least 16 levels of range, so you can only pack two cells into a BYTE. Nevertheless, halving your influence map memory usage is still useful. As the size of the range is decreased, though, the risk of heuristic overload increases.
One new thing BANG! does with influence maps is to go beyond the traditional, single layer influence maps. Multiple layer influence maps can save a lot of memory (at the cost of computation speed). Continuing to use a BYTE as a reasonable minimum cell size, we can use 8 layers of influence. Each “on” bit can be multiplied by a layer factor to create different weights for each layer. Multiplied by their respective weights, all eight layers create an aggregate value. Two cells can have the same aggregate value, but comparing how that value was obtained becomes simply comparing bits in each value. Assuming you know what each layer’s influence comes from, it’s easy to determine any pertinent differences between the two similar, aggregate values.
Saving memory is a very useful thing with influence maps. If enough memory is saved, you could consider keeping a persistent influence map in the terrain. As resources were consumed, you would remove their influence. As buildings were built, they would add influence (depending on what was tracked). This reduces the costly CPU usage of recreating the influence maps each time they are needed.
BANG! Terrain Analysis: Tile Areas
For its RTS terrain, BANG! uses a tile-based solution. As such, it makes sense to have some area decomposition system that maps one tile to one area. Extending that philosophy, we end up with any point in the terrain being in one and only one area. This allows unambiguous lookups such as “Which area is this unit in?” to be done. The CP AI can then store that area identifier off for use in the expert system or track statistics associated with the area in its knowledge base. Those statistics range from simply asking how many units are in a given area to sophisticated evaluations such as how much offensive power is in a specific area. It is possible to ask these same questions with overlapping areas, but it’s considerably harder to push that data up to something like the expert system that controls the CP behavior.
BANG! tile areas are nonconvex by nature. The areas are delineated by actual terrain passability (e.g. villagers cannot walk on lava), the slope of the terrain (e.g. villagers cannot walk up more than a 50 slope), and any additional logical area distinction (e.g. anything within 50 meters of a player’s starting position is part of that player’s town). Together all of these conditions make up the area creation conditions. Depending on the game’s particular need, different sets of areas can be generated for different creation condition sets (e.g. land vs. air units) or the area sets can carry on/off bits for passability by a given unit type (e.g. land and sea units can share the same areas, but land units cannot walk on water and sea units cannot sail on land).
BANG! Terrain Analysis: Tile Area Subareas
Just before the game starts, the entire map is processed. The initial goal is to break the map up into simple, roughly convex tile areas. These are the tile subareas. Once every tile is assigned to a subarea, the subareas are processed to create the larger areas. This process allows us to be accurate, but ignore inconsequential areas such as a small lake in the middle of a player’s town. The areas are subject to game specific constraints (e.g. each player’s town should be 250 meters in usable surface area). While not immediately obvious, the subarea process gives us a couple of very useful advantages:
Consistent generation criteria. Subareas are roughly convex and areas are made up of subareas. Assuming we bound the subareas to a reasonable, consistent size, this allows us to just change the area criteria (in case 250 meters really needs to be 400 meters) without changing our low level processing. It’s much easier to do a greedy grab on subareas until some area goal is met than to continually tweak the low level decomposition heuristics.
We actually need subarea accuracy. A twisty forest passage may be a hundred meters long, but if it’s made up of five subareas, then we already have our several usable wall endpoints determined for us. We can simply take the subarea boundaries and use those as wall locations to block that passage. Conveniently, that paradigm extends to every situation all the way to an all-grass map that’s decomposed into small subareas; walling off in that type of situation can still be accomplished by the same method as the twisty forest map.
BANG! Terrain Analysis: Tile Area Generation
Let’s talk a little bit about how the tile areas are actually generated. A decent approach is to use a stack-based flood fill (recursive function flood filling is too slow and will inevitably overrun your execution stack) with an area bound. This actually works fairly well, except that using a traditional stack tends to generate long, thin subareas. A quick solution to this is to use a stack, but to pull new cells from the bottom of the stack instead of from the top. This simple trick creates areas that grow from the initial point rather than from the along the direction of the top of the stack.
The subareas are stored with a simple span list approach. Currently, we create the spans during another pass on the terrain after every tile is flood filled, but it wouldn’t be hard to optimize the spans to be created during the flood fill. Arbitrarily choosing the X direction as the span direction, for every Z row, we track the set of contiguous X spans on that row (since there can be more than one span on any row). For each X span, we track the starting point and the number of tiles. Another indexing system is in calculated after the span creation to track the starting index into the span array for each Z row. This speeds up the point containment lookups quite a bit.
One problem with just relying on flood filling, though, is that is creates a massive amount of unrelated data. Once we’ve started filling, there aren’t any good higher level heuristics to use to make more informed decisions about how to direct the fills to create more useful areas. To do that, we actually have to jump backward and insert a step at the start of the process where we break the map down into more logical pieces before we throw the brute force approach at it.
This starting step is usually fairly game specific. To take a specific example, the AOE2 random map generator pretty much always places players in a rough circle closer to the edges of the map than not. Immediately, that creates a rough decomposition of eight pie pieces. Coupled with a Mediterranean AOE2 map (land on the outside, a circular lake in the middle), we can immediately create simple, axis-aligned boundaries to help guide the fills. Another good tactic to employ is to mip-map the game map (ensuring that critical passability is maintained) to create a smaller map. That map can then be decomposed with the flood fills to create area boundaries to use in the real flood fill. Convex areas (covered later) also afford us some simple area boundary information.
Jumping back to the point after we’ve done the tile subarea decomposition of the map. We will inevitably have created some areas that really need to be further decomposed. A good measure of when this needs to happen is to take the area of the bounding box of subarea. If that exceeds the actual area of tiles contained in the area by some threshold, the area probably needs to be further decomposed. A simple method (that ends up working surprisingly well) is to process the subarea in both the X and Z directions. The minimum span in each direction is tracked. If there is a thin span in the area, we can drop that span out and recalculate the bounding vs. actual area ratio. If that’s an improvement, we can then assign the dropped out tiles to one of the areas and move on (repeating as necessary). Some things to be aware of with this algorithm:
It’s generally better to split the areas somewhere in the middle, so preference should be given to thin spans that are closer to the center of an area.
Diagonally oriented areas will get decomposed when they shouldn’t be. One solution is to look at the bounding vs. actual area ratios of both new areas compared to the original area. If they’re not sufficiently different, then it was probably a diagonal area. Convex areas can also help here.
If there are two disjoint spans on the same row, that’s usually a good place to split the subarea if the spans are roughly the same size. If the two spans aren’t the same size, split at the smallest one and “move” the other split perpendicularly to find a smaller disjoint span.
Now that we have the map completely decomposed into subareas, we can go through and do a simple greedy process to create the actual areas. Good places to start the search are player starting positions and chokepoints (see chokepoints under Area Connectivity). At this point, we can apply heuristics such as the player town size and minimum area sizes.
BANG! Terrain Analysis: Tile Area Maintenance
So, with our map completely decomposed into nicely defined areas, we’re all set until something changes the map. At that point, we need to dynamically analyze the change(s) and alter the areas accordingly. The basic process for this is pretty straightforward:
Using the knowledge of what the change is (e.g. an earthquake creates an impassable seam in the terrain of a certain size), we rip through the area system and remove all of the tiles that could possibly be affected.
The full subarea decomposition pass is run on the removed tiles. If possible, outside information about the surrounding areas and the terrain change are used (e.g. the line of impassability the earthquake creates is a good area boundary). Time slicing the terrain analysis comes in very handy here in case this is a slow process.
Once those subareas are created, the greedy algorithm is run starting with the existing areas that bound the affected area. This will tend to push the subareas into existing areas. Generally, this is a good thing unless the earthquake stretches across the entire map.
All systems that have referenced the areas and subareas that were removed or altered get notifications to reset their data. This is much easier if the areas keep reference counts and identifiers to be able to directly notify the systems in question.
BANG! Terrain Analysis: Convex Areas
Convex areas are inherently closer to general 3D than tile areas. They can store the same data with much less space and can get pretty close to tile area speed for some of the logical operations. Convex areas are much simpler to divide and merge than tile areas. Convex area logic and code is also more easily converted to convex volumes. However, convex areas can be slower to find and generate than tile areas. There are also some logistical problems given the definition of convex hulls.
Convex areas generated by BANG! terrain analysis are defined by the same area creation criteria as tile areas. However, due the nature of convex polygonal areas, the area bounded by a convex area will often contain terrain that isn’t the same as the terrain that defines the actual area. Thus, we can end up with an effectively infinite hierarchical storage system. If each convex area needs to be fully decomposed, we have to break the top area into smaller convex areas of the same passability or other convex subareas that are then decomposed themselves. This is actually another nod to doing the tile areas for the CP AI since you can then avoid this muck because the other game systems (e.g. pathfinding) don’t need it.
To actually create the convex areas, we don’t have much choice but to process the map to pull out the appropriate terrain data. This can be done by a flood fill (like the tile areas) or some other mechanism. Once the connected terrain points are generated, we have a variety of methods available to actually generate the convex hull for the area (e.g. package wrapping or Graham scan). However, unless some proprietary knowledge of how the points are structured is used, it’s unlikely that the hulling process will be very fast. A convenient side effect of having tile-based terrain is that we can use the knowledge of how the map is organized to dramatically reduce the number of points to consider for the hull.
So, if the CP AI doesn’t use convex areas, what do we use them for? Convex areas are great for the high-level boundary determination that we use to guide the tile areas. Convex hulls wrapped around tile areas are much better at determining area characteristics such as a closer surface area approximation, (to help detect/solve the diagonal area splitting situation), area orientation and direction.
Convex areas are also better at determining chokepoints than tile areas. If we have two forest convex areas and we want to find the chokepoint between them, there are two simple cases:
If the hulls don’t overlap, the chokepoint is the midpoint of the shortest line between the two hulls.
If the hulls overlap (and there is a passable route between them), the chokepoint is inside the polygon created by the overlap. Several methods can create a line of potential chokepoints. Picking one is simply a matter of finding a point on that line that is of the passable terrain type.
Convex hulls (with area connectivity) are also excellent for high-level pathfinding. The pathfinding simply avoids all convex areas that it’s either not starting in or not trying to enter into. This works well for creating a small set of waypoints to help a unit navigate across an entire map.
BANG! Terrain Analysis: Nonconvex Areas
Nonconvex areas are really a combination of tile areas and convex areas. Nonconvex areas share some of the ease of area description with convex areas, but don’t have the overlapping problem that convex areas have. As a result, nonconvex areas typically have a lot more edges to their hulls than convex areas; this does detract some from their utility, but it’s still usually less data to manipulate than tile areas.
Nonconvex areas can be very useful during random map generation. If the random map generator creates nonconvex areas as it generates terrain and those areas have the ability to maintain surface area when “pushed”, it can significantly cut down on the iterations required to make balanced maps. As player A’s island starts to get too close to player B’s island, player B’s island can just be pushed away to create the necessary room. Clearly this requires a complicated architecture just to do this and to also prevent the circular pushing problem. But, if implemented, it is a big win for random map generation.
BANG! Terrain Analysis: Area Connectivity
The last major point to cover with areas is connectivity. This may seem obvious, but it’s worthy of a little examination to see some of the properties that fall out of area connectivity.
Area connectivity is maintained simply by having an area track which areas bound it and what the separators are. For our purposes, separators are a line that is both the boundary and connection link between areas. Each separator bounds two and only two areas. The two area restriction fits the property of a line and also allows for easy consumption by the CP AI knowledge base abstraction. For convex areas, each separator is just one or more segments of the convex hull. For tile and nonconvex areas, the same property applies, but many more segments are needed to make the separators. As an optimization, the tile area separators can be created during the pass that creates the spans.
Once we have an area separator network established, several options open up for the CP AI. CanPath checks become simple pathfinding traversals of the area network (whose results could be passed through the command system to the units to cut down on their redo of the pathfinding effort). Chokepoint determination can be augmented adding areas with a lot of separators as chokepoints. The CP knowledge base is able to track routes between areas, including which route(s) enemies are using to enter the player’s town, etc. When we carry the connectivity paradigm down to the tile subareas, we get the ability for the CP AI to track units at a lower level with the same system. This is particularly helpful if the expert system controlling the CP AI can reference and iterate over areas since it can tell the difference between enemy units in its town vs. enemy units threatening its gold gatherers. A simple, but huge benefit is to also just reuse those separators as our subarea wall points.
With convex areas, we also usually see a speedup in calculating when a unit crosses into a new area. We can simply check for intersections with the separators in his current area that he’s likely to cross given his current orientation. When that intersection happens, we immediately know which area he’s in.
Terrain analysis doesn’t need to be exact. If you try to make it perfect, you’ll either end up spending a lot of time tweaking heuristics or you’ll have a lot of extra areas that really don’t buy you anything.
Abstract the area representation (tile vs. polygonal) away from the users (e.g. the CP AI) as much as possible. This will allow you to change it to fix bugs or upgrade as needed.
Build it to support dynamic terrain. Even if you don’t have dynamic terrain in your shipping game, this helps debugging and testing.
Write all of the processing so that it is time-sliced. Even if you don’t use it right away, someone will inevitably code (or ask you to code) a feature that blows out your carefully constructed time budgets. If you have time slicing built into the system from the start, that’s not a problem. This also lets you run the terrain analysis during the game much more easily and effectively.
Build area specification tools into the scenario editor. Use these to simplify the processing. There’s no reason why a scenario author can’t put hints for the terrain analysis into the scenario. This also lets the scenario author tweak how the CP AI thinks about the map.
Since the random map generator already has to manage areas and connectivity to generate a decent map, it should just pass that data to the terrain analysis. If the random map also has a general shape (e.g. AOE2’s Mediterranean map), that information can also simplify the terrain analysis’ task.
Don’t use tiles as a measure of distance. Be trendy and use meters as the unit of measure so that you can change the tile size without having to rebalance your game data and your AI heuristics.
Pattern recognition is a hit or miss proposition. If scenario authors do a little work and know the basic properties of the game’s random maps are known, real pattern recognition may not be needed to do effective terrain analysis.
If real pattern recognition is needed, though, a couple of easy options present themselves. Since the tile subareas have too much data and convex areas have unknown holes inside the areas, the tile subareas could be hulled used instead. The data reduction would make recognition easier and the smaller areas would tend to have fewer holes. Running pattern matching on the mip-mapped version of the map is also another option.
Ensemble Studios’ programmers Paul Bettner, Doug Brucks, Tim Deen, John Evanson, Rob Fermier, Mario Grimani, Angelo Laudon, David Lewis, Herb Marselas, Matt Pritchard, Trey Taylor, Mark Terrano, and Michael Teter for going through a lot of discussions and dissections (and even a few heated debates here and there:) with me about how this should all work.
Caudill, Maureen and Charles Butler. Naturally Intelligent Systems. MIT Press. Cambridge, Massachusetts. 1990.
Gonzalez, Rafael C. and Richard E. Woods. Digital Image Processing. Addison-Wesley Publishing Company. Reading, Massachusetts. 1993.
Sedgewick, Robert. Algorithms in C++. Addison-Wesley Publishing Company. Reading, Massachusetts. 1992.
Woodcock, Steven. The Game AI Page. http://www.gameai.com/ai.html.