【Swift】SpriteKitの使い方。タイトル画面、プレイ画面、結果画面の順番でシーンを切り替える。(Swift 2.2、XCode 7.3)
シーン切替えとは
今までのSpriteKitの記事は、1つのシーン内で物理ボディを動かしたり、衝突させたりしてきた。ゲームは通常、下図のようにタイトル画面、プレイ画面、結果画面などのシーンを切り替えながら進んでいく。
シーン切替えを試す
実際にシーンの切替えを実装してみよう。以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」
事前準備では、タイトル画面シーン、プレイ画面シーン、結果画面シーンの3つを作成しておいた。
タイトル画面にはスタートボタンを配置してある。現段階ではボタンを押しても何も起きない。
以下のコードは変更前のTitleScene.swift。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// // TitleScene.swift // import Foundation import SpriteKit class TitleScene:SKScene { //現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //画面サイズを合わせる self.scaleMode = .AspectFit } //画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { print("タップしました。") } } |
プレイ画面には鳥ノードを1匹配置した。ドラッグした位置に鳥ノードが移動し、ドロップすると地面に落下する。
以下のコードは変更前のPlayScene.swift。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
// // PlayScene.swift // import Foundation import SpriteKit class PlayScene:SKScene, SKPhysicsContactDelegate { var startDate:NSDate! var birdNode:SKSpriteNode! //現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //画面端に物理ボディを設定する。 self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) //鳥ノードを取得する。 birdNode = self.childNodeWithName("bird_brown") as? SKSpriteNode //カテゴリマスクを設定する。 self.physicsBody?.categoryBitMask = 0b0001 //デリゲート先を自分に設定する。 self.physicsWorld.contactDelegate = self } //画面タッチ開始時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //タップ開始日時を取得する。 startDate = NSDate() } //画面タッチ移動時の呼び出しメソッド override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチした位置まで移動するアクションを作成する。 let location = touches.first!.locationInNode(self) let action = SKAction.moveTo(CGPoint(x:location.x, y:location.y + 20), duration:0.1) //アクションを実行する。 birdNode!.runAction(action) } //画面タッチ終了時の呼び出しメソッド override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { //重力の影響を受けるようにする。 birdNode.physicsBody?.affectedByGravity = true } //衝突検知時の呼び出しメソッド func didBeginContact(contact: SKPhysicsContact) { print("衝突しました") } } |
結果画面シーンにはスコアを表示するためのラベルノードを配置しておいた。
以下のコードは変更前のResultScene.swift。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// // ResultScene.swift // import Foundation import SpriteKit class ResultScene:SKScene { var score:Int = 0 //現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { print(score) } } |
まずは、タイトル画面のスタートボタンが押されたらプレイ画面にシーンが切り替わるものを実装する。
TitleScene.swiftのtouchesBeganメソッドを以下のコードに変更する。このように、遷移先シーンのインスタンスを引数にpresentSceneメソッドを呼び出すとシーンが切り替わる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//画面タッチ時の呼び出しメソッド override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチしたノードを取得する。 let location = touches.first!.locationInNode(self) if let node = nodeAtPoint(location) as? SKLabelNode { //タッチしたのがラベルノードの場合、スタートボタンなのかを確認する。 let startButton = self.childNodeWithName("start") as? SKLabelNode if(node == startButton) { //スタートボタンを押した場合はプレイ画面に切り替える。 let result = PlayScene(fileNamed: "PlayScene") self.view!.presentScene(result) } } } |
以下は実際のプレイ動画。スタートボタンを押したらプレイ画面に移動し、ゲームができるようになった。
次は、プレイ画面で鳥ノードを画面端に触れさせてしまった時点で、結果画面にシーンが切り替わるものを実装する。
PlayScene.swiftのdidBeginContactメソッドを以下のコードに変更する。
presentSceneメソッドでシーンを切り替える前に、ドラッグした秒数を結果画面シーンのスコアプロパティに設定している。つまり、鳥を飛ばし続けるほどスコアが高くなる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//衝突検知時の呼び出しメソッド func didBeginContact(contact: SKPhysicsContact) { //デリゲートを解除する。 self.physicsWorld.contactDelegate = nil //結果画面シーンを生成する。 let result = ResultScene(fileNamed: "ResultScene") //タップ時間を結果画面シーンのスコアに設定する。 let stopDate = NSDate() result!.score = Int(stopDate.timeIntervalSinceDate(startDate!)) //結果画面シーンに切り替える。 self.view!.presentScene(result) } |
ResultScene.swiftのdidMoveToViewメソッドを以下のコードに変更する。
プレイ画面で設定したスコアプロパティの値をラベルに表示している。
1 2 3 4 5 6 7 8 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //スコアラベルにスコアを表示する。 let scoreLabel = self.childNodeWithName("score") as? SKLabelNode scoreLabel?.text = "\(score)点" } |
以下は実際のプレイ動画
今回は画面数が少ないので、スコア渡しは遷移先シートのプロパティに設定するだけでも問題ないが、画面数が増えるとシーン切替えのたびに遷移先シートのプロパティに値を設定するのは煩雑だ。
そんなときは、SKViewのサブクラスにシーン全体で使うプロパティを追加するのが良い。