对于相同的SKPhysicsBody,多次调用didBeginContact

时间:2015-01-15 04:04:08

标签: ios swift sprite-kit skphysicsbody

 func didBeginContact(contact: SKPhysicsContact) {
    if ( contact.bodyA.categoryBitMask & BodyType.shield.rawValue ) == BodyType.shield.rawValue  {
        contact.bodyB.node?.removeFromParent()
        counter++
        println(counter)


    } else if ( contact.bodyB.categoryBitMask & BodyType.shield.rawValue ) == BodyType.shield.rawValue {
        contact.bodyA.node?.removeFromParent()
        counter++
        println(counter)
    }
}

一个物理体来自纹理shield.physicsBody = SKPhysicsBody(texture: shieldTexture, size: shieldTexture.size())

另一个来自圈子sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2)

当拖曳物体彼此接触时,有时会多次调用sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2) {{1}}。我如何得到它只为每个对象调用一次,即使我一接触它就从父对象中删除它。

6 个答案:

答案 0 :(得分:2)

我已经想出如何让func didBeginContact(contact: SKPhysicsContact)只被调用一次。这允许具有纹理SKPhysicsBody(texture: size:)的物理体一旦计算碰撞,即使在现实中(由于纹理的物理体的性质),这个函数将被多次调用。

第1步:

为SKSpriteNode创建一个名称属性(我们将在本例中使用ball) 并将其设置为唯一名称。我们可以通过创建一个int

来做到这一点
var number = 0 

ball.name = "ball \(number)"

这允许创建对象的唯一名称evertime。

第2步:

创建一个数组来保存它们,将球附加到数组,增加数字

    var array: [String] = []
    var number = 0 

ball.name = "ball \(number)" 
array.append(ball.name!)
number ++

步骤3:现在在func didBeginContact(contact: SKPhysicsContact)中查明名称是否在数组中。如果它是增加分数,则删除节点,并从阵列中删除名称。如果名称不在数组中则不做任何事情。

从数组中删除名称使我们现在只能对函数调用进行一次计数。

func didBeginContact(contact: SKPhysicsContact) {
    if ( contact.bodyA.categoryBitMask & BodyType.shield.rawValue ) == BodyType.shield.rawValue  {
        var name = contact.bodyB.node?.name!
        let index = find(array, name!)

        if contains(array, name!) {
            score++
            contact.bodyB.node?.removeFromParent()
            array.removeAtIndex(index!)
        }
    } 
}

答案 1 :(得分:2)

在这种情况下,您可以在没有数组的情况下使其工作。而不是:

contact.bodyA.node?.removeFromParent()
counter++

使用类似的东西:

if let node = contact.bodyA.node as? SKSpriteNode {
    if node.parent != nil {
        node.removeFromParent()
        counter++
    }
}

在第一次联系时,从父项中删除节点,在后续调用中,将跳过if语句中的代码。

答案 2 :(得分:2)

使用基于纹理的物理物体时,该问题似乎更经常发生。我的解决方法是,如果在先前的碰撞触发器中指示了相同的“ contact.bodyA.node”,则禁止“ didBegin(_ contact:SKPhysicsContact)”继续。即:

if lastNodeA != contact.bodyA.node {
    lastNodeA = contact.bodyA.node
    ...

答案 3 :(得分:1)

如果您使用contactbitmask来确定要捕获的碰撞,那么这是一个非常简单的解决方案。

只需将您不想重复检测到的对象的categoryBitMask更新为未使用的新值,以便系统执行此操作。不再考虑后续的函数调用。

答案 4 :(得分:0)

LearnCocos2D是正确的,只要两个物体的SKphysics体接触,SKPhysicsbody didBeginContact就会连续调用,因为我们在var中允许的形状可以有多种形式和形状。

对于那些只需要检测一次的人,我们只需要使用布尔值作为标志来检查检测是否已完成并完成。

我是这样做的:

  1. 声明var contactDone = Bool() 布尔值:

    didMoveToView
  2. 在程序开始时(例如,contactDone = false 以下)

    初始化它
    didBeginContact
  3. 检查func didBeginContact(contact:SKPhysicsBody){ if((contact.bodyA.categoryBitMask) == scoreCategory || (contact.bodyB.categoryBitMask) == scoreCategory){ if (contactDone == false){ // Increment score score++ // Set flag to disable multiple calls by checking in didEndContact contactDone = true } } }

    didEndContact
  4. 清除该标记,让它再次在func didEndContact(contact: SKPhysicsContact) { if((contact.bodyA.categoryBitMask) == scoreCategory || (contact.bodyB.categoryBitMask) == scoreCategory){ if(contactDone == true){ contactDone = false } } } 中检查:

    SKPhysicBody(circleOfRadius: object.size.height/2)
  5. 就像我使用0F 84 FF 00 00 00时一样。

答案 5 :(得分:0)

我的解决方案是通过Date()。timeIntervalSince1970花费时间 联系了didBegin

let passedTime = Date().timeIntervalSince1970 - lastContactTime

lastContactTime = Date().timeIntervalSince1970

if passedTime < 0.01 {
  // same object
  return
}