Как настроить обнаружение столкновений SceneKit

Здравствуйте, я изучил документацию и не могу понять, как настроить обнаружение столкновений в наборе сцен. Может кто-нибудь показать пример. Пожалуйста, помогите, я очень отчаянно пытаюсь понять это. Благодарю вас!

Редактировать: Здравствуйте, большое спасибо, извините, я забыл упомянуть, что мой проект находится в быстром темпе. Ничего страшного, я могу перевести себя по большей части.

У меня битмаски работают правильно, когда объекты сталкиваются и отскакивают друг от друга. Однако я не могу заставить функцию работать

func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact){
    let contactMask = contact.nodeA.physicsBody!.categoryBitMask | contact.nodeB.physicsBody!.categoryBitMask
    if (contactMask == (CollisionBallCategory | CollisionTerminatorCategory)) {
        println("Collided")
    }
}

Глядя на документация похоже, мне нужно каким-то образом назначить делегата физического мира сцен этому методу. Я не уверен, как это сделать.


person T Neate    schedule 09.12.2014    source источник
comment
Я добавил языковой тег к вопросу для вас после вашего редактирования — теперь, когда Cocoa (Touch) имеет два основных языка, всегда полезно уточнить, о каком вы спрашиваете. Говоря об этом, вы так и не упомянули, на какую платформу (ы) вы ориентируетесь — SceneKit работает как на iOS, так и на OS X, хотя обычно все, что специфично для SceneKit, является общим для обеих платформ.   -  person rickster    schedule 10.12.2014
comment
После того, как вы проверили документы и/или мой обновленный ответ, чтобы убедиться, что ваш делегат коллизии настроен правильно, вставьте println прямо внутри physicsWorld:didBeginContact:. Таким образом, вы узнаете, связана ли ваша проблема с тем, что метод не вызывается, или ваша contactMask логика работает неправильно.   -  person rickster    schedule 10.12.2014


Ответы (1)


Что нужно знать об обнаружении столкновений в SceneKit:

  • он основан на битовых масках, которые вместе образуют таблицу.
  • контактный делегат — это то, как вы реагируете на коллизии.

Столкновение объектов

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

Астероиды сталкиваются друг с другом (и образуют меньшие астероиды). Ракеты должны проходить друг сквозь друга, но уничтожать ракеты и астероиды. Ракеты не должны ничего делать с ракетами (только наоборот), но если одна подойдет слишком близко к другой или к астероиду, у вас будет серьезная проблема, и вы не полетите сегодня в космос.

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

         | Missile | Rocket | Asteroid
--------------------------------------
Missile  | No      | Yes    | Yes
Rocket   | No      | Yes    | Yes
Asteroid | No      | No     | Yes

Затем вы можете превратить заголовки таблицы в набор констант категории для использования в вашем коде.

typedef NS_OPTIONS(NSUInteger, CollisionCategory) {
    CollisionCategoryMissile    = 1 << 0,
    CollisionCategoryRocket     = 1 << 1,
    CollisionCategoryAsteroid   = 1 << 2,
};

missile.physicsBody.categoryBitMask = CollisionCategoryMissile;
rocket.physicsBody.categoryBitMask = CollisionCategoryRocket;
asteroid.physicsBody.categoryBitMask = CollisionCategoryAsteroid;

Используйте побитовое ИЛИ для этих констант, чтобы создать collisionBitMask значений, которые заполняют таблицу.

missile.physicsBody.collisionBitMask =
    CollisionCategoryRocket | CollisionCategoryAsteroid;
rocket.physicsBody.collisionBitMask =
    CollisionCategoryRocket | CollisionCategoryAsteroid;
asteroid.physicsBody.collisionBitMask = CollisionCategoryAsteroid;

Это все, что вам нужно, чтобы SceneKit разрешал за вас коллизии (то есть отбрасывал объекты друг от друга).

Реакция на столкновения

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

В вашем методе делегирования контакта (скажем, physicsWorld:didBeginContact:), вам нужно выяснить, какие категории тел участвовали в контакте и какие именно, чтобы вы могли добраться до своего кода, который делает то, что вам нужно. игра делает для столкновения:

- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact
{
    CollisionCategory contactMask =
        contact.nodeA.physicsBody.categoryBitMask | contact.nodeB.physicsBody.categoryBitMask;

    // first, sort out what kind of collision
    if (contactMask == (CollisionCategoryMissile | CollisionCategoryRocket)) {
        // next, sort out which body is the missile and which is the rocket
        // and do something about it
        if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryMissile) {
            [self hitRocket:contact.nodeB withMissile:contact.nodeA];
        } else {
            [self hitRocket:contact.nodeA withMissile:contact.nodeB];
        }
    } else if (contactMask == (CollisionCategoryMissile | CollisionCategoryAsteroid)) {
        // ... and so on ...
    }
}

Поместите этот код в один из ваших классов (возможно, в контроллер представления — везде, где вы сохраняете свою игровую логику) и заставьте этот класс декларировать соответствие SCNPhysicsContactDelegate.

@interface ViewController: UIViewController <SCNPhysicsContactDelegate>

Затем назначьте этот объект физическому миру вашей сцены в качестве контактного делегата:

// in initial setup, where presumably you already have a reference to your scene
scene.physicsWorld.contactDelegate = self

Узнать больше

Немного о разрешении коллизий есть в SCNPhysicsBody справочная документация. И у Apple есть пример кода, который использует обнаружение столкновений — это часть шведского стола демонстраций на WWDC слайды и demo в примерах приложений и в физика транспортных средств.

Кроме того, модель обработки столкновений в SceneKit почти такая же, как и в SpriteKit, поэтому почти все в Руководство по программированию SpriteKit также полезно для понимания того же самого материала в SceneKit.

person rickster    schedule 09.12.2014
comment
Немного добавлено в часть ответа на коллизии, чтобы более непосредственно решить проблему в вашем отредактированном вопросе. Оставить код в ObjC (по крайней мере, пока) — если вам удобно читать, мне не нужно его переписывать и тестировать. :) - person rickster; 10.12.2014
comment
И на самом деле, учитывая текущее состояние Swift, возможно, лучше определить перечисление категории коллизий в C, используя NS_OPTIONS, а затем импортировать его в Swift — это автоматически даст вам RawOptionSetType, к которому вы можете применить побитовые операторы, где, если бы вы объявили свое перечисление в Swift, вам пришлось бы добавить их самостоятельно. (Затем сделайте остальную часть кода в Swift.) - person rickster; 10.12.2014
comment
Большое спасибо, эти последние две строки кода были тем, что я не мог понять, спасибо! - person T Neate; 11.12.2014
comment
Привет! Кажется, я больше не могу найти CollisionCategory в Swift 4. Есть ли другой способ сделать это? - person Amit Kalra; 17.10.2017
comment
Внимательно прочитайте ответ. CollisionCategory — это не API, это тип, который вы определяете сами. - person rickster; 17.10.2017