対戦カードゲーム開発ブログ 【2019年秋リリース(ios,android)】

【Unity】 WorldSpaceでもマルチ解像度対応したかった話

こんにちは、たかせです。カードゲーム作ってます。

ちょうど先日、テストプレイの様子をyoutubeに投稿しました。

声小さい方が僕なんですが、こう改めて視聴してみると実況に慣れてない感じがひしひしと伝わってきますね。もっと大きな声でとか、言葉選びは慎重にとか、反省点が多いです。

さて、今回はマルチ解像度に対応する話です。

背景

例えば今回のテストプレイを撮影したiPhoneXだと、以前までこんな風に表示されていました。

   





_人人人人人人人人_
> MPが見えない <
 ̄YYYYYYYY^ ̄





UnityEditor上だとこんな感じ。

ちなみに横幅が広い端末だと青空が写り込んでしまう状況でした。

とりあえずぐぐった感じ、CanvasのRenderModeをScreen Space OverrayScreen Space Cameraにすると解決できそうだとわかったんですが、BeyondTheFieldではWorldSpaceのRenderModeで開発を進めていたため、この方法は採用できませんでした。

WorldSpaceによるUI設計には次の記事のような恩恵があるようです。そこまで詳しく把握できていないので説明は割愛しますが、今回はエンジニアの意地💪を見せたかったのもあり、WorldSpaceのままマルチ解像度に対応する方針で修正を進めました)

tsubakit1.hateblo.jp

修正方針

次の方針で修正することにしました。

  • カメラに映る領域を2つのレイヤーに分ける
    • Screenレイヤー: 端末サイズに合わせて拡大/縮小するレイヤー
    • Contentレイヤー: 縦横比を維持したまま端末にちょうど収まるように拡大/縮小するレイヤー
  • ScreenレイヤーとContentレイヤーを適切にリサイズするスクリプトを作る

なお、前提条件は次のとおりです。

  • CanvasのRenderModeはWorldSpace
  • カメラの位置とパラメータはゲーム中に変化しない
  • UIを正しく表示できるサイズが事前に決まっている

今回の例だと、表示したいUIは1080 x 1920で正しく表示できるように設計しています。

先に修正結果

iPhoneXにおける見え方はこのようになりました。

また、冒頭で青空の写り込んでいた端末ではこのようになりました。

良かったこと

  • UIやエフェクトが画面外に表示されてしまう問題を解決できた
  • iPhoneXにおいて、UIをセーフエリア内に収めることが出来た
  • 修正が楽だった(1日)

良くないこと

  • 端末によっては、無駄な領域が生まれてしまう
  • iPhoneX以外でセーフエリア内に収まる保証がない

修正項目は次の2つだけで、UIの配置変更では表示崩れは起きなかったので比較的楽に修正を完了することが出来ました。

  • Scene直下に配置していたUIに親を与える
  • スクリプトを1つ作成する

1080x1920を想定していたとはいえ、Anchorやlocal属性による相対的な位置取りを意識して作成していたことが功を奏したと思います(例えば540x960のサイズでも表示崩れは起きなかった)。

また、偶然といえば偶然なのですが、iPhoneXにおけるPortrait表示においてセーフエリア対応もできてしまいました。まだAppleへの審査には提出したことがないのでなんとも言えないですが、Width > Heightの状態がPortraitなセーフエリア持ちの端末が出てこない限りはこれで大丈夫...なはず...(リリース時にはLandscape状態を禁止する予定です)

楽に修正できた反面、褒められた修正ではないなぁ、という思いはあります。理想的なマルチ解像度対応を考えれば、それはその解像度で提供しうるUXを最大化することだと思うので、ゆくゆくはこの方針で再修正したいものです。

修正方法

一応前提条件の確認です。

  • CanvasのRenderModeはWorldSpace
  • カメラの位置とパラメータはゲーム中に変化しない
  • UIを正しく表示できるサイズが事前に決まっている

これらの条件を満たさない場合は、他に良い修正方法がある可能性が高いのでご注意ください。この条件を満たしている場合でも他にいい方法があれば教えてほしいです🙇‍♂️

1. ScreenレイヤーとContentレイヤーを作成する

まずは、Scene直下にScreenレイヤーを配置します。ScreenレイヤーにはCanvas系の一式をアタッチし、RenderModeをWorldSpaceに変更します。

※開発しやすいようwidth, heightに初期値を与えていますが、この値は実行時にスクリプトによって書き換えられます

次に、Screenレイヤーの子供としてContentレイヤーを追加し、Anchorsを中心に、widthとheightを想定しているサイズに合わせます。

※Contentレイヤーのwidth, heightはスクリプトによる書き換えはありません。代わりにscaleを書き換えます

最後に、Screenレイヤーの二人目の子供として背景画像を追加します。こちらの画像はAnchorsを両軸ともStretchにし、Screenレイヤーのサイズ変更を追従するようにしておきます。

2. Contentレイヤーがちょうど収まるようにカメラを調整する

カメラのパラメータを調整し、ViewPortのサイズとContentのサイズを一致させます。

※SceneエディタのGizmosをONにすると、カメラのViewPortサイズを確認可能です。

3. 各種レイヤーをリサイズするスクリプトをアタッチする

DynamicScreenViewというスクリプトを作成したので、これをスクリーンレイヤーにアタッチし、各種パラメータを設定します。

gist.github.com

  • ScreenRect: 手順1で作成したScreenレイヤーを設定します
  • ContentRect: 手順1で作成したContentレイヤーを設定します
  • SubContentRect: 後述します(設定しなくても動作します)
  • Cam: 手順2で調整したカメラを設定します

4. 完了!

後はContentレイヤーの中にUIを追加していくだけです。ここまで読んでくれてありがとうございます🥰

5. Contentレイヤーが1つでは満足できないあなたに

DynamicScreenViewはz座標の異なる複数のContentレイヤーに対応しています。

使い方は、先程の説明にあったSubContentRectsに追加するだけです。

SubContentRectsに追加しない場合

SubContentRectsに追加する場合

終わりに

BeyondTheFieldはiPhoneXでも遊べる新作カードゲームです!!!(当たり前)

twitter.com

わりと手探りで修正を終わらせた感は否めないので、何か変な点があればご指摘いただけると幸いです。それではまたー!