【问题标题】:SpriteKit: detect complete node overlapSpriteKit:检测完整的节点重叠
【发布时间】:2014-06-25 15:13:31
【问题描述】:

我有两个 SKShapeNode——一个具有基于边缘的 SKPhysicsBody,一个基于体积——我想检测它们的交叉点而不发生碰撞。我的工作正常,当一个人经过另一个人时调用 SKPhysicsContactDelegate 联系方法,但我的问题是当 edges 不再相交时,didEndContact 被调用,即使一个身体是完全包含在他者之中。确定真正接触或重叠的最佳方法是什么,而不仅仅是边缘相交?我试过usesPreciseCollisionDetection,没用。

【问题讨论】:

  • 如何添加一个 alpha 为 0 的孩子并将其用作逻辑检查的一部分?你不会看到它,但它会一直发生碰撞......并且在你的 didBeginContact 中你应该尝试一个 switch 语句,你可以在那里告诉哪些对象正在碰撞而不是计算所有的触摸。

标签: ios sprite-kit skphysicsbody sknode


【解决方案1】:
CGPoint locObj1 = [sprite1 locationInNode:self];
CGPoint locObj2 = [sprite2 locationInNode:self];

if([sprite1 containsPoint: locObj2]) return;
if([sprite2 containsPoint: locObj1]) return;

将此添加到 didBeginContact 和 didEndContact 的开头。这将检查其中一个节点是否包含另一个节点。如果是这样,它不会做任何事情来缓解你的 didBeginContact 和 didEndContact 被不必要地调用的问题。我不在我的 Mac 上,所以您可能需要稍微使用一下语法。希望这会让您朝着正确的方向前进。

【讨论】:

  • 感谢您的建议!从文档中看起来像containsPoint“返回一个布尔值,指示一个点是否位于节点的边界框内。”我担心这对于我的用例可能不够准确(即仅测试可能基于边缘的凹形物体的边界框)。不过,我找不到比 containsPoint 更严格的替代方案。
  • 你的一个节点是否必须有一个基于边缘的物理体?
  • 是的——不幸的是,基于体积的物体看起来需要定义为凸多边形,而我正在使用的形状有时可能是凹的。
  • 您所处的困境非常有趣。我将继续寻找解决方案,因为我不认为 SpriteKit 应该/不会受到这样的限制。我认为 spriteKit 社区应该对这篇文章产生更多的兴趣,并且可能有人会通过......一个自定义的 containsPoint 来满足您的凸形要求。
  • 我一直在试验这个,我认为文档是错误的! containsPoint 似乎适用于凸多边形(至少在我的上下文中,并且使用 iOS 8),但我还需要考虑另一个复杂性。我会对此表示赞成,然后为遇到此问题的其他人发布更完整的答案。
【解决方案2】:

作为meisenman suggested,看起来最好的方法是使用containsPoint 方法来确定真正的节点重叠。文档声明这“返回一个布尔值,指示一个点是否位于节点的边界框内”,但在我的实验中,它看起来也适用于基于凹边的形状。

因此,如果我想检测两个对象何时不再重叠,那么在didEndContact 内进行containsPoint 检查是有意义的——但事实证明,当每个边不再相交时会调用didEndContact,即使相同形状的另一条边仍然与同一个对象相交。例如,一个球通过它的角离开一个矩形将产生 两个 didEndContact 事件。因此,有必要保留接触事件的绝对计数(开始和结束之间的差异),并且仅在该计数为零时才测试遏制。

我的解决方案,在 Swift 中:

var _contactCount = 0

func didBeginContact(contact: SKPhysicsContact!) {
  if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
    if (_contactCount == 0) {
      // Contact is actually beginning
    }
    _contactCount += 1
  }
}

func didEndContact(contact: SKPhysicsContact!) {
  if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
    _contactCount -= 1
    let overlap = contact.bodyA.node.containsPoint(contact.bodyB.node.position) || contact.bodyB.node.containsPoint(contact.bodyA.node.position)
    if (!overlap && _contactCount == 0) {
      // Contact is actually ending
    }
  }
}

【讨论】:

  • 干得好!很高兴您找到了完整的答案!
【解决方案3】:

这些是我对#meisenman swift 3 示例的想法。假设我们想知道节点是否在节点内,而不是通过掩码进行碰撞检测。使用#meisenman,每个节点的位置都被使用。

下面这张图片是我们真正想要做的。

#meisenman 使用的代码不需要 SKPhysics。这是 Swift 3.0 中的代码

let Object_1: CGPoint! = Sprite_Object_1.position
//this obtains the location of the sprite node, through CGPoint.
if Object_Sprite_2.contains(Object_1){
    print("Then it is true, object 2 is within the location of object 1")
}

我发现的唯一限制是,如果这些节点的中心不在所需节点的主体内,那么这个 if 语句将不成立。这尚未通过设置节点的主体定义(掩码)进行测试。

我喜欢的是能够在不同的函数或覆盖函数中使用这个 if 语句,这不仅限于“开始”或“触摸移动”。

【讨论】:

  • 另请注意 - 对象 3 显示了此替代方法的局限性示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多