[Swift + SpriteKit] 衝突判定のBitMaskの使い方

Swift + SpriteKitでゲーム作ってるのですが、衝突判定で使うビットマスクの使い方で少し戸惑ったのでメモしておきます。かなり適当です。

ちなみに、この使い方が正しいのかどうかは分かりません…。

 

ビットマスクとは

調べてみると、プログラミングでは複雑なフラグ判定で使われるそうです。参考書では、大量のスイッチを扱うイメージと書かれていました。

ビット演算は2進数のビット列を操作します。
Swiftの衝突判定では、ビット演算子”|” (和)を使って組み合わせパターンを判別します。

たとえば、下記の様に各ノードとその種類判別用のビットマスクを定義しておきます。
配列でも良いですが、今回は構造体を作ります。

struct CollisionType{
   static let player: UInt32 = (1 << 0)
   static let enemy: UInt32 = (1 << 1)
   static let coin: UInt32 = (1 << 2)
}

「<<」は、ビット列の右に0を追加して列を左へシフトさせます。
すると、2進数の中身は、下記の様になります。それぞれ、違う位置に1が入った2進数が作成されます。

▼こんなイメージ

player…001
enemy…010
coin…100

これを、各ノードのcategoryBitMaskにセットしておきます。

player.physicsBody?.categoryBitMask = CollisionType.player
enemy.physicsBody?.categoryBitMask = CollisionType.enemy
coin.physicsBody?.categoryBitMask = CollisionType.coin

(A | B)とすると、AとBの列を比較してどちらかが1を持っていれば1、両方0であれば0を返します。

これらの和を取ると、組み合わせごとに全て異なる結果が帰ってきます。
なので、衝突ノードそれぞれが何なのか全パターンをチェックしなくても、「何と何が衝突したか?」を1度のチェックで判断できる仕組みです。

(player | enemy) //011
(player | coin) //101
(enemy | coin) //110

 

didBeginContactメソッドで行う事

func didBeginContact(contact: SKPhysicsContact) {
   //まず、チエック用の定数を用意
   let player_enemy = CollisionType.player | CollisionType.enemy //playerとenemy
   let player_coin = CollisionType.player | CollisionType.coin //playerとcoin
   
   //衝突ノードの和
   let check = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
   
   //判定
   if (player_enemy == check){
      self.paused = true
      //enemyと衝突した場合の処理
   }
   else if (player_coin == check){
      //coinと衝突した場合の処理
   }
}