数学向量和旋转(Topdown java 游戏开发 - 物理问题)

发布于 2024-12-03 05:15:54 字数 1265 浏览 3 评论 0原文

我已经在自上而下的汽车游戏上工作了一段时间了,而且似乎总是会回到能够正确地做一件事。就我而言,它正在正确完成我的汽车物理学。

我遇到了当前轮换处理不正确的问题。我知道问题在于我的大小在乘以 Math.cos/sin 方向时为 0,但我根本不知道如何解决它。

这是当前的底层代码。

private void move(int deltaTime) {

double secondsElapsed = (deltaTime / 1000.0);// seconds since last update
double speed = velocity.magnitude();
double magnitude = 0;

if (up)
    magnitude = 100.0;
if (down)
    magnitude = -100.0;
if (right)
    direction += rotationSpeed * (speed/topspeed);// * secondsElapsed;
if (left)
    direction -= rotationSpeed * (speed/topspeed);// * secondsElapsed;

double dir = Math.toRadians(direction - 90);
acceleration = new Vector2D(magnitude * Math.cos(dir), magnitude * Math.sin(dir));

Vector2D deltaA = acceleration.scale(secondsElapsed); 
velocity = velocity.add(deltaA); 

if (speed < 1.5 && speed != 0)
    velocity.setLength(0);

Vector2D deltaP = velocity.scale(secondsElapsed); 
position = position.add(deltaP);

...
}

我的向量类模拟向量基础知识 - 包括加减法、乘以标量...等。

要重申根本问题 - 即当幅度为 0 时,幅度 * Math.cos(dir) = 0 ,因此当玩家只按下没有“加速”方向的右或左箭头键不会改变。

如果有人需要更多信息,您可以在

http://www.java 找到它-gaming.org/index.php/topic,23930.0.html

I've been working on a top down car game for quite a while now, and it seems it always comes back to being able to do one thing properly. In my instance it's getting my car physics properly done.

I'm having a problem with my current rotation not being handled properly. I know the problem lies in the fact that my magnitude is 0 while multiplying it by Math.cos/sin direction, but I simply have no idea how to fix it.

This is the current underlying code.

private void move(int deltaTime) {

double secondsElapsed = (deltaTime / 1000.0);// seconds since last update
double speed = velocity.magnitude();
double magnitude = 0;

if (up)
    magnitude = 100.0;
if (down)
    magnitude = -100.0;
if (right)
    direction += rotationSpeed * (speed/topspeed);// * secondsElapsed;
if (left)
    direction -= rotationSpeed * (speed/topspeed);// * secondsElapsed;

double dir = Math.toRadians(direction - 90);
acceleration = new Vector2D(magnitude * Math.cos(dir), magnitude * Math.sin(dir));

Vector2D deltaA = acceleration.scale(secondsElapsed); 
velocity = velocity.add(deltaA); 

if (speed < 1.5 && speed != 0)
    velocity.setLength(0);

Vector2D deltaP = velocity.scale(secondsElapsed); 
position = position.add(deltaP);

...
}

My vector class emulates vector basics - including addition subtraction, multiplying by scalars... etc.

To re-iterate the underlying problem - that is magnitude * Math.cos(dir) = 0 when magnitude is 0, thus when a player only presses right or left arrow keys with no 'acceleration' direction doesn't change.

If anyone needs more information you can find it at

http://www.java-gaming.org/index.php/topic,23930.0.html

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

层林尽染 2024-12-10 05:15:54

是的,那些物理计算全都混淆了。根本问题是,正如您所意识到的,将加速度乘以方向是错误的。这是因为你的“方向”不仅仅是汽车加速的方向;而是汽车加速的方向。这是汽车行驶的方向。

解决这个问题的最简单方法是首先分别考虑加速和转向。首先,加速:为此,您只有一个速度,并且有“向上”和“向下”键。为此,代码如下所示(包括将接近零的速度降低到零的阈值代码):

if (up)
    acceleration = 100.0;
if (down)
    acceleration = -100.0;

speed += acceleration * secondsElapsed;

if (abs(speed) < 1.5) speed = 0;

另外,您有转向,它改变汽车运动的方向 - 也就是说,它改变您乘以的单位向量加速以获得速度。我还冒昧地修改了您的变量名称,使其看起来更像代码的加速部分,并阐明了它们的含义。

if (right)
    rotationRate = maxRotationSpeed * (speed/topspeed);
if (left)
    rotationRate = maxRotationSpeed * (speed/topspeed);

direction += rotationRate * secondsElapsed;

double dir = Math.toRadians(direction - 90);
velocity = new Vector2D(speed * Math.cos(dir), speed * Math.sin(dir));

您可以简单地将这两部分组合起来,在第二部分的速度计算中使用第一部分的速度,以获得完整的简单加速和转向模拟。

Yes, those physics calculations are all mixed up. The fundamental problem is that, as you've realized, multiplying the acceleration by the direction is wrong. This is because your "direction" is not just the direction the car is accelerating; it's the direction the car is moving.

The easiest way to straighten this out is to start by considering acceleration and steering separately. First, acceleration: For this, you've just got a speed, and you've got "up" and "down" keys. For that, the code looks like this (including your threshold code to reduce near-zero speeds to zero):

if (up)
    acceleration = 100.0;
if (down)
    acceleration = -100.0;

speed += acceleration * secondsElapsed;

if (abs(speed) < 1.5) speed = 0;

Separately, you have steering, which changes the direction of the car's motion -- that is, it changes the unit vector you multiply the speed by to get the velocity. I've also taken the liberty of modifying your variable names a little bit to look more like the acceleration part of the code, and clarify what they mean.

if (right)
    rotationRate = maxRotationSpeed * (speed/topspeed);
if (left)
    rotationRate = maxRotationSpeed * (speed/topspeed);

direction += rotationRate * secondsElapsed;

double dir = Math.toRadians(direction - 90);
velocity = new Vector2D(speed * Math.cos(dir), speed * Math.sin(dir));

You can simply combine these two pieces, using the speed from the first part in the velocity computation from the second part, to get a complete simple acceleration-and-steering simulation.

由于您询问加速度作为向量,因此这里有一个替代解决方案,可以通过这种方式进行计算。

首先,给定速度(Vector2D 值),我们假设您可以从中计算出方向。我不知道你的语法,所以这里有一个可能的草图:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

这是汽车指向的方向。 (汽车总是指向其速度的方向。)

然后,我们得到加速度的分量。首先是加速度的前后部分,这很简单:

double forwardAcceleration = 0;
if (up)
    forwardAcceleration = 100;
if (down)
    forwardAcceleration = -100;

转向引起的加速度稍微复杂一些。如果您绕圈运动,则朝向圆心的加速度大小等于速度的平方除以圆的半径。而且,如果你向左转向,加速度就会向左;如果你向左转向,加速度就会向左。如果你向右转向,它就在右边。因此:

double speed = velocity.magnitude();
double leftAcceleration = 0;
if (right)
    leftAcceleration = ((speed * speed) / turningRadius);
if (left)
    leftAcceleration = -((speed * speed) / turningRadius);

现在,您有一个包含向前方向加速度的 forwardAcceleration 值(向后为负值),以及一个包含向左方向加速度的 leftAcceleration 值(右为负)。让我们将其转换为加速度矢量。

首先,一些额外的方向变量,我们用它们来制作单位向量(主要是为了使代码易于解释):

double leftDirection = forwardDirection + 90;

double fDir = Math.toRadians(forwardDirection - 90);
double ldir = Math.toRadians(leftDirection - 90);

Vector2D forwardUnitVector = new Vector2D(Math.cos(fDir), Math.sin(fDir));
Vector2D leftUnitVector = new Vector2D(Math.cos(lDir), Math.sin(lDir));

然后,您可以通过组装向前和向左的部分来创建加速度向量,如下所示:

Vector2D acceleration = forwardUnitVector.scale(forwardAcceleration);
acceleration = acceleration.add(leftUnitVector.scale(leftAcceleration));

好的,这就是您的加速度。您可以像这样将其转换为速度的变化(请注意,正确的术语是 deltaV,而不是 deltaA):

Vector2D deltaV = acceleration.scale(secondsElapsed);
velocity = velocity.add(deltaV).

最后,您可能想知道汽车的方向是前进的(为了将其绘制在屏幕上),因此您可以根据新的速度进行计算:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

现在您已经得到了它 - 使用加速度作为矢量完成物理计算,而不是使用随速度旋转的一维速度车。

(这个版本更接近您最初尝试做的事情,所以让我分析一下您出错的地方。来自上/下的加速度部分始终指向汽车所在的方向同时,来自转向的加速度部分始终纯粹是向左或向右,其大小与前/后加速度无关。 ,特别是,即使前/后加速度为零。要获得总加速度矢量,您需要分别计算这两个部分并将它们作为矢量加在一起。)

这些计算都不是完全精确的。在此例中,您从汽车出发的位置计算“向前”和“向左”方向,但汽车正在旋转,因此这些方向会随着时间步长而变化。因此,deltaV = 加速度 * 时间等式只是一个估计,会产生稍微错误的答案。另一种解决方案也有类似的不准确性——但另一种解决方案更好的原因之一是,在这个解决方案中,小误差意味着如果你左右驾驶汽车,速度会增加,即使你不这样做触摸“向上”键——而在另一个中,这种交叉错误不会发生,因为我们将速度和转向分开。

Since you asked about acceleration as a vector, here is an alternate solution which would compute things that way.

First, given the velocity (a Vector2D value), let's suppose you can compute a direction from it. I don't know your syntax, so here's a sketch of what that might be:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

This is the direction the car is pointing. (Cars are always pointing in the direction of their velocity.)

Then, we get the components of the acceleration. First, the front-and-back part of the acceleration, which is pretty simple:

double forwardAcceleration = 0;
if (up)
    forwardAcceleration = 100;
if (down)
    forwardAcceleration = -100;

The acceleration due to steering is a little more complicated. If you're going around in a circle, the magnitude of the acceleration towards the center of that circle is equal to the speed squared divided by the circle's radius. And, if you're steering left, the acceleration is to the left; if you're steering right, it's to the right. So:

double speed = velocity.magnitude();
double leftAcceleration = 0;
if (right)
    leftAcceleration = ((speed * speed) / turningRadius);
if (left)
    leftAcceleration = -((speed * speed) / turningRadius);

Now, you have a forwardAcceleration value that contains the acceleration in the forward direction (negative for backward), and a leftAcceleration value that contains the acceleration in the leftward direction (negative for rightward). Let's convert that into an acceleration vector.

First, some additional direction variables, which we use to make unit vectors (primarily to make the code easy to explain):

double leftDirection = forwardDirection + 90;

double fDir = Math.toRadians(forwardDirection - 90);
double ldir = Math.toRadians(leftDirection - 90);

Vector2D forwardUnitVector = new Vector2D(Math.cos(fDir), Math.sin(fDir));
Vector2D leftUnitVector = new Vector2D(Math.cos(lDir), Math.sin(lDir));

Then, you can create the acceleration vector by assembling the forward and leftward pieces, like so:

Vector2D acceleration = forwardUnitVector.scale(forwardAcceleration);
acceleration = acceleration.add(leftUnitVector.scale(leftAcceleration));

Okay, so that's your acceleration. You convert that to a change in velocity like so (note that the correct term for this is deltaV, not deltaA):

Vector2D deltaV = acceleration.scale(secondsElapsed);
velocity = velocity.add(deltaV).

Finally, you probably want to know what direction the car is headed (for purposes of drawing it on screen), so you compute that from the new velocity:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

And there you have it -- the physics computation done with acceleration as a vector, rather than using a one-dimensional speed that rotates with the car.

(This version is closer to what you were initially trying to do, so let me analyze a bit of where you went wrong. The part of the acceleration that comes from up/down is always in a direction that is pointed the way the car is pointed; it does not turn with the steering until the car turns. Meanwhile, the part of the acceleration that comes from steering is always purely to the left or right, and its magnitude has nothing to do with the front/back acceleration -- and, in particular, its magnitude can be nonzero even when the front/back acceleration is zero. To get the total acceleration vector, you need to compute these two parts separately and add them together as vectors.)

Neither of these computations are completely precise. In this one, you compute the "forward" and "left" directions from where the car started, but the car is rotating and so those directions change over the timestep. Thus, the deltaV = acceleration * time equation is only an estimate and will produce a slightly wrong answer. The other solution has similar inaccuracies -- but one of the reasons that the other solution is better is that, in this one, the small errors mean that the speed will increase if you steer the car left and right, even if you don't touch the "up" key -- whereas, in the other one, that sort of cross-error doesn't happen because we keep the speed and steering separate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文