#SpriteKitの物理エンジンについて
##物理エンジンを利用する方法
###・physicsWorld(Sceneに対して重力を与えることが可能)
物理シミュレーションを適用する空間を設定する。SKSceneの大きさで空間を設定することで、画面全体に物理シミュレーションを設定することができるようになる。
###・physicsBody(どのような物理シミュレーションを適応させるか設定可能)
physicsWorldを設定した空間に配置したスプライトに対してphysicsbodyを設定することで、そのスプライトに対して衝突判定や転がったり反発したりする物理シミュレーションを適応することができるようになる。
まぁ、色々文字で書いていっても理解しにくいかなぁと思ったので、コードで少しずつ理解しようと思います。また、記述内容に誤りがあった場合はどんどん指摘していただけると嬉しいです😊
import SpriteKit
import GameplayKit
// #A→SKPhysicsContactDelegate
class GameScene: SKScene,SKPhysicsContactDelegate {
// オブジェクト群
var background = SKSpriteNode(imageNamed: "darkPurple")
var hero = SKSpriteNode(imageNamed: "playerShip1_blue")
var block = SKSpriteNode(imageNamed: "meteorBrown_big1")
override func didMove(to view: SKView) {
// #B→self.physicsWorld.gravityとself.physicsWorld.contactDelegate
// 重力の設定
self.physicsWorld.gravity = CGVector(dx:0,dy:-3.0)
// 衝突の後にdidBeginContactメソッドが呼ばれるよ!の設定
self.physicsWorld.contactDelegate = self
// 背景画像の設定
background.anchorPoint = CGPoint(x:0,y:0)
background.position = CGPoint(x:0,y:0)
background.size = self.size
self.addChild(background)
// spaceshooterの配置
hero.position = CGPoint(x:185 ,y:50)
hero.size = CGSize(width: 50, height: 50)
self.addChild(hero)
// #C→block.physicsBody
// 岩石の配置
block.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "meteorBrown_big1"), size: block.self.size)
block.size = CGSize(width:50,height:50)
block.physicsBody?.contactTestBitMask = 1
block.position = CGPoint(x:185,y:500)
self.addChild(block)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
}
}
上記のコードはあるシーンの一部のコードです。とても簡単なコードなのですがSpriteKitで物理エンジンを用いて開発を行っていく上で今後の核となる部分なのかなぁと思いメモとして残しておきたいと思います。このコード中で重要なのは、上記のGamaScene.swiftファイル内のコードのコメントアウトで記した#A#B#C部分かなと思っています。
#A部分の何が重要なのか?
まず、この部分では、
class GameScene: SKScene,SKPhysicsContactDelegate {
と書かれていますが、上記のコードはSKSceneクラスを継承したGameSceneクラスを宣言した後に、そのGameSceneクラスに対してSKPhysicsContactDelegateプロトコルを実装しています。このSKPhysicsContactDelegateプロトコルを実装という行為がどの様な重要な役割を成し遂げているのでしょうか?
↑
(どの様な重要な役割を成し遂げているのか?)
**A、**今回のGameScene.swiftファイル内には記述できていませんが、衝突を検知した際にはたらくdidBeginContactメソッドが利用可能になる。(その他のメソッドやプロパティも含む)
このdidBeginContactメソッドを記述することによって、physicsBodyを設定したスプライト同士が衝突を起こした際などのその後の動きをdidBeginContactメソッド内に記述することで実現できる様になる。
#B部分の何が重要なのか?
まず、この部分では、
// 重力の設定
self.physicsWorld.gravity = CGVector(dx:0,dy:-3.0)
// 衝突の後にdidBeginContactメソッドが呼ばれるよ!の設定
self.physicsWorld.contactDelegate = self
と書かれていますが、(全体が見たい場合は上のコードと見比べて見てください😞)まずはphysicsWorldについて詳しく見ていこうと思います。
###physicsWorldとは?
画面(シーン)にPhysicsWorldを設定することで画面内に物理シミュレーションが反映される空間を作ることができる様になります。physicsWorldを設定した空間内(シーン)には重力やスピードといった物理シミュレーションによる動きを設定することができその動きを空間内のスプライトに反映することができます。ここでphysicsWorldを設定する為のプロパティをいくつか紹介。
プロパティ | 説明 |
---|---|
gravity | physicsWorld空間内の重力を設定することができる |
speed | physicsWorld空間内の速度を設定することができる |
上記のコードの例では、(下記のコメントアウトにて記述)
// 重力の設定(CGVectorを用いて下方向に落ちる様に重力を設定。ちなみに、地球の重力値はデフォルトで設定されている(0.0,-9.8))
self.physicsWorld.gravity = CGVector(dx:0,dy:-3.0)
// 衝突の後にdidBeginContactメソッドが呼ばれるよ!の設定
self.physicsWorld.contactDelegate = self
この記述によって、現在のシーンに対して重力が設定されました。ですがその当該シーンに対して重力が設定されただけではスプライトは下方向に落ちてくれるわけでは無いらしい。そこで重要になるのが次の**#C部分**
#C部分の何が重要なのか?
まずこの部分では、
// spaceshooterの配置
hero.position = CGPoint(x:185 ,y:50) //1
hero.size = CGSize(width: 50, height: 50) //1
self.addChild(hero)
// #C→block.physicsBody
// 岩石の配置
block.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "meteorBrown_big1"), size: block.self.size) //2
block.size = CGSize(width:50,height:50) //2
block.physicsBody?.contactTestBitMask = 1 //2
block.position = CGPoint(x:185,y:500) //2
self.addChild(block) //2
この様に書かれていますが。
(//1)部分では、heroスプライトに対してphysicsBodyが設定されていません。その為先ほどphysicsWorldで設定した下方向の重力の影響を受けません。
それに変わって、(//2)のblockスプライトに対してはphysicsBodyが設定されています。その為、先ほどphysicsWorldで設定した下方向の重力の影響を受けます。
最後に、、、
これからios開発をどんどんやっていこうと思っているのですが、ビジネスアプリケーション開発(ios)やゲームアプリケーション開発(ios)について何か良いチュートリアルだったり、有料コンテンツ、無料コンテンツなどがあったら教えていただけると嬉しいです。よろしくお願いします。
今度は、当たり判定実装して飛行船ぶっ壊してみよう!後、隕石の拡大縮小も実装してみようかな。