Skip to navigation

Aviator on the BBC Micro

Detecting alien hits

The geometry behind aliens and their weak spots

Aviator is a sophisticated flight simulator, known for its accurate and realistic physics, but it is still a game. It might feel slightly bolted-on, but if you fire your bullets while sitting on the runway, then you enable "The Theme", a game where you have to fight off wave after wave of hungry aliens, who are hell-bent on attacking the town Acornsville.

You, of course, are going to save the world... although - and I hate to break it to you - you aren't going to save the world, because the game will keep throwing wave after wave of increasingly fast-moving aliens at you, until either they reach the town, or you reach the end of the road. Still, you do have a trusty Spitfire with a gun mounted on each wing, so it's up to you to track down the invaders and do your thing.

The bullets are covered in the deep dive on adding bullets to the world, but equally important to the gunfire is the method by which the game works out whether we have hit an alien. In this deep dive, we take a look at just that.

The two stages of collision maths

We can work out whether we have hit an alien with our bullets by breaking it into two stages. Both these stages are implemented by the CheckIfAlienIsHit routine, so let's take a look at what's involved.

The first step is to calculate the alien's weak spot, which is a cube at the thicker end of the alien. To be honest, I'm not entirely sure if this is the front end or the back end, but I think it might be the front end, as this is the end where the, um, "tentacles" spring from when the alien starts to fly... though as the aliens in Aviator are simple tetrahedrons, this is all guesswork. Anyway, to hit the weak spot, aim for the blunt end rather than the sharp end.

The second step is to work out whether either of the two bullet trails pass through this weak spot at any point along the length of the bullet trail. If so, we have a hit, and that's Spitfire 1, Aliens 0.

Let's look at these two stages in turn.

The weak spot

The first part of the CheckIfAlienIsHit routine calculates the alien's feeding stage, which determines the size of the alien, and therefore the size of the weak spot. The second part then calls the GetAlienWeakSpot routine to work out the location and size of the alien's weak spot, given this information.

Take a feeding alien as an example - object 31, say. The object points for object 31 in the objectPoints table look like this:

  • Object 31: 182
  • Object 31: 183 -> 182
  • Object 31: 184 -> 182
  • Object 31: 185 -> 182
  • Object 31: 186 -> 182

So point 182 is the object's anchor point, and the object consists of points 182 to 186 (see the deep dive on 3D objects for details on how objects are stored).

Looking up these point IDs in the lineStartPointId and lineEndPointId tables gives the following lines that make up the alien object:

  • 183 to 184
  • 183 to 185
  • 183 to 186
  • 184 to 185
  • 186 to 184
  • 186 to 185

and the object points have the following coordinates within the object, as given in the (xObjectPoint, yObjectPoint, zObjectPoint) tables:

  • Point ID 182 is ( 5,  0,  5) with scale factor 2^8 = (1280,  0, 1280)
  • Point ID 183 is ( 0,  0,  3) with scale factor 2^2 = (   0,  0,   12)
  • Point ID 184 is ( 3,  0,  0) with scale factor 2^2 = (  12,  0,    0)
  • Point ID 185 is (14,  0, 14) with scale factor 2^2 = (  56,  0,   56)
  • Point ID 186 is ( 3,  4,  3) with scale factor 2^2 = (  12, 16,   12)

Drawing an overhead view of the alien, it looks like this, where all the points are at ground level apart from point 186 in the middle of the alien, which is above ground at the apex of the pointed top of the alien:

                             . .´,
                        . ´  .´ .
                   . ´     .´  ,
           183  +........+´   .    <--- 186
                 `.      :   ,
                   `.    :  .
                     `.  : ,
           182  +        +  184

Point 182 has no lines attached to it and is used as the object anchor point, so the alien's visible shape consists of points 183 to 186.

All four of these points are attached to each other by lines. The alien is pointing towards the bottom-left, with its tail at point 185 and the tip of its highest point at point 186. Its blunt triangular "face" is made up of the triangle 183, 184 and 186, while its footprint on the ground is the triangle 183, 184 and 185.

We calculate the alien's weak spot as a point, and a size in each dimension.

  • The point is at coordinate ((5 Q), 0, (5 Q)) within the object, where the value of Q varies depends on the size of the alien (as feeding aliens get larger). The above coordinates are based on the smallest feeding stage, in which case Q is set to 8, so (5 Q) is 1288, so this means the weak spot is at (1288, 0, 1288).
  • The size for the smallest feeding stage is x-size = 20, y-size = 15 and z-size = 20, which we can express as (20, 15, 20).

In this case, then, if we hit the alien within a cube of size (20, 15, 20), anchored at its weak spot of (1288, 0, 1288), it explodes. In other words, if the bullets are within the cube between (1288, 0, 1288) and (1308, 15, 1308), we have hit the weak spot, which turns out to be a cube that covers the front end of the alien.

So it's perhaps no surprise that to kill an alien, you need to shoot your bullets into the alien's face, where its "tentacles" come from when it's finished feeding. Cthulhu would be proud.

Checking the whole bullet trail for hits

The CheckAlienWeakSpot routine checks whether a specific point in space is within the weak spot, but the bullets travel through the air, leaving a visible trail, so if all we did were to check the points at the start and end of each bullet trail for a hit, we could easily miss a valid kill.

To get around this, the GetTrailVectorStep routine divides the vector of the bullet trail into 32 sections, or steps. The CheckIfAlienIsHit then starts at the back of the bullet trail and checks for a hit. If there is no hit, it adds this 1/32 vector to step along the trail vector to the next point, where it checks for a hit once again. If this is also a miss, it keeps stepping along the trail vector until it either finds a hit (in which case it stops checking), or it reaches the bullet at the head of the bullet trail, in which case we have a miss.

In this way we can check whether a bullet has already passed through the weak spot, and still record a hit. It might not make killing Aviator's aliens easier, but at least it makes it fairer.