汽车转向 - OpenGL

时间:2014-12-11 16:57:56

标签: java algorithm opengl

我正在制作一款赛车游戏,并且无法弄清楚如何让转向工作。我有一个基本的比赛2D赛道,建在3D环境中。该程序仅使用x和y,z为0。

我的赛道包括一条x轴为29单位的道路和两条沿y方向长120个单位的长轨道。在y轴上120个单位处有180度转弯。您可以将球场视为类似于赛车风格的赛道。

我正试着设置我的汽车的转向,这样当我达到180度转弯时它可以变得逼真。我使用两个分别控制x / y位置的变量,以及x / y速度的两个变量。我的代码目前如下:

public void steering(){
    double degreesPerFrame = 180 / (2*30); //180 degrees over 30 fps in 2s
    velocityX = velocityX * -1 * Math.cos(degreesPerFrame);
    velocityY = velocityY * -1 * Math.sin(degreesPerFrame);
    double yChange = Math.sin(degreesPerFrame) * velocityY;
    double xChange = Math.cos(degreesPerFrame) * velocityX;
    x += xChange; //change x position
    y += yChange; //change y position
}

我不能完全确定如何让我的转向正常转向。我现在陷入困境,不知道在功能上需要改变什么才能使转向正常工作。

1 个答案:

答案 0 :(得分:2)

我认为如果您根本不使用角度进行计算,这会更容易。只需使用位置,速度和加速度矢量进行操作。

首先,快速提醒物理101.使用一小段时间dt,当前位置p,当前速度向量v和加速度向量a ,新职位p'和速度向量v'为:

v' = v + a * dt
p' = p + v' * dt

加速度a取决于驾驶员输入。例如:

  • 以恒定速度向前移动时,它为0。
  • 加速时,受发动机功率和纵向轮胎抓地力的限制。
  • 转弯时,受横向轮胎抓地力的限制。
  • 制动时,它受到轮胎抓地力的限制(大多数情况下,制动器通常强度不足以限制)。

对于一个相对简单的模型,您可以假设纵向和横向上的抓地力是相同的(实际上并非完全如此),这限制了圆内矢量的总加速度,这通常称为摩擦力圈。

那主要是背景。回到这里更具体的情况,这是一个稳定的转速。转向汽车的结果可以通过横向力和相应的加速度来建模。因此,在这种情况下,我们可以应用与当前速度矢量正交的加速度矢量。

使用速度矢量的分量:

v = (vx, vy)

一个与左边正交的向量(你提到过NASCAR,所以只剩下左转......)是:

(-vy, vx)

由于我们想要控制横向加速度的量,即加速度矢量的长度,我们将这个矢量归一化,然后乘以最大加速度:

a = aMax * normalize(-vy, vx)

如果您使用真实单位进行计算,则可以为最大横向加速度aMax应用实际数字。否则,只需调整一下即可为人工装置中的汽车提供所需的机动性。

这真的是你所需要的。以代码形式重新显示步骤:

// Realistic value for sports car on street tires when using
// metric units. 10 m/s^2 is slightly over 1 g.
static const float MAX_ACCELERATION = 10.0f;

float deltaTime = ...;  // Time since last update.
float accelerationX = -veclocityY;
float accelerationY = velocityX;
float accelerationScale = MAX_ACCELERATION /
        sqrt(accelerationX * accelerationX + accelerationY * accelerationY);
accelerationX *= accelerationScale;
acceleration *= accelerationScale;
velocityX += accelerationX * deltaTime;
velocityY += accelerationY * deltaTime;
x += velocityX * deltaTime;
y += velocityY * deltaTime;