LoginSignup
84
75

More than 3 years have passed since last update.

[Unity初心者Tips]画面を切り替える3つの方法、そしてSceneManager.LoadSceneAsyncなど

Last updated at Posted at 2016-12-24

作ってて気付いた、小ネタです。
Unityを触りはじめてから、最初はプロトタイプ的なものを作って、次の段階にはスタート画面からゲーム本体、ゲームオーバーやポーズなど、画面全体を切り替える実装に進むパターンが多いです、そこで何を使ったら良いか、考えてみましょう。
https://gyazo.com/8da619579bfae682d8992480b5d5dfcf

画面を切り替える方法の幾つかを比較

Unityで、例えばスタート画面からゲーム本体など、画面の切り替えをしたいとき、幾つか方法があります。

●方法1:Sceneを一つのままGameObjectなどを表示、非表示で制御

Scene中にGameObjectを置いた状態でgameObject.SetActive (false);の状態からtrueに切り替えるかenabled=falseからtrueにする、画角の外においた状態から画角内に座標を変える、などの方法をとります。

全部を用意したSceneでSetActiveなどで切り替え
https://gyazo.com/ab0e3beba427ea3c5a5c2cdcb95f97ba

  • 読み込み時間などを考慮するとこれが良いと推奨されてきた方法
  • ◯ 読み込みを始めに済ませておくと表示に時間はかからない
  • ◯ データが残っているのでもとに戻すのも容易、ガベージコレクション回避に繋がる
  • ✘ データを全部Scene内で定義するので分離できない(Prefab化して別個にすることは可)

とりあえず実験的にやる場合には、手間がかかりません。

●方法2:Prefabで用意、Object.Instantiateで配置

表示したいものをPrefabで別個に用意して、表示したい時にObject.Instantiateで画面上に登場させます。

必要なPrefabを読み込む
https://gyazo.com/ea39b902b892b7ae965e6a7e48568527

  • ◯座標も設定しておけば実装は簡単
  • ◯ファイルで独立するので別個に作って統合は可能(GUIDに注意)
  • △エディタでは、実行しないとInstantiateした状態の確認ができない
  • △読み込みに少し時間を要する
  • △メモリを後から消費するのでガベージコレクションなどで不利になる可能性

Sceneがごちゃごちゃしないのが良いですが、重ねて読み込むとメモリ消費が増えます。要らない他を破棄すればいいとなると、ガベージコレクションの誘引にもなるので、そこまでするならSceneごと読み込むほうが良いです。

●方法3:別個にSceneを用意してLoadする

エディタで画面を別個のSceneとして作っておき、それをSceneManager(5.3以降)で読み込ませんる方法です。旧バージョンだとApplication.LoadLevelなどで実装していました。

全部、入れ替える
https://gyazo.com/7ca216f140d8e908d9b497ed55ed9a39

  • ◯Sceneが独立するのでファイル単位で別データになり分担を分けやすい
  • ◯Singleならスッキリ全部、切り替わる
  • △Scene間で共有したいデータはStatic等で破棄されない構造にする必要がある
  • ✘読み込みと初期化で時間がかかる場合がある

こういう感じになります。

画面切り替えの選択

こうしてみると、以下のルールが明らかになります。

  • 既に配置状態のものは時間がかからないが最初からメモリを食う可能性がある
  • 後から読み込む、要らないものは破棄にすると時間が掛かるがメモリを消費しない

ということです。これは他の処理でも同様です。あとは別個に分担するなどでデータがファイルで別れたほうが良いか、等で選ぶと良いでしょう。以下は一例です。

適したパターンの比較

切り替えの種類 適した方法の例
画面に在るものに重ねたい、出したり隠したりが多い 常駐させて表示・非表示の切り替え
たまにしか出さない、それによって動作が緩慢になっても気にならない(ポーズ画面など) Prefabで用意
画面が全面的に切り替わり、元の表示が要らない(スタート画面など) Sceneを切り替え

これが必ずしも正解かは分からないので、そのゲームにあった方法を選択してください。

プロトタイピングする順番

表示の状態を試す場合は以下が良いと思いますが、予め、設計の方針が決まっている場合はそれに従いましょう。

  1. 先ずは単一Sceneで作って表示・非表示の切り替え
  2. Sceneが肥大化したらPrefab分けてInstantiate、何度か使う場合は破棄しないでメモリに置いたままにする
  3. 画面が全部、切り替わってその際のタイムラグがプレーヤーのストレスが少ないならSceneで分ける

例えば、ゲーム中にキャラクターのステータスを出すなら元からある画面に重ねるし共有する値が多いのでCanvasに作っておいて表示・非表示を切り替える。アクションゲームでのゲームオーバーからリスタートでメニュー画面へ遷移なら、プレイヤーはゲームオーバーの時点で少し間が空いてもそこで休憩する意思が働くし画面が全体で切り替わるので、Scene全体で切り替える、等です。

Scene切り替えで何を使うべきか

Sceneの読み込みには、以下の2つが在り、違いを理解すると良いプレイヤー体験を提供できます。

モードをLoadSceneMode.Singleにすると、上記の何れでも入れ替え動作になります。
ここで、どちらが良いかというと、以下の理由に因りSceneManager.LoadSceneAsyncを勧めます。

  • LoadSceneMode.Singleは画面が固まったような状態になる
  • 読み込みで固まっていてもタップなどの入力が効き、読み込まれた後のScene側で対処していない場合は、イベントが入ってくることがある

これが厄介で、画面の固まった状態で連続タップしてると次に読み込まれたシーンの操作をしてしまう状態になります。もちろん、画面が固まったような状態はプレイヤーに見せるすべきではありませんから、このパターンに限らず「今、何が起こっているか」を分かる状態にしておくためにも、SceneManager.LoadSceneAsyncが重宝されます。これを使った時の難点は非同期で読み込むので影で読み込んでる間はメモリを多く消費し、ガベージコレクションの誘引などを考えると、以下に該当する場合は適しています。

[SceneManager.LoadSceneAsyncの適したパターン]

  • 現在のSceneのオブジェクトがほぼ次の表示で要らなくなる
  • LoadするSceneのデータもその後、SceneManager.LoadSceneAsyncで置き換えられる

まとめ

データの読み込みや破棄なので、また使うであろうデータを破棄してから再び読み込むと、メモリの取得と破棄により無駄な処理が入り、更には分断化したためにガベージコレクションが起きます。ただし、それだけを考えるとメモリをどんどん消費し、結果的にそのためのガベージコレクションがあり得ます。プロファイラで様子を見ながら試しましょう。

最優先すべきはプレイヤーの体験を最良にする方法です

参考

メモリ管理については以下を参照してください。
Unity マニュアル/自動メモリ管理を理解する
https://docs.unity3d.com/jp/current/Manual/UnderstandingAutomaticMemoryManagement.html

初心者以上にとても参考になる記事

こちらの記載が管理システムにも研究されていてとても参考になります。
https://madnesslabo.net/utage/?page_id=11109#i

こちらにもいろいろ書いています。参考にしてみてください。
Unityチュートリアルindex
http://qiita.com/JunShimura/items/f87c599b3738b804f605

84
75
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
84
75