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.
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.
Next, let's look at the vector (-1, 0). This points in the opposite direction and is precisely -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 beforeangle
. - Add an
else
case to theif
block. - Move the
angle
atan
line into theelse
bracket. - In the condition slot, add
dx
=
0
. - In the
do
bracket, add a secondif... else
block. - For the second
if
condition, checkdy
<
0
. - If true,
set angle
-90
. - Else,
set angle
90
.
Have you seen
if else
blocks before? You start with a normalif
block, then click the settings cog to configure it. Just drag anelse
block into theif
section. It goes like this:
Your code should look like this:
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
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
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 anotherif
block. Do not add anelse
case. - If
dx
<
0
... - ...
set angle
toangle
+
180
.
Your code should now look like this:
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.