【Swift】SpriteKitの使い方。シーンを重ねて表示する。(Swift 2.2、XCode 7.3)
SKReferenceNodeとは
本記事ではSpriteKit Sceneファイルの編集画面(シーンエディタ)の部品一覧にあるSKReferenceNode(以下、参照ノード)について説明する。
参照ノードとは、SpriteKit Sceneファイル(以下、SKSファイル)やパーティクルファイルなどを参照して、シーンに配置するノードである。これを使えば、シーンの中に別のシーンを重ねて表示するようなことができる。
参照ノードを使ってみる
実際に参照ノードを使って、2つのシーンを重ねて表示してみよう。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」
事前準備で2つのシーンを作成しておいた。
1つ目のシーン(以下、シーン1)は、背景と猿とスピーカーのノードを配置し、ドラッグ&ドロップで猿を運べるようにした。
2つ目のシーン(以下、シーン2)は、2匹の鶏のノードを配置し、左右に自動で往復するようにしておいた。
これから、参照ノードを利用してシーン1にシーン2を重ねて表示させる。
下図赤枠のSKSファイルを選択してシーンエディタを開く。黄緑枠のオブジェクトライブラリボタンを押して部品一覧を表示し、ドラッグ&ドロップで「Reference」をシーンに配置する(紫矢印)。
黄枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Nameに「referenceNode」、Referenceに「TestScene2.sks」、PositionにX「0」、Y「0」を入力する。
PositionにX「0」、Y「0」を入力した理由は、参照ノードの座標がアンカーポイントになってノードが配置されるためである。なので仮に、シーン2のアンカーポイントが別の座標だったら、参照ノードもその座標に合わせることになる。
以下は実際のプレイ動画。2つのシーンが重なって表示された。
ちなみに、ソースコードで参照ノードを追加するときはdidMoveToViewメソッドを以下のコードのようにする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //SKSファイルに配置したノードを取得する。 monkey = self.childNodeWithName("monkey") as? SKSpriteNode speaker = self.childNodeWithName("speaker") as? SKSpriteNode //シーン2のパスを作成する。 let path = NSBundle.mainBundle().pathForResource("TestScene2", ofType: "sks") //参照ノードを作成する。 let refNode = SKReferenceNode(URL: NSURL(fileURLWithPath: path!)) //参照ノードをシーンに追加する。 self.addChild(refNode) } |
ちなみに、参照ノードを作成するときにファイル名を指定するとエラーが発生する(Swift 2.2、XCode 7.3)
1 2 3 |
//参照ノードを作成する。 let refNode = SKReferenceNode(fileNamed: "TestScene2.sks") |
参照先のノードを取得する
通常はシーンに配置したノードを取得するときは、ノード名を引数に以下のメソッドを呼び出して取得してきた。
1 2 3 |
//シーンに配置したノードを取得する。 let monkey = self.childNodeWithName("monkey") as? SKSpriteNode |
しかし、上記だとシーンの子ノードしか検索対象になってないので、孫ノードや、参照ノードが配置したノードが検索できない。
孫ノードや、参照ノードが配置したノードも検索対象に含めたい場合は、検索文字列の先頭に「//」をつけてノードツリー全体を検索対象にする。
1 2 3 |
//シーンに配置したノードを取得する。 let monkey = self.childNodeWithName("//monkey") as? SKSpriteNode |
検索文字列にはワイルドカードを含めることができる。例えば、ノードツリー全体を検索対象とし、かつ、「m」から始まるノードを検索する場合は以下のコードになる。
1 2 3 |
//シーンに配置したノードを取得する。 let monkey = self.childNodeWithName("//m*") as? SKSpriteNode |
以下のコードは先頭が「m」、2文字目が「o、p、q」のノードが抽出される。
1 2 3 |
//シーンに配置したノードを取得する。 let monkey = self.childNodeWithName("//m[o-q]*") as? SKSpriteNode |
階層を指定した検索もできる。検索文字列の記述方法について詳しくは公式リファレンスを参照されたし。
⇒公式リファレンス「SKNode」
1 2 3 4 5 6 |
//参照ノード「referenceNode」の中の「chicken1」という名前のノードを検索する。 let chickenNode = self.childNodeWithName("referenceNode//chicken1") as? SKSpriteNode //親ノード「nodeA」の中の「nodeB」という名前の子ノードを検索する。 let nodeB = self.childNodeWithName("nodeA/nodeB") as? SKSpriteNode |
上記を踏まえて、スピーカーがタップされたら鶏ノードを消すには、TestScene.swiftのtouchesBeganメソッドを以下のコードに変更する。
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 |
//画面タッチ開始時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチしたノードを取得する。 let location = touches.first!.locationInNode(self) let node = nodeAtPoint(location) as! SKSpriteNode if(node == speaker) { //鶏ノードを取得する。 let chickenNode = self.childNodeWithName("//chicken1") as? SKSpriteNode //パーティクルを作成する。 let particle = SKEmitterNode(fileNamed: "SmokeParticle.sks") //接触座標にパーティクルを放出するようにする。 particle!.position = CGPoint(x:chickenNode!.position.x, y:chickenNode!.position.y - 50) //鶏ノードを削除する。 chickenNode?.removeFromParent() //パーティクルをシーンに追加する。 self.addChild(particle!) } } |
以下は実際のプレイ動画。鶏が1匹消えた。
childNodeWithNameメソッドで取得できるノードは1つだけである。たとえ検索文字列にマッチするノードが複数あったとしても、最初に見つかったノードのみ取得される。
鶏を全部消したいときは、以下のコードのようにenumerateChildNodesWithNameメソッドを利用する。
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 |
//画面タッチ開始時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチしたノードを取得する。 let location = touches.first!.locationInNode(self) let node = nodeAtPoint(location) as! SKSpriteNode if(node == speaker) { self.enumerateChildNodesWithName("//chicken[0-9]") { node, stop in //パーティクルを作成する。 let particle = SKEmitterNode(fileNamed: "SmokeParticle.sks") //接触座標にパーティクルを放出するようにする。 particle!.position = CGPoint(x:node.position.x, y:node.position.y - 50) //鶏ノードを削除する。 node.removeFromParent() //パーティクルをシーンに追加する。 self.addChild(particle!) } } } |
以下は実際のプレイ動画。スピーカーをタップしたら鶏が全部消えた。