Aerial Combat in Video Games: A.K.A Dog Fighting

September 27th, 2011 by John Grden

A while back, we produced a Star Wars title for Lucas Film LTD. called “The Trench Run” which did very well on iPhone/iPod sales and later was converted to a web game hosted on StarWars.com.  Thanks to Unity3D’s ability to allow developers to create with one IDE while supporting multiple platforms, we were able to produce these 2 versions seamlessly!  Not only that, but this was one of our first releases that included the now famous Brass Monkey™ technology, which allows you to control the game experience of The Trench Run on StarWars.com with your iPhone/Android device as a remote control.  [Click here to see the video on youtube]

Now, the reason for this article is to make good on a promise I made while speaking at Unite2009 in San Francisco.  I’d said I would go over *how* we did the dog fighting scene in The Trench Run, and I have yet to do so.  So, without further delay…

Problem

The problems surrounding this issue are a few fold:

  1. How do you get the enemy to swarm “around you”?
  2. How do you get the enemy to attack?
  3. What factors into convincing AI?

When faced with a dog fight challenge for the first time, the first question you might have is how do you control the enemy to keep them flying around you (engage you), thus one of the most important ones is how to achieve the dog fight AI and playability.  The issue was more than just simple mechanics of how to deal with dog fighting, it also included issues with having an “endless” scene, performance issues on an iDevice and seamlessly introducing waves of enemies without interrupting game flow and performance.

Solution

In debug mode - way point locations shown as spheres

The solution I came up with, was to use what I would call “way points”.  Way points are just another term for GameObjects in 3D space.  I create around 10-15 or so, randomly place them within a spherical area around the player’s ship and anchor them to the player’s ship so that they’re always relatively placed around the player ( but don’t rotate with the player – position only ).  I use GameObjects and parent them to the a GameObject that follows the player, and this solves my issue of having vectors always positioned relative to the player.  The enemies each get a group of 5 way points and continually fly between them.  This solves the issue of keeping the enemies engaged with the player no matter where they fly and allows the enemy the opportunity to get a “lock” on the player to engage.   Since the way points move with the player’s position, this also creates interesting flight patterns and behavior for attacking craft, and now we’ve officially started solving our AI problem.

Check out the Demo.  Get the files

Check out the demo – the camera changes to the next enemy that gets a target lock on the player ship (orange exhaust).  Green light means it has a firing lock, red means it has a lock to follow the player.

Download the project files and follow along.

Setting up the Enemy Manager

The Enemy manager takes care of creating the original way points and providing an api that allows any object to request a range of way points.   Its functionality is basic and to the point in this area.  But it also takes care of creating the waves of enemies and keeping track of how many are in the scene at a time (this demo does not cover that topic, I leave that to you).

First, we’ll create random way points and scatter them around.  Within a loop,  you simply use Random.insideUnitSphere to place your objects at random locations and distances from you within a sphere.  Just multiply the radius of your sphere (fieldWidth) by the value returned by insideUnitSphere, and there you go – all done.

Now, the method for handing out way points is pretty straight forward.  What we do here is give our enemy craft a random set of way points.  By doing this, we’re trying to avoid enemies having identical sets and order of way points given to each enemy.

NOTE:  You can change the scale of the GameObject that the way points are parented to and create different looking flight patterns.  In the demo files, I’ve scaled the GameController GameObject on the Y axis by setting it to 2 in the IDE.  Now, the flight patterns are more vertical and interesting, rather than flat/horizontal and somewhat boring.  Also, changing the fieldWidth to something larger will create longer flight paths and make it easier to shoot enemies.  A smaller fieldWidth means that they’ll be more evasive and drastic with their moves.  Coupled with raising the actualSensivity, you’ll see that it becomes more difficult to stay behind and get a shot on an enemy.

Setting up the enemy aircraft

The enemy needs to be able to fly one their own from way point to way point.  Once they’re in range of their target, they randomly select the next way point.   To make this look as natural as possible, we continually rotate the enemy until they’re within range of “facing” the next target and this usually looks like a nice arc/turn as if a person were flying the craft.  This is very simple to do thankfully.

First, after selecting your new target, update the rotationVector (Quaternion) property for use with the updates to rotate the ship:

Now, in the updateRotation method, we rotate the ship elegantly toward the new way point, and all you have to do is adjust “actualSensitivity” to achieve whatever aggressiveness you’re after:

As you’re flying, you’ll need to know when to change targets.  If you wait until the enemy hits the way point, it’ll likely never happen since the way point is tied to the player’s location.  So you need to set it up to see if it’s “close enough” to make the change, and you need to do this *after* you update the enemy’s position:

Enemy flying to his next way point



You can also simply change the target for an enemy on a random timer – either way would look natural.

NOTE:  Keep the speed of the player and the enemy the same unless you’re providing acceleration controls to match speeds.  Also, keep in mind, that if your actualSensitivity is low (slow turns), and your speed is fast, you will have to make the bufferDistance larger since there is an excellent chance that the enemy craft will not be able to make a tight enough turn to get to a way point, and will continue to do donuts around it.  This issue is fixed if the player is flying around, and is also remedied by using a timer to switch way point targets.    You can also add code to make the AI more convincing that would suggest that way points are switched very often if the enemy is being targeted by the player (as well as increasing the actualSensitivity to simulate someone who is panicking).

Targeting the Player

Red means target aquired : Green means target lock to fire

The next thing we need to talk about is targeting, and that’s the 2nd part of the AI.  The first part is the enemy’s flight patterns, which we solved with way points.  The other end of it is targeting the player and engaging them.  We do this by checking the angle of the enemy to the player.  If that number falls within the predefined amount, then the currentTarget of the enemy is set to the player.

The nice part about this is that, if the player decides to fly in a straight path, then eventually (very soon actually) all of the baddies will be after him and shooting at him because of the rules above.  So, the nice caveat to all of this is that it encourages the player fly evasively.  If you become lazy, you get shot 0.o

You can also change the property “actualSensitivity” at game time to reflect an easy/medium/hard/jedi selection by the player.  If they choose easy, then you set the sensitivity so that the enemy reacts more slowly to the turns.   If it’s Jedi, then he’s a lot more aggressive and the “actualSensitivity” variable would be set to have them react very quickly to target changes.

Firing

And finally, the 3rd part to the AI problem is solved by having yet another angle variable called “firingAngle”.  “firingAngle” is the angle that has to be achieved in order to fire.  While the angle for changing targets is much wider (50), the ability to fire and hit something is a much tighter angle ( >= 15 ).  So we take the “enemyAngle” and check it against “firingAngle” and if it’s less, we fire the cannons on the player.  You could also adjust the “firingAngle” to be bigger for harder levels so that the player’s ship falls into a radar lock more frequently.

In the sample, I added an ellipsoid particle emitter/particle animator/particle renderer to the enemy ship object set the references to the “leftGun / rightGun” properties and unchecked “Emit” in the inspector. Then, via the Enemy class, I simply set emit to true on both when its time to fire:

Conclusion

So, we’ve answered all 3 questions:

  1. How do you get the enemy to swarm “around you”?
  2. How do you get the enemy to attack?
  3. What factors into convincing AI?

With the way point system, you keep the enemy engaged around you and the game play will be very even and feel like a good simulation of a dog fight.  The way points keep the enemy from getting unfair angles and provide plenty of opportunity for the player to get around on the enemy and take their own shots, as well as provide flying paths that look like someone is piloting the ship.  And adjusting values like “actualSensitivity”, “fieldWidth” and “firingAngle” can give you a great variety of game play from easy to hard.  When you start to put it all together and see it in action, you’ll see plenty of room for adjustments for difficulty as well as getting the reaction and look you want out of your enemy’s AI.

Have a Bandit Day!

9 Responses to “Aerial Combat in Video Games: A.K.A Dog Fighting”

  1. New Aerial Combat Demo & Tutorial « John Grden Says:

    [...] Check out the post, files and demo over at infrared5.com [...]

  2. Paul Gregoire Says:

    John, you rock \m/
    Cool demo!

  3. John Grden Says:

    thanks Paul!

  4. Nate Chatellier Says:

    Awesome post! And very timeline with Unite11 going on. Are you here?

  5. Richard Blakely Says:

    Whoa! Sexy stuff, awesome John!

  6. John Grden Says:

    No I wish I were! Thanks Nate!

  7. John Grden Says:

    Thanks Richard!

  8. archont Says:

    This is quite a simple approach. I was hoping for something more interesting – like enemy fighters trying to attack the player from the rear, group AI to lure the player into an ambush and such.

    With Freespace 2′s code being open I’d go see that for reference – hopefully it’s readable enough.

  9. StuntCopter: Coming Soon « John Grden Says:

    [...] = 'http://wp.me/plxAT-e9'; tweetmeme_source = '”neoRiley”'; I’ve been BUSY!  Between IR5 work and my kids sports, I’ve had very little extra time to work on projects.  However, a [...]

Leave a Reply