【Swift】SpriteKitの使い方。ノードとノードの接触を検知する。【Swift】SpriteKitの使い方。ノードとノードの接触を検知する。2020年6月16日ノードの接触を検知する本記事ではノードの接触検知について説明する。ビームで障害物を破壊したり、キャラクターを動かしてアイテムを取ったりなど、ノードが別のノードに接触したことを検知して処理したいことがある。そんなときはSKPhysicsContactDelegateを利用する。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」3匹の鳥ノードを配置し、茶鳥をドラッグで移動できるようにしておいた。この段階では接触は検知されない。https://hajihaji-lemon.com/apli/wp-content/uploads/2016/08/spritekit_physics_contact_movie.mp4まず、TestScene.swiftを以下のコードに変更する(変更箇所は青色網掛け)。SKPhysicsContactDelegateプロトコルを適用、デリゲート先を自分に設定している。茶鳥ノードのcontactTestBitMaskプロパティ(以下、接触マスク)に赤鳥のカテゴリマスクを設定している。この設定は、茶鳥の物理ボディが赤鳥の物理ボディと触れたときにデリゲートメソッドが呼ばれることを意味している。カテゴリマスクについては次の記事を参照されたし。⇒「カテゴリマスクとは」なんで接触マスクの名前がcontactBitMaskではなくcontactTestBitMaskなのだろうか。//背景画像のノードを作成する。//ラベルノードを作成する。//鳥のノードを作成する。//鳥の位置を設定する。//物理ボディを設定する。//カテゴリのビットマスクを設定する。//赤鳥との接触を検知するように設定する。//重力の影響を受けないようにする。//ノードをシーンに追加する。//デリゲート先を自分に設定する。//画面をタッチした座標に移動するアクションを作成する。//アクションを実行する。{//背景画像のノードを作成する。CGRectGetMidY(self.frame));//ラベルノードを作成する。self.frame.height-50)//鳥のノードを作成する。"bird_blue")//鳥の位置を設定する。self.frame.height-350)//物理ボディを設定する。birdBlue.size)//カテゴリのビットマスクを設定する。0b0100//赤鳥との接触を検知するように設定する。birdRed.physicsBody!.categoryBitMask//重力の影響を受けないようにする。false//ノードをシーンに追加する。self.addChild(backNode)self.addChild(testLabel)self.addChild(birdBrown)self.addChild(birdRed)self.addChild(birdBlue)//デリゲート先を自分に設定する。{//画面をタッチした座標に移動するアクションを作成する。duration:0.1)//アクションを実行する。birdBrown.runAction(action)}}SKPhysicsContactDelegateのデリゲートメソッドは接触開始時と終了時に呼び出される2つのメソッドしかない。両方とも試してみよう。TestScene.swiftに以下のメソッドを追加する。接触開始時と終了時にラベルの文字列を変更している。"接触終了"print("接続終了")}以下は実際のプレイ動画。茶鳥で赤鳥を運んでいる最中に「接触開始」と「接触終了」が連続で呼び出された。ように同じものが連続で呼び出されることもある。https://hajihaji-lemon.com/apli/wp-content/uploads/2016/08/spritekit_contact_red_bird_movie.mp4衝突させずに検知する衝突しないノード同士でも物理ボディが重なることで接触を検知できる。didMoveToViewメソッドに以下のコードを追加する。茶鳥と赤鳥の衝突マスクに青鳥のカテゴリマスクを設定し、茶鳥と赤鳥は衝突しないようにした。birdBlue.physicsBody!.categoryBitMask以下は実際のプレイ動画。重なっている状態でも開始、終了が連続で呼び出されるのが気になる。https://hajihaji-lemon.com/apli/wp-content/uploads/2016/08/spritekit_contact_no_collision_movie.mp4重なり開始、終了時の1回ずつ通知されるようにする「上記を読むと、このデリゲートメソッドではノードがどこかの領域の中に入った、抜けたの検知はできないということなのだろうか。」と思ってしまうが、物理ボディの形状を四角形や円形にすれば、重なり始めたときに「接続開始」、重なりが終わったときに「接続終了」が呼び出されるようになる。didMoveToViewメソッドの物理ボディを設定する箇所を以下のコードに変更する。Swift//物理ボディを設定する。50.0))123456789//物理ボディを設定する。50.0))以下は実際のプレイ動画。デリゲートメソッドが呼び出されるタイミングが、重なり開始時と終了時の2回だけになった。物理ボディに四角形や円形を使った場合はノードの接触位置がリアルではなくなる。物理ボディのdynamicプロパティをfalseにするとデリゲートメソッドが呼び出されなくなるので注意すること。Working」Swift//他のノードに衝突されても動かなくする。false12345//他のノードに衝突されても動かなくする。false接触したノードを調べるデリゲートメソッドの引数のPhysicsContactインスタンスには、接触した2つの物理ボディがbodyA、bodyBのプロパティで渡ってくる。そこで本記事の最後は、デリゲートメソッドが呼び出されたら接触したノードを調べ、赤鳥なら10点、青鳥なら20点が入り、鳥が大きくなる単純なゲームを作った。//背景画像のノードを作成する。//ラベルノードを作成する。//鳥のノードを作成する。//鳥の位置を設定する。//物理ボディを設定する。//カテゴリのビットマスクを設定する。//赤鳥と青鳥の接触を検知するように設定する。//他のノードに衝突されても動かなくする。//重力の影響を受けないようにする。//ノードをシーンに追加する。//デリゲート先を自分に設定する。//画面をタッチした座標に移動するアクションを作成する。//アクションを実行する。//茶鳥を重力の影響を受けるようにする。