У меня есть два SKShapeNode — один с SKPhysicsBody на основе ребер, другой на основе объема — и я хочу обнаружить их пересечение без коллизий. У меня это работает нормально, когда методы контакта SKPhysicsContactDelegate вызываются, когда один проходит над другим, но моя проблема в том, что didEndContact
вызывается, когда ребра больше не пересекаются, даже когда одно тело полностью содержится внутри другого. Как лучше всего определить истинный контакт или перекрытие, а не только пересечение ребер? Я пробовал usesPreciseCollisionDetection
, безрезультатно.
SpriteKit: обнаружение полного перекрытия узлов
Ответы (3)
CGPoint locObj1 = [sprite1 locationInNode:self];
CGPoint locObj2 = [sprite2 locationInNode:self];
if([sprite1 containsPoint: locObj2]) return;
if([sprite2 containsPoint: locObj1]) return;
Добавьте это в начало didBeginContact и didEndContact. Это проверяет, содержит ли один из узлов другой узел. Если это так, он ничего не делает, что облегчит вашу проблему с ненужным вызовом didBeginContact и didEndContact. Я не на своем Mac, поэтому вам, возможно, придется немного поиграть с синтаксисом. Надеюсь, это направит вас в правильном направлении.
containsPoint
возвращает логическое значение, указывающее, находится ли точка внутри ограничивающей рамки узла. Я обеспокоен тем, что это может быть недостаточно точным для моего варианта использования (т.е. только тестирование ограничивающей рамки для потенциально вогнутых тел на основе ребер). Однако я не могу найти более строгой альтернативы containsPoint
.
- person man1; 25.06.2014
Как meisenman предложено, похоже, лучший способ сделать это - использовать метод containsPoint
для определения истинного перекрытия узлов. В документах говорится, что это «возвращает логическое значение, указывающее, находится ли точка внутри ограничивающей рамки узла», но в моих экспериментах похоже, что это работает и для вогнутых форм на основе ребер.
Поэтому, если я хочу определить, когда два объекта больше не перекрываются, имеет смысл выполнить проверку containsPoint
внутри didEndContact
, но оказывается, что didEndContact
вызывается, когда каждое ребро больше не пересекается, даже если другое ребро той же формы все еще пересекает ребро. тот же объект. Например, мяч, вылетевший из прямоугольника через его угол, приведет к двум didEndContact
событиям. Следовательно, необходимо вести абсолютный подсчет событий контакта (разница между началом и концом) и проверять на сдерживание только тогда, когда этот подсчет равен нулю.
Мое решение в Swift:
var _contactCount = 0
func didBeginContact(contact: SKPhysicsContact!) {
if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
if (_contactCount == 0) {
// Contact is actually beginning
}
_contactCount += 1
}
}
func didEndContact(contact: SKPhysicsContact!) {
if ((contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (CATEGORY_ONE | CATEGORY_TWO)) {
_contactCount -= 1
let overlap = contact.bodyA.node.containsPoint(contact.bodyB.node.position) || contact.bodyB.node.containsPoint(contact.bodyA.node.position)
if (!overlap && _contactCount == 0) {
// Contact is actually ending
}
}
}
Это мои мысли о примере #meisenman для swift 3. Вместо обнаружения столкновений с помощью масок, скажем, мы хотели узнать, находится ли узел внутри узла. С #meisenman местоположение узла используется для каждого.
Это следующее изображение - это то, что мы на самом деле хотим сделать.
Код, который использует #meisenman, не требует SKPhysics. Вот код в Swift 3.0
let Object_1: CGPoint! = Sprite_Object_1.position
//this obtains the location of the sprite node, through CGPoint.
if Object_Sprite_2.contains(Object_1){
print("Then it is true, object 2 is within the location of object 1")
}
Единственные ограничения, которые я обнаружил, заключаются в том, что если центр этих узлов не находится внутри тела желаемого узла, то это утверждение if не будет истинным. Это не было проверено путем установки определения тела узла (маски).
Что мне нравится, так это возможность использовать этот оператор if в различных функциях или переопределять функции, это не ограничивается только «начало» или «касание перемещено».