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)
может прийти в нескольких формах и формах.
Для тех, кому нужно его обнаружение только один раз, нам просто нужно использовать логический флаг в качестве флага, чтобы проверить, выполнено ли обнаружение и завершено ли оно.
Вот как я это делаю:
Объявить
var
логическое значение:var contactDone = Bool()
Инициализируйте его при запуске программы (например, ниже
didMoveToView
)contactDone = false
Сделать проверку в
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 } } }
Снимите флажок, чтобы снова включить его
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)
,