web-dev-qa-db-ja.com

SceneKit衝突検出を設定する方法

こんにちは私はドキュメントを詳しく調べましたが、シーンキットで衝突検出を設定する方法がわかりません。誰かが例を示してもらえますか?私がこれを理解するのに非常に必死であるのを手伝ってください。ありがとうございました!

編集:こんにちはありがとうございます、申し訳ありませんが、私のプロジェクトがSwiftにあることを忘れてしまいました。大したことではありませんが、ほとんどの場合、自分自身を翻訳することができます。

オブジェクトが互いに衝突して跳ね返るときに、BitMaskが正しく機能しています。しかし、機能を動作させることができないようです

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

ドキュメント を見ると、どういうわけか、シーン物理学の世界の代表団をこのメソッドに割り当てる必要があるようです。どうすればいいのかわかりません。

13
T Neate

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;

これらの定数でビット単位のORを使用して、テーブルに入力するcollisionBitMask値を作成します。

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

SceneKitに衝突を解決させる(つまり、オブジェクトを互いにバウンスさせる)ために必要なのはこれだけです。

衝突への対応

衝突の通知も受けたい場合(ミサイルを爆破させ、船を小惑星にぶつけてゲームを終了させることができます)、シーンに 連絡先代理人 を設定する必要があります。物理学の世界で、連絡が発生したときに呼び出される 連絡先デリゲートメソッド の1つ以上を実装します。

連絡先デリゲートメソッド(たとえば、 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 ...
    }
}

このコードをクラスの1つ(ビューコントローラー、おそらく—ゲームロジックが適切な場所であればどこでも)に配置し、そのクラスに 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のデモのスモーガスボードの一部です スライド および デモ サンプルアプリ、そして 車両物理学 デモでも。

それ以外の点では、SceneKitの衝突処理モデルはSpriteKitのモデルとほぼ同じであるため、 SpriteKitプログラミングガイド のほとんどすべてがSceneKitの同じ内容を理解するのにも役立ちます。

34
rickster