didBeginContact вызывается несколько раз для одной и той же 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) вызывается несколько раз. Как заставить его вызываться только один раз для каждого объекта, даже если я удаляю его из родительского объекта, как только он связывается.

5 ответов

В этом случае вы можете заставить его работать без массива. Вместо этого:

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

Используйте что-то вроде этого:

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

При первом контакте вы удаляете узел из родительского, при последующих вызовах код в операторе if будет пропущен.

Проблема возникает чаще, когда используются физические тела на основе текстур. Я обошел это так, чтобы запретить "didBegin(_ contact: SKPhysicsContact)" продолжать работу, если тот же "contact.bodyA.node" был указан в предыдущем триггере столкновения. то есть:

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

Есть очень простое решение, если вы используете contactbitmask определить, какие столкновения захватить.

просто обновите categoryBitMask объекта, который вы не хотите повторно обнаруживать, с новым значением, которое не используется, поэтому система больше не считает последующие вызовы функций релевантными.

Я понял, как получить func didBeginContact(contact: SKPhysicsContact) быть вызванным только один раз. Это позволяет физике тел с текстурой SKPhysicsBody(texture: size:) для подсчета столкновений один раз, хотя в реальности (из-за природы физического тела текстуры) эта функция будет вызываться несколько раз.

Шаг 1:

Создайте свойство name для SKSpriteNode (в этом примере мы будем использовать ball) и установите его равным уникальному имени. Мы можем сделать это, создав инт

var number = 0 

ball.name = "ball \(number)"

Это позволяет уникальное имя, когда объект создается.

Шаг 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!)
        }
    } 
}

Мое решение - взять время через Date(). TimeIntervalSince1970 в контакте didBegin

let passedTime = Date().timeIntervalSince1970 - lastContactTime

lastContactTime = Date().timeIntervalSince1970

if passedTime < 0.01 {
  // same object
  return
}

LearnCocos2D прав, SKPhysicsbody didBeginContact будет вызывать непрерывно, пока SKphysicsbody двух объектов находится в контакте, потому что форма, которую мы допустили в SKPhysicsBody(texture:xxx, size:xx) может прийти в нескольких формах и формах.

Для тех, кому нужно его обнаружение только один раз, нам просто нужно использовать логический флаг в качестве флага, чтобы проверить, выполнено ли обнаружение и завершено ли оно.

Вот как я это делаю:

  1. Объявить var логическое значение:

    var contactDone = Bool()
    
  2. Инициализируйте его при запуске программы (например, ниже didMoveToView)

    contactDone = false
    
  3. Сделать проверку в didBeginContact:

    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
    
          }
    }
    }
    
  4. Снимите флажок, чтобы снова включить его didEndContact:

    func didEndContact(contact: SKPhysicsContact) {
    
    if((contact.bodyA.categoryBitMask) == scoreCategory || (contact.bodyB.categoryBitMask) == scoreCategory){
    
                if(contactDone == true){
    
                    contactDone = false
    
                }
    
    }
    
    }
    

Он работал так же, как когда я использовал SKPhysicBody(circleOfRadius: object.size.height/2),

Другие вопросы по тегам