Refining atan

In this chapter, we will make our monkey aim correctly. We will identify and fix the bugs that cause atan to give the wrong angles.

Currently, your monkey will attempt to aim wherever you press in the game. However, if you click on the left side of the monkey, it will get the wrong angle. And if you click in just the right places, the game will crash.

Let's look at our angle-finding process. This will change throughout the chapter.

Blocks setting angle from atan

We're going to add checks for two situations into this process:

  • Divide-by-zero errors
  • Negative coordinates

Don't Divide by Zero

In your game, you will get a divide-by-zero error if your dx is precisely 0. This is because we divide dy by dx before we run atan.

angle = atan( Y / X )

angle = atan( 1 / 0 ) ???

You can't divide by zero. The result is undefined. Computers will throw errors, and mathematicians will get upset.

Fortunately, we can tell this bug is coming. We know dx before we run atan. If dx is precisely 0, we don't need to run atan. We can supply some other answer instead.

What should that answer be? You can figure this out by graphing the problem. First, let's look at a vector (1, 0). This is an arrow pointing straight down. We know that this is precisely 90 degrees.

Vector (1, 0) and the angle 90 degrees

Next, let's look at the vector (-1, 0). This points in the opposite direction and is precisely -90 degrees.

Vector (-1, 0) and the angle -90 degrees

These two vectors describe all possible angles for vectors with X component 0.

Let's add a check to our game, and get rid of pesky divide-by-zero errors.

  • Add an if conditional block just before angle.
  • Add an else case to the if block.
  • Move the angle atan line into the else bracket.
  • In the condition slot, add dx = 0.
  • In the do bracket, add a second if... else block.
  • For the second if condition, check dy < 0.
  • If true, set angle -90.
  • Else, set angle 90.

Have you seen if else blocks before? You start with a normal if block, then click the settings cog to configure it. Just drag an else block into the if section. It goes like this: Adding else cases

Your code should look like this:

Blocks with divide-by-zero amelioration

Now test your game. You should be unable to get divide-by-zero errors.

Negative Coordinates

When you try to aim to the left, your monkey gets confused. Why is this?

The answer has to do with vectors and division.

First, let's look at the vector (1, 1).

angle = atan( 1 / 1 )

angle = atan( 1 )

angle = 45 degrees

Vector (1, 1) with angle indicated

So far so good. Now let's look at a vector pointing in the opposite direction, (-1, -1).

angle = atan( -1 / -1 )

angle = atan( 1 )

angle = 45 degrees

Vector (-1, -1) with actual and calculated angles indicated

Uh-oh. That's wrong.

Can you see the reason? Both (1, 1) and (-1, -1) resolve to 1 before we run atan. If we put the same number in, we get the same number out. The operation isn't magic.

In fact, atan will give the wrong answer any time X is negative. It will only return angles between -90 and 90 degrees. You will never receive angles between -180 and -90, or between 90 and 180. Half the arc of angles is impossible!

Fortunately, we know the exact nature of the error. When X is negative, the answer is off by precisely 180 degrees.

So if we know X is negative, we can just add 180 to the output of atan and get the correct result every time.

Let's do this now.

  • Directly after our angle atan line, add another if block. Do not add an else case.
  • If dx < 0...
  • ... set angle to angle + 180.

Your code should now look like this:

Completed atan handling code

Play your game, and press all over the game. Your monkey will now shoot wherever you press.

Congratulations! You understand the failure modes of atan, and how to get the right answer under any circumstances.

results matching ""

    No results matching ""