关于重力,游戏对象与地面之间的碰撞?

15

游戏中的重力如何处理移动物体(例如玩家,怪物或物体)与地面之间的关系? 玩家是否会不断地“掉进”地面并被弹回来?

我发现有两种反应碰撞的方法:将玩家移回到碰撞前的位置,以及在移动前测试新位置是否会导致碰撞,但我不知道这两种方法如何处理需要抬起玩家的上升平台。 我从2D游戏设计的角度看待这个问题,但我想3D游戏设计也会遇到同样的问题。 有什么提示吗? 有哪些参考资料我应该查看? 谢谢。

5个回答

19

您可能想查看GameDev.net的重力常见问题解答以获取一些基本信息。

由于您正在制作游戏而不是高度精确的物理建模,因此我们可以使用欧拉积分。如果您对准确性的需求增加,则我看到使用最多的积分方法是龙格-库塔(RK4)积分。您很可能不需要这些简单的游戏,但它们绝对用于更高级的物理模拟和3D游戏中。使用RK4的缺点是稍微增加了复杂性和略慢。它非常准确,但现在让我们坚持好老的欧拉。

我问了一个类似的问题“如何将重力应用于我的弹跳球游戏”,并得到了几个很好的答案。首先,您需要为游戏选择任意的重力常数。在我的弹跳球应用程序中,我使用默认重力常数为2000px / s。您将希望尝试这种重力常数,以获得特定游戏所需的效果。

接下来,您需要确保独立渲染游戏并更新游戏对象。这是为了防止游戏内物体在快速计算机上移动得非常快,在慢速计算机上移动得非常慢。您希望物体移动的物理和速度与计算机速度无关。有一篇很好的文章介绍了这方面的内容:游戏物理学:修复您的时间步长!
那么我们该怎么做呢?您需要跟踪自上次调用Update方法以来经过的时间。我创建了两个线程,虽然这不是直接必要的。我有一个游戏更新线程和一个渲染线程。更新线程控制更新游戏中物体的位置。更新线程知道上次调用的时间、当前时间,并从中计算自上次更新方法被调用以来经过的时间。
为了应用重力,我们将通过重力常数乘以经过的时间来简单地增加我们对象的Y速度。
private long previousTime = System.currentTimeMillis();
private long currentTime = previousTime;

public void updateGame()
{
    currentTime = System.currentTimeMillis();
    float elapsedSeconds = (currentTime - previousTime) / 1000f; 

    foreach(GameObject gameObject in gameObjects)
    {
        // Apply gravity to velocity vector
        gameObject.velocity.y += (gravityConstant * elapsedSeconds); 

        // Move objects x/y position based off it's velocity vector
        gameObject.position.x += (gameObject.velocity.x * elapsedSeconds); 
        gameObject.position.y += (gameObject.velocity.y * elapsedSeconds);

    }
    
    checkCollisions();

    previousTime = currentTime;
}

那将根据速度向量移动所有对象,并基于重力常数施加重力。最重要的是,它独立于计算机的速度执行!
回答您的另一个问题,是的,对象将不断地在其y向量上受到重力"force"的影响。因此,它将不断与地板碰撞。但是,您想要做的一件事是使用Epsilon值将gameObject的速度最终降为零。然后,在碰撞检测期间作为修剪过程的一部分,通常可以跳过检查非移动物体是否与任何东西发生碰撞(反之亦然!)。
我喜欢用碰撞时找到相互碰撞(相互穿透)的对象,通过它们的最小平移距离(MTD)将它们推开,以使它们分开。这一步很关键,否则您将会在游戏中看到经常出现的物体“粘”在一起,抖动移动。一旦它们分开,我就会计算我的碰撞响应。
使用这种方法,它将在您描述的上升平台场景中正常工作。平台将继续上升,gameObject将使用其与平台之间的MTD自行分离,并自然上升。
如果您需要在碰撞响应方面获得帮助,我建议查看:

我不得不两次打出这个答案,哈哈。肯定有一些Firefox的插件可以防止前进/后退按钮清除字段。非常令人沮丧。 - mmcdole

2
在一些游戏中使用的一种方法是作弊:将行走和空中状态分开。在行走时,游戏引擎可以确定所行走表面的坡度,如果不太陡峭,就会让角色沿着表面方向移动,并使角色相对于表面获得正确的垂直位置。
至于物理学方面,我变成了Gamasutra: Advanced Character Physics中描述的Verlet积分的粉丝。它简化了物理更新方程(不必跟踪速度!),并简化了碰撞(不必调整速度!)。话虽如此,如果需要准确性,它确实有一些细微之处

1

1

我不是专门的游戏程序员,但这是我的理解:

  • 在一个“无限帧率”的理想世界中,您将精确地检测到碰撞发生的时刻,并使用一些标准物理学来模拟碰撞后物体的新速度和加速度(请参阅标准高中力学教科书或各种名为“游戏程序员物理学”的书籍)
  • 实际上,由于您有固定的帧率,因此物体只能以一定的粒度移动,通常需要添加额外的技巧,例如预先计算物体在下一帧上将要行进的相对路径,并查看是否存在任何路径相交
  • 如果它们相交,则交点实际上将是一个估计值,但略微不准确,表示物体真正会发生碰撞的点;然后您可以选择不关心并将该估计作为交点,并进行线性插值以获得碰撞点处的速度,或者现在进行更精确的计算,以获取实际的碰撞点/时间/速度,因为您已经发现它们将相交

1
除了对碰撞进行建模外,一个好的方法是还要对能量(或动量,或速度,这取决于您的仿真复杂程度)的持续传递进行建模。当您的玩家站在一个平台上时,请将该信息存储在代表平台的对象中,每当对象的速度被调整时,您都可以直接将此更改应用于与之链接的玩家或其他物体。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接