【Swift】SpriteKitの使い方。放射重力ノードで物理ボディを引き寄せたり、遠ざけたりする。(Swift 2.2、XCode 7.3)
Radial Gravity Fieldとは
本記事では、SKFieldNodeの「Radial Gravity Field(以下、放射重力ノード)」について説明する。
SKFieldNodeとは、バネ運動や乱気流など様々な物理的効果を物理ボディに与えるノードである。放射重力ノードはSKFieldNodeの一種で、物理ボディを引き寄せる、または、遠ざける方向に加速させるノードである。
放射重力ノードを使ってみる
実際に放射重力ノードをシーンに配置して物理ボディを加速させてみよう。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」
事前準備では月と3個のロケットをシーンに配置しておいた。この時点では何も起きない。
下図赤枠のSKSファイルを選択してシーンエディタを開く。黄緑枠のオブジェクトライブラリボタンを押して部品一覧を表示し、ドラッグ&ドロップで「Radial Gravity Field」をシーンに配置する(紫矢印)。
黄枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Nameに「gravity」、Parentに「moon」、Category Maskに「1」を入力、Enabledのチェックを外す。
青ロケットの画像を選択、下図赤枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Field Maskに「1」を入力する。茶ロケット、赤ロケットも同じ「1」に設定する。
SKFieldNodeのCategory Maskと、物理ボディのField MaskのビットマスクのAND演算結果が0以外になるので、ロケットは放射重力ノードの影響を受けるようになる。
⇒「ビットマスクとは」
TestScene.swiftのtouchesBeganメソッドを以下のコードに変更する。「gravity」の前にスラッシュスラッシュが付いている理由は次の記事を参照されたし。⇒記事「ノードを取得する」
1 2 3 4 5 6 7 8 9 10 |
//画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //放射重力ノードを取得する。 let gravityNode = self.childNodeWithName("//gravity") as? SKFieldNode //物理的効果を有効にする。 gravityNode?.enabled = true } |
以下は実際のプレイ動画。ロケットが月に向かって加速するようになった。
ソースコードで実装する。
放射重力ノードをシーンエディタではなく、ソースコードで実装する場合は以下のコードのようにする。
試してみる場合は、先ほどシーンエディタで追加した放射重力ノードを削除してから行うこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { ‥省略‥ //放射重力ノードを作成する。 let gravityNode = SKFieldNode.radialGravityField() //放射重力ノードの名前を設定する。 gravityNode.name = "gravity" //放射重力ノードのカテゴリマスクを設定する。 gravityNode.categoryBitMask = 0b0001 //放射重力ノードの物理効果を無効にする。 gravityNode.enabled = false //月ノードを取得する。 let moonNode = self.childNodeWithName("moon") as? SKSpriteNode //月ノードの子に放射重力ノードを追加する。 moonNode?.addChild(gravityNode) } |
放射重力ノードを移動する
放射重力ノードをドラッグで移動させるとロケットはどのような動きをするか試してみよう。
TestScene.swiftに以下のメソッドを追加する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//画面タッチ移動時の呼び出しメソッド override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { //ノードを取得する。 let moonNode = self.childNodeWithName("moon") as? SKSpriteNode //タッチした座標を取得する。 let location = touches.first!.locationInNode(self) //タッチした位置まで移動するアクションを作成する。 let action = SKAction.moveTo(CGPoint(x:location.x, y:location.y), duration:0.1) //アクションを実行する。 moonNode!.runAction(action) } |
以下は実際のプレイ動画。ロケットが月を追いかけるようになった。
設定項目
放射重力ノードのアトリビュートインスペクタの設定項目は、概ね前回記事「Liner Gravity Field(以下、線形重力ノード)」と同じなので、そちらを参照されたし。⇒「記事」
線形重力ノードと意味が若干異なる項目を説明する。
Strength
加速の強さを指定する。プラス値の場合は放射重力ノードに向かって物理ボディが加速し、マイナス値の場合は放射重力ノードから遠ざかる方向に物理ボディが加速する。
以下はStrengthを「-1」に設定した場合のプレイ動画。ロケットが月から逃げる。
ちなみに、月とロケットを衝突させないようにした場合は、以下の動画のようになる。ロケットは放射重力ノードの位置で急激に加速して遠くに向かって飛び出したり、放射重力ノードの周りをクルクルをまわるのが面白い。