【问题标题】:Collision reaction in a 2D side-scroller game similar to "Mario"类似于“马里奥”的 2D 横向卷轴游戏中的碰撞反应
【发布时间】:2021-04-04 00:20:23
【问题描述】:

在过去的几周里,这一直困扰着我。在这段时间里,我一直在网上研究,甚至在 Borders 的计算机部分阅读书籍试图找到答案,但我没有太多运气。

我为横向卷轴视频游戏编写了一个 2D 关卡编辑器。现在我想把它变成一个游戏,我有一个可以跑跳来探索关卡的玩家,类似于“马里奥”。

真正给我带来麻烦的是碰撞响应(不是检测:我已经知道如何判断两个块是否正在碰撞)。以下是我将要说明的一些场景,以便您了解我的问题(阴影块是地面,箭头是玩家的速度矢量,虚线是玩家的投影路径)。

查看此碰撞响应场景图片:

http://dl.dropbox.com/u/12556943/collision_detection.jpg

假设场景 (1) 和 (2) 中的速度向量相等(方向和大小相同)。然而,在场景 (1) 中,玩家正在撞到块的侧面,而在场景 (2) 中,玩家正在降落在块的顶部。这让我得出结论,确定碰撞响应不仅取决于玩家的速度矢量,还取决于玩家与碰撞块的相对位置。这引出了我的第一个问题:知道玩家的速度向量和相对位置,我如何确定玩家从哪个方向(左侧、右侧、顶部或底部)与块碰撞?

我遇到的另一个问题是,如果玩家与同一帧中的多个块发生碰撞,如何确定碰撞响应。例如,假设在场景 (3) 中,玩家同时与这两个块发生碰撞。我假设我将不得不遍历玩家正在碰撞的每个方块,并相应地调整每个方块的反应。总结一下,这是我的第二个问题:如果玩家与多个方块发生碰撞,我该如何处理碰撞响应?

请注意,我从未透露我正在使用的编程语言;这是因为我希望你不知道(虽然不是私人的:])。我对伪代码比查看特定语言的代码更感兴趣。

谢谢!

【问题讨论】:

  • 您是否使用基于图块的世界(类似于 2D 马里奥游戏)?你的形象让我相信你是,但我不确定。
  • 是的,我有一个二维数组,用于存储关卡中每个块的类型。

标签: 2d collision-detection game-engine


【解决方案1】:

我认为XNA's example platform game 处理冲突的方式可能对您很有效。我将这个答案发布到了一个非常相似的问题elsewhere on Stack Overflow,但也会在这里转发。

  1. 应用移动后,检查并解决碰撞。
  2. 根据玩家的边界框确定玩家重叠的图块。
  3. 执行以下操作遍历所有这些图块:(通常不会很多,除非您的玩家与您的世界图块相比很大)
    1. 如果正在检查的图块无法通过:
      1. 确定玩家在 X 轴和 Y 轴上与不可通过的图块重叠的距离
      2. 通过将玩家移出该图块来解决碰撞仅在浅轴上(无论哪个轴穿透最少)
        • 例如,如果 Y 是浅轴并且碰撞在下方,则将播放器向上移动以不再与该图块重叠。
        • 类似这样的东西:if(abs(overlap.y) < abs(overlap.x)) { position.y += overlap.y; } else { position.x += overlap.x; }
      3. 根据玩家的新位置更新边界框的位置
      4. 转到下一个图块...
    2. 如果正在检查的图块可以通过的,则什么也不做
  4. 如果解决碰撞可能会使玩家进入另一个碰撞,您可能需要再次运行上述算法。或者重新设计你的关卡。

此逻辑的 XNA 版本位于 player.cs 中的 HandleCollisions() 函数中,如果您有兴趣获取他们的代码以查看他们在那里具体做了什么。

【讨论】:

  • 如果您的玩家站在 2 个街区的顶部怎么办。如图所示:i.gyazo.com/01d4258366e7353492b78af9bbb97b11.png 这样的情况可能会导致玩家被侧身移动。这不是您可能想要的行为。
  • @Oli414 您的示例的常见简单解决方案是通过仅在 x 轴方向上移动您的实体来修改上述内容,水平解决碰撞,然后仅在 y 轴方向上重复上述操作(反之亦然)。
【解决方案2】:

因此,让这变得更棘手的是不断调整玩家位置的重力。如果你的玩家跳到了一个街区的顶部,他们不应该反弹,他们应该降落在街区的顶部并停留在那里。然而,如果玩家在左侧或右侧击中一个方块,他们不应该只是呆在那里,重力必须将他们拉下来。我认为这大致是您的问题。

我认为您需要将重力和玩家速度这两种力与碰撞检测/响应算法分开。如果玩家与方块发生碰撞,无论方向如何,都使用玩家的速度,只需将玩家的位置移动到碰撞边缘,然后从玩家的速度中减去相等和相反的向量,因为不这样做会导致他们再次与目的。您将需要计算交点并将玩家的位置放置在块上。

在旁注中,您可以通过玩家碰撞哪种类型的障碍物来改变真正大的力量,从而允许有趣的反应,例如如果玩家跑得足够快(即玩家的速度>而不是力量)就可以突破障碍物块)

然后继续对玩家的位置施加恒力重力,并继续进行正常计算以确定玩家是否已到达地板。

我认为通过将这两个概念分开,您就有了一个非常简单的直接碰撞响应算法,并且您有一个相当简单的重力地板算法。这样你就可以改变重力而不必重做你的碰撞响应算法。比如说水位、空间位等,碰撞检测响应都是一样的。

【讨论】:

    【解决方案3】:

    最近想了很久。

    我正在使用分离轴定理,因此如果我检测到碰撞,我会继续将对象投影到归一化速度矢量上,并在负速度矢量的方向上移动该距离。假设对象来自安全的地方,此解决方案将在碰撞后将对象定位在安全的地方。

    可能不是您想要得到的答案,但希望它能为您指明正确的方向?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多