2D 平台游戏两个轴的碰撞问题

发布于 2024-08-29 09:07:27 字数 372 浏览 5 评论 0原文

我正在使用 C++ 和 SDL 开发一个小型 2D 平台游戏/格斗游戏,但在碰撞检测方面遇到了很多麻烦。

这些关卡由一系列图块组成,我使用 for 循环来遍历每个图块(我知道这可能不是最好的方法,而且我可能也需要这方面的帮助)。对于角色的每一侧,我将其朝该方向移动一个像素并检查是否发生碰撞(我还检查角色是否朝该方向移动)。如果发生碰撞,我将速度设置为 0 并将玩家移动到图块的边缘。

我的问题是,如果我首先检查水平碰撞,并且玩家每帧垂直移动超过一个像素,它会处理水平碰撞并将角色移动到图块的一侧,即使图块位于下方(或上方)角色。如果我首先处理垂直碰撞,它会执行相同的操作,只是它针对水平轴执行此操作。

如何处理两个轴上的碰撞而不出现这些问题?有没有比我这样做更好的处理碰撞的方法?

I'm working on a little 2D platformer/fighting game with C++ and SDL, and I'm having quite a bit of trouble with the collision detection.

The levels are made up of an array of tiles, and I use a for loop to go through each one (I know it may not be the best way to do it, and I may need help with that too). For each side of the character, I move it one pixel in that direction and check for a collision (I also check to see if the character is moving in that direction). If there is a collision, I set the velocity to 0 and move the player to the edge of the tile.

My problem is that if I check for horizontal collisions first, and the player moves vertically at more than one pixel per frame, it handles the horizontal collision and moves the character to the side of the tile even if the tile is below (or above) the character. If I handle vertical collision first, it does the same, except it does it for the horizontal axis.

How can I handle collisions on both axes without having those problems? Is there any better way to handle collision than how I'm doing it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦途 2024-09-05 09:07:28

是的。基于矢量的碰撞比基于图块的碰撞要好得多。将图块的每个边缘定义为线(有捷径,但暂时忽略它们。)现在要查看是否发生了碰撞,找到最近的水平线和垂直线。如果您取 lastPos.x * LineVector.y - lastPos.y * LineVector.x 的符号并将其与 thisTurnsPos.x * LineVector.y - ThisTurnsPos.y * LinePos.x 进行比较。如果这两个值的符号不同,则说明您已越过了该线。但这不会检查您是否已经越过线段的末端。您可以在相同的 lineVector 和 curPosition 之间形成点积(这里有一点错误,但可能足够好),它要么是负数,要么大于线的大小平方,您不在该线段内,并且没有发生碰撞。

现在这非常复杂,你可能可以通过简单的网格检查来看看你是否已经进入了另一个方块的区域。但!使用向量进行此操作的优点是它解决了移动速度快于碰撞框大小的问题,并且(更重要的是),您可以使用非轴对齐线进行碰撞。该系统适用于任何 2D 矢量(稍微按摩一下,也适用于 3D)。它还允许您相当轻松地沿着碰撞框的边缘滑动角色,因为您已经完成了 99% 所需的数学运算。找到碰撞后您应该所在的位置。

我掩盖了一些实现细节,但我可以说我已经在无数商业视频游戏中使用了上述方法,并且它非常有效。祝你好运!

Yes. Vector based collision will be much better than tile based. Define each edge of a tile as lines (there are short cuts, but ignore them for now.) Now to see if a collision has occured, find the closest horizontal and vertical line. if you take the sign of lastPos.x * LineVector.y - lastPos.y * LineVector.x and compare that with thisTurnsPos.x * LineVector.y - ThisTurnsPos.y * LinePos.x. If the signs of those two values differ, you have crossed that line this tic. This doesn't check if you've crossed the end of a line segment though. You can form a dot product between the same lineVector and your curPosition (a little error here, but good enough probably) and it is either negative or greater than the line's magnitude squared, you aren't within that line segment and no collision has occured.

Now this is farily complex and you could probably get away with a simple grid check to see if you've crossed into another square's area. But! The advantage of doing it with vectors is it solves the moving faster than the size of the collision box problem and (more importantly), you can use non axis aligned lines for your collisions. This system works for any 2D vectors (and with a little massaging, 3D as well.) It also allows you slide your character along the edge of the collision box rather easily as well because you've already done 99% of the math needed to find where you are supposed to be after a collision.

I've glossed over a couple of implementation details, but I can tell that I've used the above method in countless commercial video games and it has worked like a charm. Good Luck!

将军与妓 2024-09-05 09:07:27

XNA 的 2D 平台游戏示例也使用基于图块的碰撞。他们的处理方式非常简单,可能对您有用。以下是对其中内容的简要说明(删除了特定于演示的内容):

  1. 应用移动后,它会检查碰撞。
  2. 它根据玩家的边界框确定玩家重叠的图块。
  3. 它会遍历所有这些图块......
    1. 如果正在检查的图块不合格:
    2. 它确定玩家在 X 轴和 Y 轴上与不可通过的图块重叠的距离
    3. 仅在浅轴上解决了碰撞:
      1. 如果Y是浅轴(abs(overlap.y) < abs(overlap.x)),position.y += Overlap.y;如果 X 是浅轴,同样如此。
      2. 边界框根据位置变化进行更新
    4. 转到下一个图块...

如果您获取代码并希望了解它们具体执行的操作,则位于 HandleCollisions() 函数中的player.cs 中。

XNA's 2D platformer example uses tile-based collision as well. The way they handle it there is pretty simple and may useful for you. Here's a stripped down explanation of what's in there (removing the specific-to-their-demo stuff):

  1. After applying movement, it checks for collisions.
  2. It determines the tiles the player overlaps based on the player's bounding box.
  3. It iterates through all of those tiles...
    1. If the tile being checked isn't passable:
    2. It determines how far on the X and Y axes the player is overlapping the non-passable tile
    3. Collision is resolved only on the shallow axis:
      1. If Y is the shallow axis (abs(overlap.y) < abs(overlap.x)), position.y += overlap.y; likewise if X is the shallow axis.
      2. The bounding box is updated based on the position change
    4. Move on to the next tile...

It's in player.cs in the HandleCollisions() function if you grab the code and want to see what they specifically do there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文