Learning and Applying Mathematics using Computing

Where Am I Headed?

This post is about calculating your direction and overall speed from your X and Y speeds and restricting maximum speed, or: cartesian and polar coordinates.

In our last post, we saw how to implement drifting. With drifting, your direction is independent from your ship’s current rotation: once you’re moving, you can let go of the up key and just hold left or right to spin round without affecting your trajectory. However, it can be useful to know the current speed (as a single number) and the current direction, rather than separate X and Y speeds.

Calculating Direction

So, we have an X speed and a Y speed, and we want to calculate the direction (angle) in which we are heading. This sounds familiar — we’ve already seen how to calculate an angle from an X and Y distance, and this is exactly the same principle:

    private static double calculateDirection(double x, double y)
    {
        return Math.toDegrees(Math.atan2(y, x));
    }

Calculating Speed

As well as direction, we also want to calculate the speed as a single number, rather than separate X and Y speeds. The X and Y speed can inevitably form a right-angled triangle, like so:

So we know two sides and need to know the third: this is a case for Pythagoras. The square of the hypotenuse (diagonal line) is equal to the sum of the squares of the other two sides, so we just have to square-root the sum of the squares of the other sides:

    private static double calculateMagnitude(double x, double y)
    {
        return Math.sqrt(x * x + y * y);
    }

(In fact, Java provides this exact function as Math.hypot, but I wanted to show here how it works.)

There… And Back Again

So we’ve seen how to turn X and Y speeds into distance and a single-speed. It’s also possible to do the reverse: turn distance and a single-speed into X and Y speeds. And in fact, we’ve already covered that one, too. So the code is:

    private static double calculateX(double dir, double mag)
    {
        return Math.cos(Math.toRadians(dir)) * mag;
    }
    
    private static double calculateY(double dir, double mag)
    {
        return Math.sin(Math.toRadians(dir)) * mag;
    }

I’m using the more general term magnitude rather than speed here, because actually this function can be used for speeds or positions or any “vector”.

Cartesian and Polar

We’ve seen two different ways of representing our ship’s heading: either as an X and Y velocity, or as a direction and speed. The former representation is known as Cartesian, the latter is known as Polar. We’ve seen that you can convert between the two representations easily. In general, Cartesian is often easier to work with, e.g. adding two Cartesian vectors is easy, whereas adding two Polar vectors requires converting to Cartesian anyway. However, Polar can also be useful, such as implementing a maximum speed, and a few other uses in future posts.

Maximum Speed

In our last post, we implemented drifting, but our spaceship could keep on accelerating forever. It’s better for a game if you have a maximum speed, so you can add a function like this to set a maximum speed:

    private void clampSpeed()
    {
        double dir = calculateDirection(speedX, speedY);
        double speed = calculateMagnitude(speedX, speedY);
        
        final double MAX_SPEED = 10;
        
        if (speed > MAX_SPEED)
        {
            speed = MAX_SPEED;
        }
        
        speedX = calculateX(dir, speed);
        speedY = calculateY(dir, speed);
    }

We first convert to polar, then “clamp” the speed to a maximum of 10, then convert back to cartesian using the same direction and the (potentially altered) speed.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s