2015-01-15 5 views
5
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()) didBeginContact вызывается несколько раз для одной и той же SKPhysicsBody

другой из круга sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2)

Когда буксировочный объекты контакт друг друга иногда sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2) вызывается много раз. Как получить его, чтобы получить вызов только один раз для каждого объекта, даже если я удалю его из родителя, как только он свяжется.

+2

Я считаю, что это работает так, как предполагалось, поскольку тело из текстуры может генерировать несколько форм внутри, каждый из которых может вызвать контактное событие. Удаление узла не удаляет тело до тех пор, пока не закончится шаг симуляции физики. Вы должны вручную «маркировать» узел или тело как обработанные в этом событии контакта, чтобы вы могли пропустить любые последующие события контакта с теми же телами. – LearnCocos2D

+0

Хотелось бы, чтобы SKPhysicsBody из текстуры выбрал параметр, чтобы он соответствовал параметру, поэтому он ведет себя точно так же, как например. SKPhysicsBody от circleOfRadius, поэтому он подсчитывает ТОЛЬКО 1 удар/контакт, как в некоторых случаях, что было бы очень желательно, чем создание какой-либо дополнительной логики, включая ответ ниже. Кроме того, он может сэкономить ресурсы, чтобы не обнаруживать больше контактов, если они не нужны. –

ответ

2

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

Шаг 1:

Создать свойство имени для SKSpriteNode (мы будем использовать мяч для этого примера) и установите его равным уникальное имя. Мы можем сделать это, создав a 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

Не можете ли вы добавить SKSpriteNode в массив? Его передают по ссылке, поэтому мы можем сравнивать их, я не понимаю, почему нам нужно назначать уникальные имена. – 3366784

0

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).

+0

Не работает, когда я использую «SKPhysicsBody (текстура: ghostTexture, размер: Obj.size)» – Danny182

0

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

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

использовать что-то вроде этого:

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

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

1

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

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

Смежные вопросы