こんにちは、のっくんです。
ゲーム開発の記事も早くも8つ目。
今日は、コリジョンイベント(Collision Event)についてです。
以下のようにアプリを実装してみました。
弾が敵に当たった後に敵が死んでいます。
カエルはその場で透明になり、ハエは落下しています。
この実装はコリジョンイベントを利用することで実現しています。
コリジョンイベントとは、その名の通り、キャラクター同士が衝突・接触した場合のイベントです。
Spritekitでは衝突イベントを管理するために以下の3つのマスクを用意しています。
- categoryBitMask、自分のカテゴリー。弾と敵。
- contactTestBitMask、接触した時にイベントを発生させる相手。弾が敵と接触するように設定する。
- collisionBitMask、衝突する相手。デフォルトは0xFFFFFFFF、すべての物体と衝突するようになっている。
BitMaskを設定する
まずカテゴリーを列挙型で設定します。
enum PhysicsCategory: UInt32{ case enemy = 1 case bullet = 2 }
次にShotクラスでは以下のようにbulletカテゴリーを設定、enemyと接触した時にイベントを発生するようにしました。
self.physicsBody?.categoryBitMask = PhysicsCategory.bullet.rawValue self.physicsBody?.contactTestBitMask = PhysicsCategory.enemy.rawValue
カエルやハエのFrog、Flyクラスでは以下のようにenemyカテゴリーを設定しました。
self.physicsBody?.categoryBitMask = PhysicsCategory.enemy.rawValue
接触時のイベント
カテゴリーが設定できたところで接触時のイベントを実装していきます。
SKPhysicsContactDelegateをGameSceneの中でインプリします。
didBegin(_ contact: SKPhysicsContact) {}が使えるようになるのでこの中で接触イベントを書いていきます。
弾のカテゴリーを取得。
let bulletMask = PhysicsCategory.bullet.rawValue
didBeginの中では、衝突した物体AとBが得られますが、弾がどちらなのかは分かりません。
ですので、Aがだった場合とBが弾だった場合でそれぞれ条件分けします。
// Aが弾だった場合、Bを条件判定対象に if (contact.bodyA.categoryBitMask & bulletMask) > 0 { one = contact.bodyA two = contact.bodyB // Bが弾だった場合、Aを条件判定対象に }else if(contact.bodyB.categoryBitMask & bulletMask > 0){ one = contact.bodyB two = contact.bodyA }
これでoneが弾、twoが判定対象として設定されました。
次にtwoが敵だった時の処理を書いていきます。
// oneは弾 switch two.categoryBitMask { case PhysicsCategory.enemy.rawValue: print("bullet -> enemy") // 弾を消す nodesToRemove.append(one.node!) // カエルかハエである場合ダウンキャストする if let frog = two.node as? Frog{ frog.die() }else if let fly = two.node as? Fly{ fly.die() }
弾を消して、敵がカエルもしくはハエだったらそれぞれ死ぬようにしました。
弾を貫通させる
動画をよく見てもらうと分かりますが、死んだカエルは透明になり弾が貫通しています。
着弾直後は透明になって見えますが、存在しないことになっています。
すべての接触や衝突を回避するために、カエルが死ぬ時にはcategoryBitMaskとcollisionBitMaskを0にしています。
// 判定を無効に self.physicsBody?.collisionBitMask = 0 self.physicsBody?.categoryBitMask = 0
終わりに
いかがでしたでしょうか。
接触や衝突イベントはゲームを作る上で欠かせない要素だと思います。
それでは。