创建一个不错的汽车运动并不难(但是这篇文章会很长)。您需要“模拟”几个基本力才能使汽车在物理上看起来合理。
(所有代码示例都是伪代码。)
加速
首先,您显然需要加速。就像下面的代码行一样简单:
acceleration_vector = forward_vector * acceleration_input * acceleration_factor
forward_vector
—指向与汽车相同方向的向量。
acceleration_input
—输入应在[-1,1]范围内。
acceleration_factor
—加速度的值(像素/秒^ 2,或任何单位)。
操舵
转向也很简单。原则上,您要做的是旋转汽车的前向矢量,使其指向其他方向。
steer_angle = steer_input * steer_factor
new_forward_vector = rotate_around_axis(forward_vector, up_vector, steer_angle)
但是,您可能会在这里遇到麻烦。如果通过键盘输入,则其值将为-1或1,这意味着您的汽车将立即转弯。您可以使用非常简单的线性插值(公差)来解决此问题:
amount = time_since_last_frame * steer_lerp_factor
forward_vector = lerp(forward_vector, new_forward_vector, amount)
数量应取决于时间,以使您的移动不取决于帧频。该值应在[0,1]之间,并且该值越小,新旧矢量之间的过渡越平滑。
(在这一点上,你会发现,该车将引导即使是站着不动。为了防止这种情况,乘steer_angle
用current_speed / max_speed
,这里max_speed
是由您定义的常量。)
移动
现在,我们将应用加速度,并根据其速度,加速度和转向将汽车移动一定数量的像素。我们还将希望限制汽车的速度,以使其最终不会无限快地行驶。
current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
velocity_vector += acceleration_vector * time_since_last_frame
}
position_vector += velocity_vector * time_since_last_frame
你的车现在在滑
如果我是对的,那么当您转弯时,您的汽车现在似乎应该在滑行,就像在冰上一样。这是因为没有摩擦。在真实的汽车上,存在很大的侧向摩擦力(由于车轮无法横向旋转:P)。
您将需要降低横向速度。通过不完全减小它,您还可以使汽车看起来正在漂移。
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
既然我们在谈论摩擦,您可能还希望有一个(摩擦)力来降低速度,这样当您停止加速时,您的汽车最终将停止。
backwards_friction = -velocity_vector * backwards_friction_factor
您的汽车行驶代码现在应如下所示:
// Friction should be calculated before you apply the acceleration
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
backwards_friction = -velocity_vector * backwards_friction_factor
velocity_vector += (backwards_friction + lateral_friction) * time_since_last_frame
current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
velocity_vector += acceleration_vector * time_since_last_frame
}
position_vector += velocity_vector * time_since_last_frame
结束语
我提到您应该如何将套环应用于转向;我认为您可能需要对加速和转向角做同样的事情(您将必须存储前一帧的值,并从前一帧起跳)。同样,相对于汽车的所有矢量(前,右,上)都应为长度1。
而且,摩擦比我在这里显示的要复杂一些。您应始终确保其长度不大于使轿厢停止所需的加速度的长度(否则摩擦会使轿厢向相反方向移动)。因此,您应该具有以下内容:
dt = time_since_last_frame
backwards_friction.resize(min(backwards_friction.norm(), velocity_vector.norm() / dt))
lateral_friction.resize(min(lateral_friction.norm(), lateral_velocity.norm() / dt))