9.Catch My Drift: a post about implementing asteroids-style drifting
This post is about implementing drifting movement (a la asteroids), and draws together several previous posts.
这篇帖子讨论如何实现飘移(以星球大战为例),并把前面帖子的内容综合一下。
There are various simple movement schemes that you can implement in games. We’ve used one in our previous posts:moving at a fixed speed (with steering). Another is what I will call asteroids-style movement: you have a persistent velocity (or “drift”), and you can apply thrust in a particular direction to change the velocity. It’s hard to describe it simply in text, so the best way to get an idea of what I’m talking about is togo have a play with the scenario.
在游戏中你可以实现各种各样简单的运动设计。在前面的帖子中我们使用了一种:以固定的速度移动(结合转向)。另一种是我将称为星球大战类型的运动:拥有持续的速率(或“漂移”),同时能够在某个特定的方向运用推力来改变速率。这很难用文字简单地进行描述,因此要了解我说的什么意思最好去玩一下相关的游戏剧本。
In this post, we will implement drifting. To do this, we must create a variable to hold the current speed in the X direction, and the current speed in the Y direction. Each frame we add the current speeds onto the current position.
在这篇帖子里,我们将实现飘移。为了达到目的,我们必须创建一个变量来保存当前x方向和y方向的速度值。每一帧我们把当前的速度值加到当前的坐标上去。
The key aspect of implementing drift-style movement is that when we press a key to move, instead of adding some amount to the currentposition, we add some amount (known as acceleration) to the currentspeed, which in turn will be added to the current position in each of the future frames. We’ve already seen this technique inthe previous post on falling, so we can form a rough skeleton of our code:
实现类似飘移运动的关键部分是,当按下某个键来移动时,我们并不是增加当前坐标值,而是增加速度值(加速度),相应地在每个下一帧将其累加到当前坐标上。我们在之前讨论下落的帖子里已经了解了这个技术,因此我们可以形成如下代码框架:
private double speedX;
private double speedY;
public void act()
{
doTurn();
doMove();
}
private void doMove()
{
if (Greenfoot.isKeyDown("up"))
{
setImage("rocket.png");
speedX = speedX + ???;
speedY = speedY + ???;
}
else
{
setImage("rocket_nothrust.png");
}
setLocation(getX() + (int)speedX, getY() + (int)speedY);
}
(We’ll additionally use the doTurn method from our turning example, and alsothe world-wrapping code from our world-wrapping example.)
(我们将额外地使用在转向示例中提到的doTurn方法,以及在世界卷动示例中提到的坐标卷动代码。)
So we have persistent variables for speedX and speedY, declared as members of our Spaceship class. We add these speeds to our position each frame, on the last line of the code above. We also have some code to change the image of the rocket when we are accelerating/drifting. The bit that still needs filling in is how to adjust the speed each frame.
于是我们拥有了持久的变量speedX 和speedY,并把它们定义为Spaceship 类的成员变量。每一帧我们把这些速度值累加到坐标上,如上述代码的最后一行所示。我们也通过一些代码来改变火箭加速/飘移时的图像。现在有待完成的是如何在每一帧中去调准速度值。
We want to add an appropriate acceleration to our speed, based on which direction we’re facing. We want to accelerate a certain amount in the direction we are pointing. This is exactly the same principle asan earlier post, where we wanted to move a certain amount in the direction we are pointing. The only difference is that instead of moving, we add to our speed: 我们希望在当前所处的方向上给速度增加一个加速度值。我们希望在当前方向增加一个固定值。这和之前帖子讨论的原理是一致的。唯一的区别在于我们增加的是速度值,而不是移动距离:
double radians = Math.toRadians(getRotation());
double moveSpeed = 0.1;
double accX = Math.cos(radians) * moveSpeed;
double accY = Math.sin(radians) * moveSpeed;
speedX = speedX + accX;
speedY = speedY + accY;
You can have a play with the finished scenario, or view its full source code in Greenfoot. You may notice that its speed can increase to unlimited amounts — we will fix that in a forthcoming post.
你可以玩一下完成后的游戏剧本,或者在Greenfoot中查看完整代码。你可能会注意到其速度值可以无限增加——我们将会在接下来的帖子中进行修正。