【Swift】SpriteKitの使い方。物理ボディにバネをつけたかのように振動させる。(Swift 2.2、XCode 7.3)
Spring Fieldとは
本記事では、SKFieldNodeの「Spring Field(以下、バネノード)」について説明する。
SKFieldNodeとは、重力や乱気流など様々な物理的効果を物理ボディに与えるノードである。バネノードはSKFieldNodeの一種で、バネノードを中心に物理ボディを単振動させるノードである。まるで物理ボディにバネを取り付けたような動きをする。
バネノードを使ってみる
実際にバネノードをシーンに配置して物理ボディを単振動させてみよう。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」
事前準備では、目印とボールをグリッド線の背景の上に配置しておいた。この段階では何も起きない。
下図赤枠のSKSファイルを選択してシーンエディタを開く。黄緑枠のオブジェクトライブラリボタンを押して部品一覧を表示し、ドラッグ&ドロップで「Spring Field」をシーンに配置する(紫矢印)。
黄枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Nameに「spring」、Parentに「center_point」、Category Maskに「1」を入力、Enabledのチェックを外す。
黒ボールの画像を選択、下図赤枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Field Maskに「1」を入力する。
SKFieldNodeのCategory Maskと、物理ボディのField MaskのビットマスクのAND演算結果が0以外になるので、黒ボールはバネノードの物理的効果を受けるようになる。
⇒「ビットマスクとは」
TestScene.swiftのtouchesBeganメソッドを以下のコードに変更する。
「spring」の前にスラッシュスラッシュが付いている理由は次の記事を参照されたし。⇒記事「ノードを取得する」
1 2 3 4 5 6 7 8 9 10 |
//画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //バネノードを取得する。 let springNode = self.childNodeWithName("//spring") as? SKFieldNode //物理的効果を有効にする。 springNode?.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 springNode = SKFieldNode.springField() //バネノードの名前を設定する。 springNode.name = "spring" //バネノードのカテゴリマスクを設定する。 springNode.categoryBitMask = 0b0001 //バネノードの物理効果を無効にする。 springNode.enabled = false //中心ノードを取得する。 let centerNode = self.childNodeWithName("center_point") as? SKSpriteNode //中心ノードの子にバネノードを追加する。 centerNode?.addChild(springNode) } |
バネノードを移動する
中心ノードをドラッグで移動させると黒ボールはどのような動きをするか試してみよう。
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 centerNode = self.childNodeWithName("center_point") as? SKSpriteNode //タッチした座標を取得する。 let location = touches.first!.locationInNode(self) //タッチした位置まで移動するアクションを作成する。 let action = SKAction.moveTo(CGPoint(x:location.x, y:location.y), duration:0.1) //アクションを実行する。 centerNode!.runAction(action) } |
以下は実際のプレイ動画。ボールの進行方向と逆向きにバネノードを動かすとボールは加速し、進行方向と同じ向きにバネノードを動かすとボールは減速する。
バネを伸ばして勢いをつけ、バネを縮めて勢いを弱くする感覚と同じだ。
設定項目
放射重力ノードのアトリビュートインスペクタの設定項目は、概ね「Liner Gravity Field(以下、線形重力ノード)」と同じなので、そちらを参照されたし。
線形重力ノードの説明と異なる項目を説明する。
Stringth
プラス値の場合はバネノードに向かって物理ボディが加速し、マイナス値の場合はバネノードから遠ざかる方向に物理ボディが加速するのは同じだが、マイナスにしてしまうとボールはバネノードからどんどん離れていって単振動にならないので注意すること。
Falloff
シーンエディタでバネノードを配置するとFalloffはデフォルトでは「-1」に設定されているが、この値を一度変更すると何故かマイナスの値を設定できなくなる。。(Swift 2.2、XCode 7.3)。
以下の動画はFalloffが「-1」の場合と、「0」の場合を比較したもの。0の方が振動が速い。減衰率が大きいほど加速度が大きくなるということか。
大きい方が振動が速くなるからといって、Falloffにプラス値を設定すると予測不能の動きをする。
以下の動画はFalloffに0.5を設定したときの動画。
バネの振動幅を維持する
バネノードを動かさないとボールは徐々に勢いが無くなり、最後は停止する。これは物理ボディに設定されているLinear Damping (線形減衰)によって減速させられるためである。⇒「Linear Dampingとは」
ではLinear Dampingを「0」に設定して動かしてみよう。なお、StrengthとFalloffはデフォルトの値に戻してから実行する。(Stringは「1」、Falloffは「-1」)
下図赤枠のSKSファイルを選択してシーンエディタを開く。シーンに配置されているボールを選択、紫枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Lin. Dampingを「0」に変更する。
以下は実際のプレイ動画。ボールの勢いが衰えなくなった。