OK - Я уверен, что это дубликат, и что Whirlwind или KnightOfDragons опубликовали решение, но я не могу его найти.Sprite-Kit, регистрирующий множественные столкновения для одного контакта
Я пишу клон Space Invader в Swift с помощью Sprite-Kit. Проблема в том, что, когда бомба-захватчик поражает мой корабль, код иногда регистрирует 2 или 3 столкновения, сразу заканчивая игру. Вот раздел «didBeginContact», который обрабатывает столкновение бомбы/корабля:
case category.bomb.rawValue | category.ship.rawValue:
print("Bomb hit ship!")
let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node
bomb?.physicsBody?.contactTestBitMask = 0 // Seems to prevent multiple contacts with same bomb
ship.physicsBody!.contactTestBitMask = 0 // We'll reset this after the death animation
bomb?.removeAllActions()
ship.removeAllActions()
bomb?.removeFromParent()
ships -= 1
if ships == 0 { endScene(won: false, withMessage: "A bomb got you!") }
и когда я запускаю игру, я вижу:
Bomb hit ship!
2 ships left.
после 1 попадания бомбы (это правильно)
Bomb hit ship!
1 ships left.
Bomb hit ship!
0 ships left.
после 2-го удара бомбы (что неправильно).
У меня никогда не было контакта, не будучи зарегистрированным, а иногда (50%?) Он отлично работает. В других случаях я видел себя с -4 кораблями! Я уверен, что это что-то очевидное/фундаментальное, что я ошибаюсь.
Мои комментарии относительно установки контактаTestBitMask на 0 для бомбы и корабля, очевидно, являются неправильными. Я знаю, что это не обязательно, поскольку я удаляю бомбу, когда происходит контакт, поэтому она не должна повторяться снова.
Как я могу гарантировать, что контакт обрабатывается только один раз?
================================
Обновление: Я добавил 2 print
заявления, чтобы обеспечить более отладочная информация:
print("bodyA is \(contact.bodyA.node!.name)")
print("bodyB is \(contact.bodyB.node!.name)")
Это после let bomb = contact.bodyA.category
... заявление и теперь я получаю:
Bomb hit ship!
bodyA is Optional("bomb")
bodyB is Optional("playerShip")
1 ships left.
после 1 попаданием бомбы, а также:
Bomb hit ship!
fatal error: unexpectedly found nil while unwrapping an Optional value
после 2-го удара бомбы. Итак, после второго столкновения, bodyA равно нулю, поэтому я не понимаю, почему Sprite-Kit фактически зарегистрировал столкновение?
Любые идеи?
Является ли ответ, что Sprite-Kit поставил в очередь несколько столкновений, которые должны быть обработаны между судном и бомбой (что не должно, но эй, кто знает), а затем SK называет dBC для каждого столкновения и потому, что я удалил бомбу первый раз, это ноль второго и последующих времен. Поэтому мне нужно отметить бомбу как активную, когда она упала, проверить, активна ли бомба, когда я обнаруживаю столкновение и устанавливаю его неактивным, а не удаляет его в dBC? –
Из того, что я видел, didBeginContact запускается несколько раз, когда между двумя телами есть несколько точек контакта. Это может произойти, когда вы создаете тело из текстуры или даже если тела являются круговыми. На данный момент я не могу найти свои собственные ответы (я нахожусь по телефону), но в этом объясняется крах, который вы испытываете: http://stackoverflow.com/a/37003007 Существует несколько способов решить вашу проблему. Можно было бы проверить, нет ли node.parent nil и return from didBeginContact, если true. Другой способ - это флаг на пулевом узле. Возможно, некоторые другие способы, я не помню больше. – Whirlwind
Да, что @Whirlwind сказал, помните, что вы действительно не хотите удаляться от родителя во время фазы didcontactbegin, потому что могут быть случаи, когда вам нужен узел, который все еще будет в сцене для второго контакта (одна пуля попадает 2 перекрытия враги, может быть, вы хотите призрак, кто знает) Мне лично нравится резервировать categoryBitMask бит 31 для обработки живых или мертвых, а во время проверки физики пропустите эти узлы – Knight0fDragon