12.燃烧的橡胶:使用极坐标旋转位置

来源:互联网 发布:mac屏蔽广告插件 编辑:程序博客网 时间:2024/06/12 01:07

12.Burning Rubber: rotating positions using polar coordinates

This post is about rotating coordinates by using polar coordinates.

这篇帖子讨论使用极坐标进行坐标的旋转

In our last post, we added a braking capability to our bus. One visual effect that’s quite neat is adding tyre (US: tire) marks where the vehicle has braked sharply and left rubber on the ground. In this post, we’ll add these tyre tracks to our bus scenario.

在上一篇帖子里,我们为巴士添加了减速功能。一个特别棒的视觉效果是当巴士急剧减速时在地面上留下轮胎的橡胶印迹。在这篇帖子里,我们为游戏剧本添加轮胎印迹。

Tyre Tracks

轮胎印迹

The basic idea for adding tyre tracks is the same as things like smoke effects in Greenfoot: we will have a tyre-track actor, of which we’ll add many to the world, and once added they will remain stationary but slowly fade away until they remove themselves entirely. The code for the tyre-track actor is not very mathematical, but just so you can see how it’s done, here it is:

在Greenfoot中,添加轮胎印迹的基本思路和烟雾效果一样:我们定义一个tyre-track角色,然后在世界中加入许多这样的角色对象,而且一旦加入到世界中,它们将逐渐消失直到完全被清除。tyre-track角色的代码不是十分精确,但是如此一来你便能知道是怎样做的,如下所示:

public class TyreTrack extends Actor{    public void act()    {        // Make a faded copy of the image:        Color color = getImage().getColorAt(0, 0);        color = new Color(color.getRed(), color.getGreen(), color.getBlue(),                          Math.max(0,color.getAlpha() - 2));        GreenfootImage img = new GreenfootImage(getImage().getWidth(),                                                getImage().getHeight());        img.setColor(color);        img.fill();        setImage(img);        if (color.getAlpha() == 0)            getWorld().removeObject(this);    }}

Where’s Ya Wheels?

车轮在哪?

The main difficulty in adding tyre tracks is where exactly to add them. Obviously, we should add them under the wheels. The first step is to load up the bus image and determine suitable coordinates (relative to the centre of the image) of the four wheels — that is (45, 26) for my bus drawing, and the image is symmetrical in both dimensions. This tells us where to add the tyre tracks, when the bus is pointing to the right. Here’s the first version of the code:

主要的难点在于要精确地添加轮胎印迹。明显地,我们应该将它们加入到轮胎下面。第一步是读取巴士的图像并在绘制巴士时为四个轮胎设定合适的坐标(相对于图像的中点)——其中之一是(45,26),而且图像在两个方向都是对称的。这告诉我们当巴士朝向右边的时候应该在哪儿添加轮胎印迹。以下是代码的第一个版本:

    private void layDownRubber()    {        double wheelPos[][] =           { {45, 26}, {45, -26}          , {-45, 26}, {-45, -26} };                  for (double[] pos : wheelPos)        {            double x = pos[0];            double y = pos[1];                        double worldX = getX() + x;            double worldY = getY() + y;                        if (worldX >= 0 && worldX < getWorld().getWidth()               && worldY >= 0 && worldY < getWorld().getHeight())            {                TyreTrack track = new TyreTrack();                // Orient it in the same direction as the bus (wheels point same way as bus):                track.setRotation(getRotation());                getWorld().addObject(track, (int)worldX, (int)worldY);            }        }    }

The basic idea is that we have four wheel positions (each position is a two-item array, with X and Y in it), which we go through, and add a tyre-track at that coordinate, relative to our own position (which we get with getX() and getY()). The last if-check is just to make sure we’re not trying to add them outside the world (which Greenfoot will not like).

基本思路是,我们拥有四个轮胎的位置(每个位置是一个包含两个元素的数组,包含了x和y 的值),当我们向前行驶时便在那个坐标处添加一个轮胎印迹,这是相对于当前位置(调用getX() 和getY()方法获取)来说的。最后一个if检查语句保证我们不会将它们添加到世界的外面(Greenfoot不允许)。

 The problem is that as soon as we rotate the bus, these positions won’t be correct any more, and the tyre marks will start appearing in odd places that don’t look right given the bus’s current orientation. We need to rotate these positions (not just rotate the tyre tracks, but rotate the position relative to the bus’s centre) according to the bus’s rotation.

问题在于,当我们旋转巴士时这些位置将不再准确,而且轮胎印迹将开始在早前的位置上显现,考虑到巴士当前的朝向,这看起来不是很正确。我们需要根据巴士的方向来旋转这些位置(不仅旋转轮胎印迹,而且参照巴士中心来旋转其位置)。

Rotating A Vector

旋转一个向量

There’s a couple of different ways we could go about rotating the position of the wheels. I’m going to choose the method that re-uses code we’ve already seen in a previous post. We can convert the position of the wheels (which is relative to the centre of the bus) to a polar coordinate. This allows us to easily rotate them, by manipulating the polar rotation, before converting them back to cartesian. So the new version of our code looks like this:

这儿有几种途径来旋转车轮的位置。我准备采用一个方法来重新利用前一篇帖子里我们已经了解的代码。我们可以将车轮的位置(参照巴士的中心)转换为极坐标。这使得我们能够在将其转换回笛卡尔坐标之前通过操作极坐标旋转来轻易地旋转它们。因此新版本的代码如下:

    private void layDownRubber()    {        double wheelPos[][] =           { {45, 26}, {45, -26}          , {-45, 26}, {-45, -26} };                  for (double[] pos : wheelPos)        {            double x = pos[0];            double y = pos[1];                        double dir = calculateDirection(x, y);            double dist = calculateMagnitude(x, y);                        dir = dir + getRotation();                        double worldX = getX() + calculateX(dir, dist);            double worldY = getY() + calculateY(dir, dist);                        if (worldX >= 0 && worldX < getWorld().getWidth()               && worldY >= 0 && worldY < getWorld().getHeight())            {                TyreTrack track = new TyreTrack();                // Orient it in the same direction as the bus (wheels point same way as bus):                track.setRotation(getRotation());                getWorld().addObject(track, (int)worldX, (int)worldY);            }        }    }

The difference here is that now we convert the X and Y into direction and magnitude (distance), then alter the rotation by adding our current rotation, then convert it back to cartesian X and Y coordinates. This will position the tyre tracks in the right place. To make this all work, we add a call to the layDownRubber() function in the braking code fromthe last post, to make us skid whenever we’re braking at high speed:

这儿的区别在于现在我们将x和y坐标转换为方向和幅度(距离),接着通过加上当前角度值来改变其角度,接着将其转回到笛卡尔坐标下的x和y坐标。这将使得轮胎印迹显示在正确的位置。为了让一切工作起来,我们在上一篇帖子中使用的减速代码里添加了layDownRubber() 方法调用,以便实现高速运动中刹车时的滑行。

        if (Greenfoot.isKeyDown("down"))        {            speed = Math.max(0, speed - 0.1);            if (speed > 5)            {                layDownRubber();            }        }

Now you can perform cool-looking skids like this one:

现在你可以实现如下所示的看起来很酷的滑行:

Have a play yourself orlook at the source code.

自己玩一下或者查看一下源代码。