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

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

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

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

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

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

Ответ 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 есть пример кода, который использует обнаружение конфликтов - это часть smorgasbord демонстраций в WWDC слайды и demo примеры приложений, а также в автомобильной физике.

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