【SpriteKit】シーンサイズとデバイス画面サイズの合わせ方


この記事について

SpriteKitでゲームを開発する際に、数年前はXcodeのGUIを使わずにガリガリとコーディングするのが当たり前でしたが、最近はGUIによるアシストが充実してきて、Unityっぽく開発ができるようになりました。
この記事では、SpriteKitでゲーム開発をする際の最初の一歩である「ビューにシーンを表示する」部分に焦点を当てました。

ビューとシーン

UIKitでアプリを開発する場合、ルートビューにどんどんビューを乗せていくカタチになります。
この時のルートビューとはUIViewクラスであり、サブビューは主にUIViewのサブクラスだったりします。

対してSpriteKitでのゲーム開発では、ルートビューはSKViewになります。
また、ゲーム自体はシーンと呼ばれるSpriteKitSKSceneクラス内で描画されます。
つまり、SKView(ビュー)にSKScene(シーン)を表示させることになります。

このとき、ルートビューSKViewはデバイス画面サイズになっているわけですが、シーンSKSceneは開発者が適切な寸法にリサイズしてあげる必要があります。

動作環境

Swift3.0.1
Xcode8.2
iOS10.2

プロジェクト準備

iOSのSingle View Templateで新規プロジェクトを作成
ViewController.swiftファイルの名をGameViewController.swiftに変更(ナビゲータエリア)
クラス名をViewControllerからGameViewControllerに変更(エディタエリア)
ビューコントローラのルートビューをSKViewに変更(インスペクタエリア)

GameSceneクラスを定義

メニューバーから「File > New > File... > iOS > Cocoa Touch Class」を選択して、GameScene.swiftとして保存

GameScene.swift
import SpriteKit

class GameScene: SKScene {
    // something to do
}

新規シーンファイルを作成

メニューバーから「File > New > File... > iOS > Resource > SpriteKit Scene」を選択して、GameScene.sksとして保存

アンカーポイントとサイズ

図. 新規作成したシーンのファイル

サイズ(w:750, h:1334), アンカーポイント(X:0.5, Y:0.5)になっています。
サイズはiPhone7の4.7インチの状態、アンカーポイントはシーンの中央にある十字印です。
ちなみに、4.7インチのビューコントローラではビューのサイズは(X:375, Y:667)です。
シーンはピクセル単位、ビューコントローラはポイント単位になっていることがわかります。

シーンを表示する

この状態でシーンをビューに表示すると、どんな風に見えるでしょうか。
シーンに表示する適当な画像を用意します。

図.適当な画像(background.png)

画像をプロジェクトにインポートして、シーンにドラッグ&ドロップで配置します。
シーンに画像を配置すると、スプライトノードになります。
スプライトノードは、シーンいっぱいに広げて枠とピッタリになるようにしておきます。

図.シーンに配置されたスプライトノード

このシーンは、iPhone7(4.7インチ)の画面サイズになっています。
以下のように記述して、シミューレータに表示して見ましょう。

GameViewController.swift
import UIKit
import SpriteKit

class GameViewController: UIViewController {

    let gameScene = GameScene(fileNamed: "GameScene")

    override func viewDidLoad() {
        super.viewDidLoad()

        if let skView = view as? SKView {
            skView.presentScene(gameScene)
        }
    }

}

ビルド

シミュレータはiPhone7を選択します。

中央に寄ってしまって、全体が表示しきれていません。
次のようにコードを修正しましょう。

GameViewController.swift
class GameViewController: UIViewController {

    let gameScene = GameScene(fileNamed: "GameScene")

    override func viewDidLoad() {
        super.viewDidLoad()

        if let skView = view as? SKView {
            gameScene?.scaleMode = .aspectFill
            skView.presentScene(gameScene)
        }
    }

}

これで、シーンをビューにピッタリ合わせて表示できるようになりました。