A Day In The Life

とあるプログラマの備忘録

SpriteKit SceneをiPhone/iPadのホームバーに対応させる

3年間放置していたiOSアプリをホームバーに対応させた話

かれこれ3年くらい放置していた iPhone/iPad 両対応のアプリをホームバーに対応させようと思ったら結構大変だったのでその記録です。 ちなみに放置していたアプリはこちらです。

ピアノ - 即興ピアノ

ピアノ - 即興ピアノ

  • taisuke fujita
  • ミュージック
  • 無料
apps.apple.com

対応前の設定はこんな感じ

4.7インチの iPhone(6, 6S, 7, 8, 第2世代SEなど1334 * 750ピクセル)をベースにiPadにも対応させるため、SKScene の幅を1334ピクセル高さを1000.5ピクセル(4:3)に設定し、アンカーポイントを(0, 0)に設定してました。 以前の画面 4:3の iPad を表示領域として、スプライトを16:9の iPhone の領域におさまるように配置するイメージです。この設定だと iPhone だとぴったりで iPad だと上下に余白ができます。 シーンのスケールモードの設定は aspectFill に設定してました。

class GameViewController: UIViewController {
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        if let view = self.view as! SKView? {
            // Load the SKScene from 'GameScene.sks'
            if let scene = GameScene(fileNamed: "GameScene") { 
                // Set the scale mode to scale to fit the window
                scene.scaleMode = .aspectFill
                // Present the scene
                view.presentScene(scene)
            }
        }
    }
}

ホームバーの無い iPhone 8iPad Pro 第2世代では問題なく表示できていました。しかし iPhone X 以降(またはiPad Pro 11, 12.9インチ)のホームバー付きの端末で表示させる以下のようになりました。 はみ出た 全体が拡大されてスプライトがはみ出ています。

ホームバーに対応する手順

iPhone X 以降(またはiPad Pro 11, 12.9インチ)のホームバーに対応する手順は以下のようになります。

  1. SKSceneのサイズを16:9に合わせて変更する
  2. アンカーポイントを(0, 0)から(0.5, 0.5)に変更する
  3. presentSceneを呼び出すタイミングでSceneのサイズを調整する

手順1と2でシーンエディタの修正をします。手順3でプログラムの修正をします。

SKSceneのサイズを16:9に合わせて変更する

SKScene のサイズを16:9に合うように変更します。私の場合は1334 * 1000.5だった設定を1334 * 750に変更しました。16:9であれば960 * 540だったり、2208 * 1242だったりでも問題ないようです。作成したスプライトの画像サイズに合うように適宜変更すれば良いようです。ポイントは縦横比が16:9になるように SKScene のサイズを設定することです。

Sceneのアンカーポイントを中央にする

16:9 の iPhone の画面にぴったり合うようにスプライトを配置すると iPhone 11 系では左右に余白ができ、iPad 系では上下に余白ができます。この余白に影響を受けないようにするにはアンカーポイントを中央(0.5, 0.5)に設定する必要があります。シーンのアンカーポイントを変更するとスプライトの位置が変わってしまうので適宜スプライトの位置も変更します(地味にこの作業が一番めんどくさい)。

ここまでの修正を反映するとこんな感じです

修正後の画面

presentSceneを呼び出すタイミングでSceneのサイズを調整する

UIView の presentScene メソッドを呼ぶタイミングで、UIView のサイズ(機種によってサイズがかわる)と SKScene のサイズの比率を計算して SKScene のサイズを調整してあげます。スケールモードの設定は aspectFill から aspectFit に変更します。

class GameViewController: UIViewController {
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        if let view = self.view as! SKView? {
            // Load the SKScene from 'GameScene.sks'
            if let scene = GameScene(fileNamed: "GameScene") {
                var factor = view.frame.size.height / scene.size.height
                // iPad
                if view.frame.size.width / factor < scene.size.width {
                    factor = view.frame.size.width / scene.size.width
                }
                scene.size = CGSize(width: view.frame.size.width / factor,
                                       height: view.frame.size.height / factor)
                
                // Set the scale mode to scale to fit the window
                scene.scaleMode = .aspectFit
                // Present the scene
                view.presentScene(scene)
            }
        }
    }
}

手順を適用した結果はこちら

手順1から3を適用して修正した結果は以下のようになります。

iPhone 8

ホームバーなし(ホームボタンあり)の従来型の iPhone 画面です。 iPhone8

iPhone 11

ホームバーありの新型の iPhone 画面です。左右に余白ができています。 iPhone11

iPad Pro 11インチ

ホームバーありの新型の iPad 画面です。上下に余白ができています。 iPad Pro

参考記事