【问题标题】:Block world collision detection阻止世界碰撞检测
【发布时间】:2012-04-03 23:30:24
【问题描述】:

我目前正在 XNA 中开发块世界引擎,但无法让碰撞检测和处理正常工作。世界位于一个以 ( z * width * width + y * width + x ) 为索引的数组中,并包含由字节表示的不同块。一切都很好,花花公子。或者我是这么想的。

我尝试了不同的碰撞处理技术,我目前正在使用计算玩家/相机方向的版本,在将其添加到位置之前,我用半个矢量检查每个单独的向量(x、y 和 z)单位偏移(以补偿 1.0 的块大小)相对于世界,并且仅在结果为零时应用它。到目前为止,一切都很好。现在,当我直接走进一个角落时,问题就出现了,因为 x 轴和 z 轴直到我进入立方体后才会相交/碰撞。

那么我该如何正确计算方块世界中的碰撞检测和处理呢?

我真的很想就此事提供一些意见,最好是更高/概念级别的意见,但当然也欢迎代码示例。



为了进一步解释我的情况,根据@A-Type 的回复:

所以,让我们在这里更准确地帮助我理解你。我的角色在各个方向都只有一个单位,这应该会让事情变得更容易。

首先,你认为我应该先更新我的角色位置,然后再检查碰撞吗?这将是我进行碰撞检测的首选方式,但如果它更容易,我会先检查并在可能的情况下稍后移动。

好吧,我知道玩家只能与 8 个立方体相交(在您的示例中为 12),并且舍入似乎也是一个非常好的主意,但我不太清楚 12 个立方体的过渡(再次在你的例子,我的应该是 8) 到只有 3。这会不会导致同样的问题,即不考虑角色立方体的角?

我曾尝试实现这一点但失败了,所以我认为更多的理论可能会做到这一点。 (我实际上已经让碰撞检测工作了,但在那些情况下,我完全失去了我的速度,而不仅仅是在碰撞方向上。)



谢谢你的时间! 卡尔

【问题讨论】:

    标签: xna collision


    【解决方案1】:

    好吧,让我们再试一次。在任何有效的系统中,碰撞检测都有两个基本阶段。有宽相位和窄相位,如果你愿意的话。 Wide-phase 使用不准确但廉价的方法来确定两个对象是否可以相交,并将它们传递到narrow-phase。 Narrow-phase 采用我们的两个候选对象并应用更复杂的物理来调解碰撞。

    对于基于网格的世界,我们有一个非常简单且有利的宽相位碰撞方法。这就是网格本身。我们可以使用玩家的位置和大小来确定他可能相交的 8 个方块(从现在开始我们将使用您的案例)。请注意,在我最初的答案中,我似乎在谈论将其缩小到 3 个块——我让它比它需要的更复杂,尤其是对于 1 个块的字符。最简单的方法是:将角色的中心圆到网格的,即8个方块的角相交的地方。然后选择这 8 个块进行窄相测试。请务必使用中点舍入,而不是使用整数时默认的下舍入。即,如果值为 1.53,则应舍入为 2,而 1.49999 应舍入为 1。

    现在,狭窄的阶段我并没有真正涵盖太多。你问是先搬还是后搬,我觉得你需要先搬。我不是物理模拟大师,但我知道您首先要计算碰撞方向(字符中心减去块中心)。深度是这个向量的长度。如果您的块是 1 宽,那么您不希望该长度小于 1;这表明它们是相交的(基本上有点)。

    现在,有很多方法可以从碰撞中“恢复”对象。我建议确定对象在哪个轴上碰撞最少。也就是说,如果您的碰撞方向向量的 X 分量最小,则意味着您的玩家最接近在 X 方向上的碰撞out。在该方向上施加与 X 方向上的碰撞深度成比例的反作用力。或者,如果您选择,只需将角色的位置设置为您想要离开的距离,而不要打扰力量。但是您只想将角色朝一个主要方向移动。这使事情变得更简单,并且不会阻碍沿地面或沿墙壁的移动。

    这样想:假设您的角色每一帧都因重力而落入地面 0.3。现在,假设当他落入这个框架时,他位于街区的中心。这意味着他与下方方块的碰撞深度为 (0.5, 0.3, 0.5)(其中 X 为侧向,Y 为向上,Z 为向前)。如果您在所有这些方向上施加恢复力,您将让玩家向左、向后和在地面上方移动。最后一点是你唯一想做的部分。因此,忽略较大的碰撞轴,仅在较小的 (Y) 轴上恢复。现在你的角色的水平移动不受阻碍,他停留在地面上。

    【讨论】:

    • 好了。现在我明白了,它工作正常。以前我并没有真正理解宽相和窄相的结合,但现在一切都清楚了。也许我可以做一些更有效的事情,但它就像我想要的那样工作,所以我会让它一段时间。非常感谢 A-Type,并祝你在 Gravitas 项目上好运。至少可以说它看起来很有希望。 :)
    【解决方案2】:

    利用您的世界格式创建比检查每个块更有效的碰撞算法。

    假设您的块有一个 3D 字节数组,其中 0 是一个空白空间,我强烈建议您将玩家的位置四舍五入到您世界中的一组网格空间,并检查是否有任何这些空间不为 0。然后针对非空块执行碰撞处理代码。

    例如,如果您的角色的高度为 2,宽度/深度为 1(就像 Minecraft 中的史蒂夫),他最多可以同时与 12 个网格空间相交(4 个在他的头上方,4 个在他的腰部,4 个在他的下方英尺),至少 2 英尺(如果他与网格完全对齐)。

    将角色的主体翻译成网格术语。将字符的位置四舍五入到一个网格单元格,然后检查它周围的 12 个空格(如果他是 2x1)。如果有任何不为空,请在这些块和您的角色之间执行碰撞解决。您检查哪些相邻块取决于您四舍五入的方向。例如,如果您的角色的位置是 (3.4, 2.7, 1.1),您可以将其四舍五入为 (3, 3, 1),然后检查哪些块大于 1 X 方向,Y 方向 1 LESS,Z 方向 1 GREATER,因为您分别将 DOWN、UP 和 DOWN 四舍五入。

    我希望这也许是可以理解的。如果没有,请发表评论。我不知道具体为什么,但我似乎无法按照我应该的方式解释这个概念,尤其是因为我已经做了近一年的此类事情了。

    【讨论】:

    • 非常感谢@A-Type!非常抱歉没有早点确认您的回答,但事情一直很忙。我在这里很新,但弹出窗口告诉我编辑我的原始问题,所以我们开始吧。
    猜你喜欢
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    • 2014-02-04
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多