15

重力游戏如何处理玩家、怪物或物体等移动物体与地板之间的关系?球员是否经常“落入”地板并被弹起来?

我发现对碰撞做出反应的两种方法是将玩家移回碰撞前的先前位置,并在移动之前测试新位置以查看是否会导致碰撞,但我不知道其中任何一个如何可以处理一个向上上升的平台,需要能够抬起玩家。我从 2D 游戏设计的角度来看这个问题,但我想同样的问题也会出现在 3D 游戏设计中。有什么提示吗?我应该查看任何参考资料吗?谢谢。

4

5 回答 5

18

您可能想查看GameDev.net 的 Gravity 常见问题以了解一些基本信息。

由于您正在制作游戏而不是高度精确的物理建模器,因此我们可以进行欧拉积分。如果您对准确性的需求增加,我看到使用的最流行的集成方法是Runge-Kutta (RK4) 集成。对于简单的游戏,您很可能不需要这些,但它们肯定用于更高级的物理模拟和 3D 游戏。使用 RK4 的缺点是稍微增加了复杂性并且稍微慢了一点。虽然它非常准确,但现在,让我们坚持使用好的 ole Euler。

我问了一个类似的问题,“我如何在弹跳球比赛中应用重力”,并得到了几个很好的答案。你要做的第一件事是为你的游戏选择一个任意的重力常数。在我的弹跳球应用程序中,我使用 2000px/s 的默认重力常数。您需要使用此重力常数来获得特定游戏所需的效果。

接下来,您要确保您正在渲染您的游戏并独立更新您的游戏对象。这是为了防止您的游戏内对象在快速计算机上移动得非常快,而在慢速计算机上移动得慢。您希望对象移动的物理特性和速度独立于计算机速度。一篇关于这方面的好文章是游戏物理:修正你的时间步长!.

那么我们该怎么做呢?您可以跟踪自上次调用 Update 方法以来已经过去了多少时间。我创建了 2 个线程,尽管它不是直接必需的。我有一个游戏更新线程和一个渲染线程。更新线程控制更新游戏对象的位置。更新线程知道它之前被调用的时间、当前时间,并从中计算自调用更新方法以来经过的时间。

为了应用重力,我们只需将我们的重力常数乘以经过的时间加到物体的 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 向量上会不断地具有重力“力”。所以它会不断地与地板发生碰撞。但是,您想要做的一件事是使用Epsilon 值最终使您的游戏对象的速度为零。然后,在作为修剪过程的一部分的碰撞检测期间,您通常可以跳过检查非移动物体是否与任何物体发生碰撞(反之亦然!)。

我喜欢对碰撞做的事情是,一旦我发现物体发生碰撞(相互穿透),我会将它们分开的最小平移距离(MTD)将它们分开。这一步很关键,否则你会得到游戏中常见的错误,即物体“卡”在一起抖动移动。一旦它们分开,我就会计算我的碰撞响应。

使用这种方法,它将在您描述的上升平台场景中正常工作。平台会继续上升,游戏对象会使用自身与平台之间的MTD将自己分开,它自然会随之上升。

如果您在碰撞响应方面需要帮助,我建议您查看:

于 2009-01-13T02:26:01.773 回答
2

在某些游戏中使用的一种方法是作弊:为行走和在空中设置单独的状态。在行走时,游戏引擎可以确定所走过的表面的坡度,如果不是太陡,则沿表面方向移动角色,并为角色提供相对于表面的适当垂直位置。

至于物理学,我正在成为Gamasutra: Advanced Character Physics中描述的 verlet 集成的粉丝。它简化了物理更新方程(不必跟踪速度!),它简化了碰撞(不必调整速度!)。也就是说,如果您需要准确性,它确实有一些细微差别。

于 2009-01-13T03:43:13.677 回答
1

关于这个主题的最完整的教科书之一是Christer Ericson的Realtime Collision Detection。他也有一个同伴博客。Eric Lengyel 的3D 游戏编程和计算机图形学数学也很有用。

于 2009-01-13T01:30:47.937 回答
1

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

  • 在具有“无限帧速率”的理想世界中,您会在碰撞发生的那一刻准确地检测到碰撞,并使用一些标准物理学来模拟碰撞后物体的新速度和加速度(参见标准高学校力学教科书,或各种题为“游戏程序员物理学”之类的书籍)
  • 实际上,因为你有一个固定的帧速率,因此物体只能以一定的粒度移动,你通常需要添加一个额外的技巧,比如提前计算物体在下一帧中移动的相对路径,看看是否有任何路径相交
  • 如果它们确实相交,那么相交点实际上将是对物体真正碰撞的点的估计,但稍微不准确;然后,您可以选择不关心并将该估计值作为交点并进行线性插值以获得碰撞点的速度,或者现在您已经发现它们将相交进行更精确的计算以获得实际碰撞点/时间/速度
于 2009-01-13T01:37:31.793 回答
1

除了模拟碰撞之外,一个好的方法是模拟能量的持续传递(或动量,或只是速度,取决于模拟的复杂性)。当您的玩家站在平台上时,将该信息存储在代表平台的对象中,并且任何时候调整对象的速度,您都可以直接将该更改应用到如此链接的玩家或其他对象。

于 2009-01-13T02:22:21.437 回答