I was out of town for a week. Before I left, I worked hard to add a level to Planetary Defense that would include enemy missiles. The current Planetary Defense game has three levels, The first is the standard game with the satellite in orbit around the planetoid and attacking enemy bombs. The second level reached at some high score includes a small moon with the satellite rotating around it. The third level is the one with the enemy missile. It aims itself at the satellite and a direct hit will knock out the satellite gun for a while.

The enemy missile is problematic because it must aim for the satellite but also avoid the planetoid. Here is a quick description of how it does that:

  • Keep track of the current heading of the missile.
  • Figure out a new heading towards the satellite.
  • Limit the change in angle to some small amount to keep from making sharp turns.
  • Figure out the points on the planetoid that form tangents from the missile to the planetoid. This is done with some simple trigonometry.
  • If the satellite is closer than the tangent points then nothing else needs to be done.
  • If the new heading of the missile is not between the tangent point angles then nothing else needs to be done.
  • Figure out which tangent point is closest in heading to the current heading, not the newly calculated heading.
  • Figure out the change of heading towards the tangent point. Limit this to some small amount to avoid sharp turns. Use this new heading instead of the one calculated to aim towards the satellite.

There it is. Path finding for the missile. It’s not complex but there are a few things that make it rather tricky.

First, Once the missile is close to the planetoid, it is very close to one of the tangents. Calculating a new heading based on this could, in theory, generate larger than needed headings changes because of limited numeric precision. If the precision of floating point numbers in JavaScript are exceeded because the missile is too close to the tangent point, wild headings changes may be calculated. Fortunately, an oddball heading change will be limited to a small amount to avoid sharp turns and this means that the missile will soon move further from the tangent point and get better headings because of it.

Second, and more importantly, the missile could be within the circle used to calculate the tangent points. If this happens, we will get NAN (Not a Number) results from one of the calculations. The inverse sine of (opposite/hypotenuse) with hypotenuse being smaller than opposite results in a number greater than one which screws up the inverse sine function. This is handled by a test and if the missile is inside of the circle used for path finding around the planetoid, the missile is simply left to travel the current heading and no change is made. it will hit the planetoid or will move outside of the circle. Either way solves the problem.

Third, and a minor problem, is that I did something wrong in some of the code and if the missile gets close enough to the satellite while circling the planetoid, the missile will turn towards to the satellite and cut closer to the planetoid than allowed. I’m not sure where I screwed this up.

Another thing that caused me problems is angle normalization and angle ranges. Using radians or degrees, there is a small issue of testing to see of an angle is between two others when the angle to the left is bigger than the angle to the right. Every test of angles must take this into account. In other words, 10 degrees is between 350 and 30 degrees even though it is not numerically between those two numbers. It is mandatory to know which angle is the left one and which is the right one.

I’m going to improve that code but it might be later in another version of the game. I am going to try to write this as a native OSX Mac program using Objective C and OpenGL. If that works, I should be able to make an IOS port and run this native on an iPhone or iPad. If anything, I can add the knowledge to my resume and maybe get some IOS consulting work in the future. I may also try to write this in Java for Android.