Whilst catching up with recent discussions about game AI on the web, I stumbled on this thread about cover. Implementing good combat behaviors using cover isn’t always straightforward, but game developers often use the same tricks to solve this problem…
Screenshot: Finding and taking cover in Gears of War.
The actual behaviors are the most important part of the cover AI. If you get these right, the rest of the AI doesn’t have to be perfect as there’ll always be an appropriate fallback behavior when no cover is available nearby.
Most actors require the following behaviors:
Reacting to weapon fire by looking surprised for a short amount of time.
Assuming a intermediate position to search for cover, e.g. like dropping down on one knee.
Playing a short animation while looking for cover, and signaling the threat to team mates.
Moving swiftly but carefully into the most appropriate position,
Or alternatively, lying down on the spot for protection.
Once you have the combat behaviors work correctly without using context sensitive cover, you can start thinking about scanning the environment for places to hide.
Manually Placing Cover Points
The simplest solution to allow actors to find cover locations in the world is to manually place them while editing the level. It’s a simple workflow that requires very little technology, so it’s often the best compromise.
- Manual placement is a great way to fine tune the behaviors by placing cover locations exactly where you want them. So if you have special geometry, or need to customize the cover location per-level to fit in with a story, then manually adding cover locations to the level ideal.
- The only down side of this approach is that it requires more work by the level designers. To remedy this, you should consider attaching cover points to the object geometry (pillars, boxes, etc.), rather than for each instance in the world. Then, only add cover locations to static geometry as a fallback.
Ideally, you should start with manual cover point placement, then design your software to support multiple sources for cover spots. This will allow you to automate part of the process where possible.
If you feel confident about extending your level geometry pipeline, then terrain analysis becomes an option too. The idea is to use the structure of the world itself to find cover locations automatically. This process typically involves two steps: generating candidates and filtering out the bad ones.
1) Generate cover candidates from the geometry
To achieve the first step of generating cover candidates, you can use any of the 3D data available for each level. This includes the collision mesh (low and high detail), the navigation mesh, or even a waypoint graph.
Typically, the navmesh provides the most useful information as it models the floor of the environment very closely. Each external edge of the navmesh can be assumed to be around an obstacle of some kind, so generating cover points at fixed intervals along those edges is a very good strategy. Concave navmesh corners also provide you with information about leaning from cover, which would be very hard to determine otherwise.
Using the waypoint graph also works, but it doesn’t have as good a sense of the floor as the navmesh. The result is that the waypoints are rarely placed perfectly up against the cover locations. It’s also much harder to annotate the cover points as places where leaning is supported.
2) Filter out invalid or bad choices for cover.
The algorithm for generating cover candidates is typically very overeager, so it’s necessary to filter most of them out. To do this, you need to compute if each provides sufficient cover from any area of fire. A zone around each cover point should be scanned using line of sight (LOS) checks, either limited by a maximum radius or using the potentially visible set (PVS) in the level. If a cover location is hidden from a minimum area (customizable), then it should be saved for use at runtime as it may be useful.
Pre-processing cover locations helps greatly, but since most game situations change dynamically, there’s always some checking necessary at runtime. Typically, the cover selection algorithm takes into account:
Position and orientation of the enemies to determine the source of fire.
Accessibility of cover points, and is return fire possible.
A good place to start for cover selection is to implement a scoring mechanism for neighboring locations. You can add different heuristics to rank the cover points as necessary, and the actor will always try to pick the best.
What techniques do you use to find cover for your actors?