The Problem

Five years ago, I created a software project in C#. The goal was to create a clone of an old computer game called Gorillas. For those who don’t know abut this game, click this link for an article on The Wiki. Most people would have played a variant of this game based around cannons, though.

I’d got the game 90% complete in my time budget. The only things that where missing were textures (I was still only a baby programmer back then), and aiming code.

My not so elegant code for aiming was terrible, to say the least. By pressing left, right, up or down the player could change the position of the projectile (in this case, a banana). When the player pressed the fire button, the banana would be fired out in a straight line from it’s current position. For some reason, I’d felt that I would never be able to put code in that would make this aiming process simple.

Anyone who’s played the original (be it in tank of gorilla form) will know how to use the aiming system: Right to decrease the trajectory and Left to increase it. Simple.

For some reason, my brain couldn’t figure out how this was done. I tried and tried my hardest, but I couldn’t visualise it. At one point, I ended up trying to program a semi circle of points that could be selected by the user, but that went as well as this sentence seems to have done.

The Solution

Last night I was snuggled up in bed, watching an episode of Seinfeld. The episode ended, I turned the DvD player off, then got back into bed and started to fall asleep. All of a sudden the following image popped into my head.

 

Mario and Tanooki are used via Fair Use. No copyright infringment is meant. Both are copyrighted by Nintendo

At first I wasn’t sure what to make of it. Then, I figured out why the axis are there.

Pressing left will decrease the X value, but increase the Y value. Pressing right will increase the X value but decrease the Y value.

Both X and Y have pre-set limits, X can only be between 5 – 20 units in front of Tanooki and Y can only be between 5 – 20 units above Tanooki, for example.

This algorithm will successfully move the projectile (assuming you show it) around your gorilla (or tank, or Tanooki) along a quarter circle in front of it. In pseudocode it might look something like this:

[sourcecode language=”cpp”]
int projectileXPos, projectileYPos;
int upperLimitX, upperLimitY = 20;

// game code in here

switch (key) {
case left:
//without any bounds checking
projectileXPos–;
projectileYPos++;
break;
case right:
//without any bounds checking
projectileXPos++;
projectileYPos–;
}
[/sourcecode]

Calculating the Angle

So, you’re projectile is moving around the character in a quarter circle arc; which is great. But now you want to be able to fire along the correct trajectory? That’s really simple to work out.

If you look back at the image of Tanooki you’ll see a Greek symbol near his face. For those who aren’t familiar, this is symbol is called Theta and in trigonometry it represents an unknown angle. To calculate this angle we’re going to use something called SoH, CaH, ToA.

Copyrighted by processing.org. Used via Fair Use

If you look back again (what’s with all this looking?) at Tanooki, you might be able to see a triangle forming – the X axis and the trajectory forming the adjacent and the Hypotenuse.

We know all three values for the sides of this triangle (we actually only know two, but a quick bit of trig will calculate the Hypotenuse for us), so we can use any part of SoH CaH ToA to work out the angle.

We’ll use ToA for now, as we know both the Adjacent (X value) and the Opposite (Y value). But we could use either, if we worked out the Hypotenuse.

Again with pseudocode, it could look like this:

[sourcecode language=”cpp”]
#include <math.h>

int projectileXPos, projectileYPos;
int upperLimitX, upperLimitY = 20;
double opposite, adjacent, firingAngle;

// working out the angle

switch (key) {
case fire:
opposite = projectileYPos – player.GetYPos();
adjacent = projectileXPos – player.GetXPos() ;
firingAngle = tan(opposite/adjacent);
}
[/sourcecode]

To calculate the Hypotenuse, all you would have to do is basic Pythagoras. Again, in pseudocode it might look like this:

[sourcecode language=”cpp”]
#include <math.h>

int projectileXPos, projectileYPos;
int upperLimitX, upperLimitY = 20;
double opposite, adjacent, hypotenuse;

// working out the hypotenuse

opposite = projectileYPos – Player.GetYPos();
adjacent = projectileXPos – player.GetXPos();
hypotenuse = sqrt((opposite * opposite) + (adjacent * adjacent));
[/sourcecode]

Why Five Years

I know that this is really simple trig, and I know that the code for it is also really simple. For some reason, though it never crossed my mind to code it this way. I have no idea what prompted this “Eureka moment” for me last night, but I’m really glad that it did. Since then, I’ve been finding simple solutions to other coding problems.

I suppose my problem was, at that time, my whole life revolved around that one problem; as such, and to coin an old phrase, I couldn’t see the wood for the trees.  My best advice for anyone confronting a problem with no, obvious solution – regardless of whether it’s coding or math or life or whatever – is this:

Take a step back from it, and look at it from another angle.

If that doesn’t work walk away from it completely. Some of my other problems have actually been solved by me taking a break and going for a long walk.

If all else fails, watch something like Seinfeld.

I’ve found that, Seinfeld is my Plan Nine From Outer Space.

Anyone who has seen a few episodes of the X-Files will know what I mean there.

There’s that little going on, that my sub-concious mind can, and does, wander. This enables me to find the solutions without even thinking about the problems, while still enjoying the show.

More proof, if anyone needed it, that Larry David is a genius

Related Post


GaProgMan

Jamie is a .NET developer specialising in ASP.NET MVC websites and services, with a background in WinForms and Games Development. When not programming using .NET, he is either learning about .NET Core (and usually building something cross platform with it), speaking Japanese to anyone who'll listen, learning about languages, writing for this blog, or writing for a blog about Retro Gaming (which he runs with his brother)