57879


私は殆ど、参考になりそうなウェブサイトを頼りに書き写したりして作業をしているのですが、PhysicsBodyでの当たり判定についてはそれだけではロジックの理解に繋がりませんでした。すごく単純な話ではありますが、こちらで質問させてください。

* * *

まず、 **physicsBody.contactTestBitMask** についてなのですが  
この値が一体何をしているのかがわかりません。  
使い方は  
foo, barいずれもphysicsBodyを持った状態で、一度

[code]

    foo.physicsBody.contactTestBitMask = bar.physicsBody.categoryBitMask
    
[/code]

としておくだけで、fooの剛体がbarの持つカテゴリの世界線において何らか（スプライトノードなど）と衝突あるいは重なっている状態であれば  
**SKPhysicsContactDelegate** 下の  
didBegin(_ contact: SKPhysicsContact)関数内の処理が呼び出されるという認識で間違い無いのでしょうか。  
であれば一体前述した1行のコードで何が行われているのでしょうか、何もトグル（発火）しているようには見えません。ただの代入なのでしょうか。

* * *

このような質問をするのは他でもなく、私はこの当たり判定の実装に成功できていないからなのですが、どのような仕組みなのかを理解するだけでも解決につながるかもしれないので、この場をお借りしました。  
ご回答のほどよろしくお願いいたします。


CC BY-SA 4.0
2019-09-05T08:10:52.080
57870
2019-09-05T17:15:50.970
16877
question
swift4 spritekit
SpriteKitでのphysicsBodyを用いた当たり判定の流れ知りたい


> 使い方は foo, barいずれもphysicsBodyを持った状態で、一度
[code]

>     foo.physicsBody.contactTestBitMask = bar.physicsBody.categoryBitMask
>  
[/code]

>
> としておくだけで、fooの剛体がbarの持つカテゴリの世界線において何らか（スプライトノードなど）と衝突あるいは重なっている状態であれば  
>  SKPhysicsContactDelegate下の didBegin(_ contact:  
>  SKPhysicsContact)関数内の処理が呼び出されるという認識で間違い無いのでしょうか。

いいえ。そのようなコードで当たり判定(接触検出)が出来るのは極めて限定的な場合だけです。

(そんなコードだけを十分な解説も無しに載せているサイトを「参考になりそうなウェブサイト」として頼りにするのはやめた方が良いでしょう。）

* * *

`BitMask`の働きを完全に理解するにはある程度2進法についての理解が必要です。基本は以下のような感じ。

[code]

    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        private var player: PlayerNode?
        private var enemy1: EnemyNode?
        private var wall: SKShapeNode?
    
        override func didMove(to view: SKView) {
            physicsWorld.contactDelegate = self
    
            //適切な`SKPhysicsBody`をもったノードが存在するものとする
            player = PlayerNode(imageNamed: "player")
            player!.physicsBody = SKPhysicsBody(circleOfRadius: 12)
            enemy1 = EnemyNode(imageNamed: "enemy1")
            enemy1!.physicsBody = SKPhysicsBody(circleOfRadius: 12)
            wall = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 384, height: 12))
            wall!.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 384, height: 12))
            //...
            //ノードのカテゴリー(分類)ごとに`categoryBitMask`を設定する
            player!.physicsBody!.categoryBitMask = 0b00000000_00000000_00000000_00000001
            enemy1!.physicsBody!.categoryBitMask = 0b00000000_00000000_00000000_00000010
            wall!.physicsBody!.categoryBitMask   = 0b00000000_00000000_00000000_00000100
            //接触判定をしたい相手の`categoryBitMask`を自分の`contactTestBitMask`に設定する
            player!.physicsBody!.contactTestBitMask = 0b00000000_00000000_00000000_00000110
            enemy1!.physicsBody!.contactTestBitMask = 0b00000000_00000000_00000000_00000111
            wall!.physicsBody!.contactTestBitMask   = 0b00000000_00000000_00000000_00000011
            //各ノードをシーン内に置いたり、初期速度を与えたり…
            //...
        }
    
        func didBegin(_ contact: SKPhysicsContact) {
            print(contact.bodyA, contact.bodyB)
            //...
        }
    
        //...
    }
    
[/code]

普通は、`0b00000000_00000000_00000000_00000001`みたいな長い2進法の定数を書くのは、書きにくく読み難いので、次のような定数宣言を書くのが好まれます。

[code]

        let playerBit: UInt32 = 1 << 0 //0b00000000_00000000_00000000_00000001
        let enemy1Bit: UInt32 = 1 << 1 //0b00000000_00000000_00000000_00000010
        let wallBit  : UInt32 = 1 << 2 //0b00000000_00000000_00000000_00000100
    
[/code]

これらの定数を使って、

[code]

            //...
            //ノードのカテゴリー(分類)ごとに`categoryBitMask`を設定する
            player!.physicsBody!.categoryBitMask = playerBit
            enemy1!.physicsBody!.categoryBitMask = enemy1Bit
            wall!.physicsBody!.categoryBitMask   = wallBit
            //接触判定をしたい相手の`categoryBitMask`を自分の`contactTestBitMask`に設定する
            player!.physicsBody!.contactTestBitMask = enemy1Bit | wallBit
            enemy1!.physicsBody!.contactTestBitMask = playerBit | enemy1Bit | wallBit
            wall!.physicsBody!.contactTestBitMask   = playerBit | enemy1Bit
            //...
    
[/code]

としておくと、

  * `player` → カテゴリーが`enemy1Bit`と`wallBit`の相手と接触判定を行う
  * `enemy1` → カテゴリーが`player1`と`enemy1Bit`と`wallBit`の相手と接触判定を行う
  * `wall` → カテゴリーが`player1`と`enemy1Bit`の相手と接触判定を行う

と言う設定を行ったことになります。

* * *

上記のコードを元にサンプルコードを作られて、動きを確かめてみられると良いかと思います。


CC BY-SA 4.0
2019-09-05T17:15:50.970
57879
2019-09-05T17:15:50.970
13972
57870
answer