【Swift】SpriteKitの使い方。物理エンジンを使ってノードに重力をかける。(Swift 2.2、XCode 7.3)
物理エンジンとは
本記事ではSpriteKitの機能の物理エンジンについて説明する。
物理エンジンとは、ノードに重力加速度や衝突などの物理現象を発生させる機能である。この機能を使うと、現実世界と同じようような物理運動をするノードを表現できる。
ノードを落下させる
実際に物理エンジンを使ってノードを画面下に落としてみよう。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。
⇒「テスト用プロジェクト」
以下のコードは変更前のTestScene.swift。
TestSceneが現在シーンになったら、背景と鳥2匹のノードをシーンに設定している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// // TestScene.swift // import Foundation import SpriteKit class TestScene:SKScene { var birdNode1:SKSpriteNode! var birdNode2:SKSpriteNode! //現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //背景画像のノードを作成する。 let backNode = SKSpriteNode(imageNamed: "mountain") //背景画像のサイズをシーンと同じにする。 backNode.size = self.frame.size //背景画像の位置をシーンの中央にする。 backNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); //鳥のノードを作成する。 birdNode1 = SKSpriteNode(imageNamed: "bird1") birdNode2 = SKSpriteNode(imageNamed: "bird2") //鳥の座標を指定する。 birdNode1.position = CGPointMake(self.frame.width / 3, CGRectGetMidY(self.frame)); birdNode2.position = CGPointMake(self.frame.width * 2 / 3, CGRectGetMidY(self.frame)); //ノードをシーンに追加する。 self.addChild(backNode) self.addChild(birdNode1) self.addChild(birdNode2) } } |
TestScene.swiftに以下のメソッドを追加する。
ノードにSKPhysicsBodyのインスタンスを設定するだけで、そのノードは重力を受ける物体として落下し始める。引数には、物体の領域を指定するための画像とサイズを与えている。
1 2 3 4 5 6 7 8 |
//画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //鳥ノードに物理ボディを設定する。 birdNode1.physicsBody = SKPhysicsBody(texture: birdNode1.texture!, size:birdNode1.size) } |
以下は実際のプレイ動画
タップしたノードを落下させる
ちなみに、物理エンジンとは関係ないが、タップしたノードに物理ボディを設定するには以下のようにする。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチした座標のノードを取得する。 let location = touches.first!.locationInNode(self) let node = nodeAtPoint(location) as! SKSpriteNode //鳥ノードの場合、物理ボディを設定する。 if(node == birdNode1 || node == birdNode2){ node.physicsBody = SKPhysicsBody(texture: node.texture!, size:node.size) } } |
以下は実際のプレイ動画
画面外に落ちていかないようにする
先ほどの例では、ノードは画面下端を通りぬけてそのまま落ちていく。画面端から物体を出ていかないようにしたい場合は以下のコードをdidMoveToViewメソッドに追加する。
画面端を物体の領域とする物理ボディをシーンに設定した。
1 2 3 4 5 6 7 8 9 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { ‥省略‥ //画面端に物理ボディを設定する。 self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) } |
以下は実際のプレイ動画。
もちろん、以下コードのように枠のサイズを指定すれば任意の場所を壁にできる。
1 2 3 4 5 6 7 8 9 10 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { ‥省略‥ //物理ボディを設定する。 self.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(0, 100, frame.size.width, frame.size.height)) } |
以下は実際のプレイ動画
地面用のノードを追加する
地面用のノードを追加して落下するノードが落ちないようにしてもいい。その際、地面用のノードが落下してしまわないように、ノードのdynamicプロパティをfalseにすること。
具体的にはdidMoveToViewメソッドを以下のコードのように変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //背景画像のノードを作成する。 let backNode = SKSpriteNode(imageNamed: "mountain") //背景画像のサイズをシーンと同じにする。 backNode.size = self.frame.size //背景画像の位置をシーンの中央にする。 backNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); //鳥のノードを作成する。 birdNode1 = SKSpriteNode(imageNamed: "bird1") birdNode2 = SKSpriteNode(imageNamed: "bird2") //鳥の座標を指定する。 birdNode1.position = CGPointMake(self.frame.width / 3, CGRectGetMidY(self.frame)); birdNode2.position = CGPointMake(self.frame.width * 2 / 3, CGRectGetMidY(self.frame)); //地面のノードを作成する let kabeNode = SKSpriteNode(color: UIColor.brownColor(), size: CGSize(width: frame.size.width, height: 100)) kabeNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(kabeNode.frame)) //地面のノードに物理ボディを設定する。 kabeNode.physicsBody = SKPhysicsBody(rectangleOfSize: kabeNode.frame.size) //重力の影響を受けないようにする。 kabeNode.physicsBody?.dynamic = false //ノードをシーンに追加する。 self.addChild(backNode) self.addChild(birdNode1) self.addChild(birdNode2) self.addChild(kabeNode) } |
以下は実際のプレイ動画
重力の方向や加速度を変更する
重力の方向や加速の大きさは画面下方向だけではなく、gravityプロパティの値を変更すれば方向も加速度も自由に変更できる。デフォルトはX方向「0」、Y方向「-9.8」に設定されている。高校の授業で習ったg(9.8m/s^2)だ。
例えば、画面左方向に重力をかけたい場合は以下のコードになる。
1 2 3 4 5 6 7 8 9 10 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { ‥省略‥ //重力加速度の設定 self.physicsWorld.gravity = CGVector(dx:-9.8, dy:0.0) } |
以下は実際のプレイ動画。左に落ちていった。重力加速度で飛行する鳥。。夢のような世界だ。