SpriteKit: обнаружение полного перекрытия узлов

У меня есть два SKShapeNode — один с SKPhysicsBody на основе ребер, другой на основе объема — и я хочу обнаружить их пересечение без коллизий. У меня это работает нормально, когда методы контакта SKPhysicsContactDelegate вызываются, когда один проходит над другим, но моя проблема в том, что didEndContact вызывается, когда ребра больше не пересекаются, даже когда одно тело полностью содержится внутри другого. Как лучше всего определить истинный контакт или перекрытие, а не только пересечение ребер? Я пробовал usesPreciseCollisionDetection, безрезультатно.


person man1    schedule 25.06.2014    source источник
comment
как насчет добавления дочернего элемента с альфой до 0 и использования его как части логической проверки? вы не увидите его, но он будет все время сталкиваться... и в вашем didBeginContact вы должны попробовать оператор switch, вы можете указать там, какие объекты сталкиваются, вместо того, чтобы подсчитывать все касания.   -  person Juan Boero    schedule 27.11.2015


Ответы (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, поэтому вам, возможно, придется немного поиграть с синтаксисом. Надеюсь, это направит вас в правильном направлении.

person meisenman    schedule 25.06.2014
comment
Спасибо за идею! Из документации видно, что containsPoint возвращает логическое значение, указывающее, находится ли точка внутри ограничивающей рамки узла. Я обеспокоен тем, что это может быть недостаточно точным для моего варианта использования (т.е. только тестирование ограничивающей рамки для потенциально вогнутых тел на основе ребер). Однако я не могу найти более строгой альтернативы containsPoint. - person man1; 25.06.2014
comment
Должен ли один из ваших узлов иметь физическое тело на основе ребер? - person meisenman; 25.06.2014
comment
Да, к сожалению, похоже, что объемные тела должны быть определены как выпуклые многоугольники, в то время как формы, с которыми я работаю, иногда могут быть вогнутыми. - person man1; 26.06.2014
comment
Очень интересное затруднительное положение, в котором вы оказались. Я продолжу поиск решения, так как я не верю, что SpriteKit должен / будет ограничен таким образом. Я думаю, что сообщество spriteKit должно проявить больше интереса к этому сообщению, и, возможно, кто-то придет с... пользовательским containsPoint, который удовлетворяет вашим требованиям к выпуклой форме. - person meisenman; 26.06.2014
comment
Я экспериментировал с этим, и я думаю, что документация неверна! containsPoint, кажется, работает с выпуклыми многоугольниками (по крайней мере, в моем контексте и с использованием iOS 8), но есть еще одна сложность, которую мне нужно учитывать. Я проголосую за это, а затем опубликую еще более полный ответ для всех, кто столкнется с этим. - person man1; 01.07.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
    }
  }
}
person man1    schedule 01.07.2014
comment
Хорошая работа! Рад, что вы нашли полный ответ! - person meisenman; 01.07.2014

Это мои мысли о примере #meisenman для swift 3. Вместо обнаружения столкновений с помощью масок, скажем, мы хотели узнать, находится ли узел внутри узла. С #meisenman местоположение узла используется для каждого.

Image Пример CGPoint двух разных узлов.

Это следующее изображение - это то, что мы на самом деле хотим сделать.

Пример изображения двух CGPoint внутри друг друга.

Код, который использует #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 в различных функциях или переопределять функции, это не ограничивается только «начало» или «касание перемещено».
Пример изображения двух CGPoint внутри друг друга,  с возможными ограничениями.

person Community    schedule 04.11.2016
comment
Также обратите внимание: объект 3 показывает пример ограничений этого альтернативного метода. - person dnaatwork.com; 04.11.2016