3

基本上,我正在研究物理游戏中的阻力。需要减少侧向运动(因为接近于 0,而不仅仅是带负数),但我不知道它在哪个方向行进,所以我不知道是增加阻力还是减少阻力。

(如果一个项目向右移动,它有正向力,向左移动,负向力)

现在我正在这样做:

if (objects[i]->force.x > 0)
    objects[i]->force.x -= drag;
else
    objects[i]->force.x += drag;

效果很好,但我觉得肯定会有一种更时尚的方式来做到这一点。

找到一种方法来确保它不会超过 0 也无妨

4

4 回答 4

6

如果您试图模拟摩擦,最简单的方法是了解速度并使用数学模型或微分方程来近似它。

     dx
-c * --
     dt

基本上,摩擦力与速度成正比,方向相反。因此,您可以简单地计算摩擦力(或阻力),如下所示:

objects[i]->force = -drag_coefficient * objects[i]->velocity

如果你不知道速度,就很难得到好的结果,因为你可能有一个向右推的力,而物体向左移动(因此你会向错误的方向施加阻力)。

编辑:

实际上,并非所有类型的摩擦都取决于速度的大小(速度)干摩擦通常被称为仅考虑速度的方向

force = -drag_coefficient * sign(velocity)

然而,在计算上,当速度达到 0 时,它变得不稳定,超过它并来回振荡。

另一种模型是湿摩擦模型,即我在第一个示例中使用的模型:

force = -drag_coefficient * velocity

这意味着当您的对象运行得更快时,它会因摩擦而减慢更多。以空气的力量为例,当你跑步时,你跑得越快,空气就越试图让你慢下来。

上述两种模型都不是 100% 准确的,但对于游戏来说,它们应该绰绰有余

于 2013-05-10T15:00:34.800 回答
2

阻力应该是速度的函数:drag = r_1 * v其中r_1 < 0. 这将导致阻力与速度相反。然后你可以只添加阻力。

于 2013-05-10T15:00:47.757 回答
2

首先,我们应该澄清这里所代表的内容。你写“如果一个项目向右移动,它有正向力……”通常,如果一个项目向右移动,我们会期望它在那个方向有一个正向速度,不一定是一个正向力。

如果您在固体表面上拖动固体物体,抵抗拖动运动的“理想”摩擦力是将物体推入表面的力(例如重力)乘以摩擦系数(取决于所涉及的材料)。将此力除以物体的质量会产生加速度。在物体(包括其质量)、材料和垂直力不变的情况下,您可以计算一次该加速度并将其视为常数,a

在连续模型中,这种加速度将速度平滑地降低到零。在您的模型中,您可能正在使用离散时间步长,一些时间t。因此,在每个正常步骤中,速度按加速度乘以步骤时间而减小,a*t。我们还可以计算它并将其分配给某个变量,例如d

出现问题是因为您的离散时间步长可能会超出速度变为零的时刻。为了解决这个问题,您可以使用如下代码:

if (velocity > d)
    velocity -= d; // Resist rightward velocity for a full time step.
else if (velocity < -d)
    velocity += d; // Resist leftward velocity for a full time step.
else
    velocity = 0;  // Resist small velocity until it becomes zero.

当然可以使用其他模型,对于非固体物体有不同的物理特性。一些人在其他答案和评论中提到的一个简单模型是通过乘以小于 1 的值来降低速度。该示例没有模拟拖动实体对象的真实世界物理。它是否适合您的游戏可能是一种审美选择。如果你使用它,你的代码可能很简单:

velocity *= factor;

这样做的一个问题是,某些处理器对于次正规数的性能非常差。最常用的浮点算法 IEEE-754 为经过特殊处理的非常小的数字指定了一个区间(以获得有助于证明和预测行为的某些数学属性)。在没有任何其他变化的情况下,诸如此类的表达式velocity *= factor;将驱动数字越来越小,直到它们达到这个低于正常的区间。在易受攻击的处理器上,这将导致程序的性能突然下降。这当然可能会破坏游戏物理。一些系统设置了一种处理器模式,其中次正规数被转换为零。这避免了性能问题,但违反了 IEEE-754 标准。这对于游戏物理来说可能是可以接受的。

于 2013-05-10T15:04:20.103 回答
1

如果您对模型感到满意(注意注释中的警告),您可以使用符号函数缩短表达式。尽管在 C++ 中选择一个显然有些复杂......

无论您选择哪个,我都会在这里将其称为sgn(). 然后,您希望应用拖动的符号是 的相反符号force.x

objects[i]->force.x += -1 * sgn(objects[i]->force.x) * drag;

(我知道我可以在这里使用一元减号;我认为这使意图更清晰)

于 2013-05-10T14:54:12.903 回答