10.敢问路在何方?:笛卡尔坐标和极坐标的转换

10.Where Am I Headed?: converting between cartesian and polar coordinates

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.

这篇帖子讨论如何根据x和y轴的速度值来计算总体速度及方向,以及如何限制最大速度,或者:笛卡尔坐标和极坐标。

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.

在我们上一篇的帖子里,我们了解了如何实现漂移。在漂移中,飞船的方向与飞船当前的角度值无关:一旦启动起来,你可以松开up键而仅仅按住left键或right键,飞船便会快速旋转而并不影响运动轨迹。然而,了解当前的速度值(作为单独的数字)和当前的方向值,而不是分离的x和y轴速度值,这是有用的。

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 seenhow to calculate an angle from an X and Y distance, and this is exactly the same principle:

因此,我们已知一对x速度和y速度值,同时希望去计算我们所面对的方向值(角度值)。这听起来很熟悉——我们已经了解了如何根据x和y轴的距离去计算角度值,其实原理是完全一样的:

    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:

和计算方向一样,我们也希望将速度作为单独的数字进行计算,而不是计算分离的x和y速度值。x和y速度毫无疑问可以形成一个直角三角形,如图所示:

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.)

(事实上,java提供了Math.hypot方法完成该功能,但是我希望展示它的计算原理)

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:

于是我们已经知道如何将x和y速度值转化为方向值和单一速度值。也可以进行相反的变换:将方向值和单一速度值转化为x和y速度值。事实上,我们已经讨论这个问题。代码如下:

    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.

我们已经了解了两种不同的表示飞船朝向的途径:要么使用x和y速率,或者使用方向和速度。前者是笛卡尔坐标,后者是极坐标。可以看到两种表示方式可以轻易地进行转换。一般来说,笛卡尔坐标通常便于处理,例如,两个笛卡尔坐标相加很容易,而两个极坐标相加则需要转换为笛卡尔坐标来进行。然而极坐标也是有用的,比如设定最大速度值,已经在今后帖子中提到的用处。

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.

我们首先转换为极坐标,接着将速度“锁定”至上限值10,然后将相同的方向值和(可能改变过的)速度值转回到笛卡尔坐标。

你可能感兴趣的:(Joy,of,Greenfoot)