【问题标题】:Surface Detection in 2d Game?二维游戏中的表面检测?
【发布时间】:2011-02-27 18:01:01
【问题描述】:

我正在开发一款 2D 平台游戏,我想知道实现表面(碰撞)检测的最佳(性能方面)方法是什么。

到目前为止,我正在考虑构建一个由线条列表构成的关卡对象列表,并沿着线条绘制图块。

alt text http://img375.imageshack.us/img375/1704/lines.png

我认为每个对象都包含他行走的表面的 ID,以便在上坡/下坡时轻松操纵他的 y 位置。

类似这样的:

//Player/MovableObject class
MoveLeft()
{
    this.Position.Y = Helper.GetSurfaceById(this.SurfaceId).GetYWhenXIs(this.Position.X)
}

所以我用来检测“跌落/在表面上行走”的逻辑是一个简单的点(玩家的小腿)-touches-line(表面)检查 (有一些安全近似值 - 让我们说线上 1-2 个像素)。

这种方法可以吗? 我一直难以找到有关此问题的阅读材料,因此请随时删除链接/建议。

【问题讨论】:

    标签: xna 2d collision


    【解决方案1】:

    长期使用基于多边形的 2D 平台游戏,让我给你一些建议:

    制作基于图块的平台游戏。

    现在,直接回答您关于碰撞检测的问题:

    您需要使您的世界几何体“实心”(您可以将玩家对象设为一个点,但将其设为实心更好)。我所说的“实心”是指 - 您需要检测玩家对象是否与您的世界几何体相交

    我尝试过“玩家是否跨越了这个世界几何体的边缘”,但实际上是行不通的(即使它似乎在纸上可行——浮点精度问题并不是您唯一的问题)。

    网上有很多关于如何在各种形状之间进行交叉测试的说明。如果您刚刚开始,我建议您使用 Axis-Aligned Bounding Box (AABB)。

    制作一个基于图块的平台游戏比制作任意几何形状的平台游戏要容易得多、得多、得多、。所以从瓷砖开始,检测与 AABB 的交叉点,然后一旦你开始工作,你就可以添加其他形状(例如斜坡)。

    一旦检测到交叉路口,就必须执行碰撞响应。同样,基于图块的平台游戏是最简单的 - 只需将玩家移动到被碰撞的图块之外(你是移动到它上面还是移动到一边? - 这将取决于碰撞 - 我将离开如何做到这一点练习)。

    (PS:您可以仅使用方形图块获得极好的结果 - 例如,看看 Knytt Stories。)

    【讨论】:

      【解决方案2】:

      在 XNA 的Platformer Starter Kit 项目中查看它是如何完成的。基本上,瓷砖有枚举来确定瓷砖是否可以通过,不可通过等,然后在你的水平上,你 GetBounds 的瓷砖,然后检查与玩家的交叉点并确定要做什么。

      【讨论】:

      • 谢谢迈克,会继续努力的。我很好奇它如何处理旋转的对象。
      【解决方案3】:

      我在处理 2D 碰撞检测方面玩得很开心。如果您不提前计划,看似简单的问题很容易变成一场噩梦。

      在 OO 意义上做到这一点的最佳方法是创建一个通用对象,例如类映射对象。这有一个位置坐标和斜率。由此,您可以将其扩展为包含其他形状等。

      由此,让我们来处理与 Solid 对象的碰撞。假设只有一个方块,比如 32x32,您可以从左、右、上和下击中它。或者,根据您的编码方式,同时从顶部和左侧击中它。那么你如何确定角色应该走哪条路呢?例如,如果角色从顶部撞到方块,要站立,编码错误,您可能会无意中将角色推到一边。

      那么,你应该怎么做?我为 2D 游戏所做的事情是,在决定如何对碰撞做出反应之前,我查看了该人的先前位置。如果角色的 Y 位置 + 高度在方块上方并向西移动,那么我会先检查顶部碰撞,然后再检查左侧碰撞。但是,如果角色的 Y 位置 + 高度低于块的顶部,我会检查左侧碰撞。

      现在假设您有一个有坡度的块。块宽 32 像素,高 32 像素,x=32,高 0 像素,x=0。 有了这个,你必须假设角色只能从顶部撞到这个块才能站立。有了这个块,如果它是左/右/下,你可以返回一个 FALSE 碰撞碰撞,但如果是从顶部碰撞,则可以声明如果角色在 X=0,则返回碰撞点 Y=0。如果 X=16,Y=16 等等

      当然,这都是相对的。您将检查多个块,因此您应该将角色方向的所有可能更改存储到临时变量中。因此,如果字符在 X 方向上与块重叠 5,则从该变量中减去 5。累积 X 和 Y 方向上所有可能的变化,将它们应用到角色的当前位置,并在下一帧将它们重置为 0。

      祝你好运。稍后我可以提供更多示例,但我在我的 Mac 上(我的代码在 WinPC 上) 这与经典的《洛克人》游戏 IIRC 中使用的碰撞检测类型相同。这也是一个视频:http://www.youtube.com/watch?v=uKQM8vCNUTM

      【讨论】:

        【解决方案4】:

        您可以尝试使用其中一种物理引擎,例如 Box2DChipmunk。他们拥有自己先进的碰撞检测系统和许多不同的奖励。当然,它们不会加速您的游戏,但它们适用于任何现代设备上的大多数游戏

        【讨论】:

          【解决方案5】:

          创建自己的碰撞检测算法并不容易。一个简单的困难示例是:如果您的角色以足够高的速度移动,以至于在两帧之间它将从一条线的一侧移动到另一侧怎么办?这样您的算法就没有时间在两者之间运行,并且永远不会检测到碰撞。

          我同意 Tiendil:使用库!

          【讨论】:

          • w00t?您检查两个对象是否相交,而不是对象边界是否与另一个对象“碰撞”。
          • 如果物体的移动速度足够快以至于它们的每帧速度大于它们的宽度,那么对于你的天真的碰撞检测算法来说,永远不会发生碰撞。
          • +1 同意正确行事非常具有挑战性。我有一个小项目,涉及汽车在高速公路上的车道行驶,即使在有限的情况下,当汽车想要改变时,只需要检查同一车道和下一车道的前车和后车的位置车道上,有无数难以调试的错误,只是在非常特定的情况下偶尔出现。我个人没有看过这些库中的任何一个,但如果我要开发一个合适的碰撞检测系统,我绝对至少会先阅读现有的库。
          • 好吧,在这种情况下,你是对的。对不起,我第一次没有理解你的答案......顺便说一句。那么计算对象移动的向量呢?
          • 也许检查由先前和当前位置形成的线是否与表面线相交+移动方向是向下的。然后下落停止,物体开始站立在表面上。
          【解决方案6】:

          我推荐Farseer Physics。这是一个强大而强大的物理引擎,应该能够处理您需要的任何事情!

          【讨论】:

          • 感谢 RCIX,但 IMO its too much for what im 试图实现。
          【解决方案7】:

          我会这样做:

          1. 严格禁止碰撞线。只有实体形状(盒子和三角形,也许是球体)
          2. 2D BSP、2D 分区以存储所有级别形状,或“扫描和修剪”算法。每一个都将非常强大。 Sweep 和 prune 与插入排序相结合,可以轻松地处理数千个可能发生碰撞的对象(如果不是数十万个),并且 2D 空间分区将允许根据需要快速获取附近所有可能发生碰撞的形状。

          让物体在表面上行走的最简单的方法是让每帧然后下降几个像素,然后获取物体碰撞的表面列表,并将物体移动到表面法线的方向。在 2d 中,它是一条垂线。这种方法会导致对象在非水平表面上向下滑动,但您可以通过稍微改变法线来解决此问题。 此外,您必须每帧多次运行碰撞检测和“将对象推开”例程,而不仅仅是一次。这是为了处理对象在堆中或它们接触多个表面的情况。

          【讨论】:

            【解决方案8】:

            我使用了一种有限的碰撞检测方法,它在非常不同的基础上工作,所以我会把它扔在这里以防万一:

            黑白的次要图像。无法通过的像素是白色的。构造一个字符的掩码,它只是当前设置的任何像素。要评估预期的移动,请从次要图像中读取该蒙版的像素,看看是否有白色的像素回来。

            要检测与其他对象的碰撞,请使用相同类型的方法,但不是使用布尔值,而是使用足够的深度来覆盖所有可能的对象。完全以其对象编号的“颜色”将每个对象绘制到辅助对象。当您阅读蒙版并获得一个非零像素时,“颜色”就是您点击的对象编号。

            这可以在 O(n) 时间内解决所有可能的冲突,而不是计算交互的 O(n^2)。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-10-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多