【Unity】同時に複数のシーンを使うことのメリットとデメリットを考える

Unityでは同時に複数のシーンを読み込むことができます。単一のシーンを読み込む形だと、前のシーンが破棄されてから新しいシーンがロードされますが、追加読み込みの形にすれば前のシーンを使いつつ、新しいシーンも読み込むことができます。
複数シーンの実装の仕方は十人十色で開発者によってまちまちだったりします。そのため、判断のきっかけのひとつになるよう、このメリット、デメリットを考えていきたいと思います。
参考
Unityでノベルゲームを作る際に助かる「宴」のMadnessLaboさんが複数シーンを使った実装についてまとめてくださっているので、こちらが非常に参考になります。
同時に複数のシーンを読み込む方法
複数のシーンを同時に読み込む際には、SceneManagerのLoadScene()を呼び出す際に読み込みモードを指定します。
単独でロードする場合、つまりそれまでのシーンを破棄して新しいシーンをロードする場合はLoadSceneMode.Singleを指定します。第2引数を指定しない場合はこちらのモードでロードされます。
既存のシーンに追加でロードする場合はLoadSceneMode.Additiveを指定します。この場合、既存のシーンは破棄されないので、必要のなくなったシーンはUnloadSceneAsync()などを使って自分で破棄する必要があります。
LoadSceneAsync()を使う場合でも、シーンの読み込みモードを引数で指定できます。
上で触れたメソッドの詳細については、以下のスクリプトリファレンスもご参照ください。
Unityエディタ上で複数のシーンを編集する場合は、Hierarchyウィンドウにシーンファイルをドラッグ&ドロップすることで同時に編集を行うことができます。
ゲーム内オブジェクト用のシーンを表示しつつ、UI用のシーンを表示して画面の見た目を確認する、といったことも可能です。
複数シーンのメリット
複数のシーンを同時に読み込むメリットとしては以下のものが考えられます。
- 複数人開発でコンフリクトを避けられる
- 読み込む範囲を限定できる
複数人開発でコンフリクトを避けられる
複数人開発でコンフリクトを避けられる点はメリットが大きいものです。複数人開発において、それぞれがシーン内のゲームオブジェクトをいじっている状態だと、高い確率でマージする際にコンフリクトが発生します。
yamlファイルを見比べてマージしていくことになるのですが、マージで相手の変更分を消し飛ばしてしまったり、逆に相手がマージする際にこちらの変更分が消し飛んだりと、疲れている時や開発後半のとても追い込まれている時だと、不毛な争いの原因になることもあるのでシーンがひとつの場合は実は潜在的なリスクがあったりします。
シーンを複数に分ける形だと、ファイル自体が分けられるため、担当する機能に応じたシーン分けがされているとコンフリクトが発生する確率が下げられます。
読み込む範囲を限定できる
シーンをメモリ上にロードする際のロード時間もゲームには影響が大きいところで、大きなシーンを単独で使っている場合、シーンの中で使うタイミングが後のものでもロード時に読み込まれるため、分けることによってロード時間を減らせる可能性があります。
使うタイミングが後のものについては非同期で裏でロードを進めておいて、シーンのメイン部分のロードだけ待ち合わせるようにすると、多少ロード時間を減らせます。
例えばオープンワールドのゲームで、今いるエリアに対応するシーンは先に読み込んで、次のエリアが見える範囲に近づいたらロードを開始する、みたいなイメージです。
複数シーンのデメリット
複数のシーンを同時に読み込むデメリットについても考えてみると、以下のものがありそうです。
- シーン間の参照の問題
- メモリリークが発生する可能性がある
- 読み込み機能を自分で実装する必要がある
シーン間の参照の問題
単独シーンではシーン内の参照がしやすいのですが、シーンをまたぐ参照を保持するのはちょっと手間が増えます。同一シーンならInspectorウィンドウから参照をアサインしておいて実行時にはそれを使う、なんて形で実装ができます。しかし、複数のシーンを使っている場合には、別のシーンのゲームオブジェクトやコンポーネントへの参照を事前にアサインしておくことができないので、動的に参照を取得する形にしておく必要があります。
管理系のコンポーネントであれば、シングルトンにしておくのが便利かもしれません。各シーンを管理するクラスを用意しておいて、シングルトンのインスタンスを通して何らかの操作をするのが良さそうです。別のシーンのゲームオブジェクトやコンポーネントを直接操作するのは密結合になりやすいので、シーン間の情報をやり取りするクラスがあると安心です。
メモリリークが発生する可能性がある
シーン間で参照を保持している場合、参照されているオブジェクトがあるシーンをアンロードしても消えてくれずにメモリリークが発生する可能性があります。参照されているオブジェクトはガベージコレクションの際にも削除の対象とならずに生き延びるので、テクスチャなどのメモリ使用量が大きいオブジェクトに対する参照が残っているとメモリリークが発生しやすくなります。
どこから参照されているかを確認するのは大変ですが、上で挙げた宴のページにもあるように、使い終わったらnullを代入して参照を減らしておくのが対処として有効かと思います。
シーンを丸ごとアンロードしてくれるLoadSceneMode.Singleの方だとこの辺は心配しすぎなくてもよかったりします。
そうは言いつつ、実機で確認してみたらそこまで心配するほどメモリを使っていなかった、というケースもあるので、実機確認を行なってから対策をしていくのがスムーズかもしれません。
読み込み機能を自分で実装する必要がある
LoadScene()などを使って自分でロードする仕組みを実装する必要があります。別のシーンのコンポーネントを使いたいケースもあるので、まだ読み込まれていないシーンのコンポーネントを使わないように読み込み順を制御しておきましょう。
また、追加読み込みの場合はLoadScene()で元のシーンがアンロードされないので、必要のなくなったシーンを自分でアンロードしていく必要があります。先述の通り、参照関係には気をつけておきたい部分です。
Prefabを使うケースとの違い
Prefabを使うことで、動的にゲームオブジェクトを生成してシーンのロード時間を減らすこともできます。シーンを使う場合との比較ですが、
- 複数人開発しているか
- ライティングにこだわるか
といった点はどちらを使うかの判断のポイントになりそうです。
複数人開発している場合はシーンを分けることを検討すると良いかと思います。コンフリクトを解消する際のストレスや、コンフリクトを気にした開発など、変なところに意識を向けつつ開発するのは精神衛生上あまり良くないので、あらかじめシーンを分けておいて役割や担当範囲を分けておくと精神的なものも含めて負荷が減ります。
その上で、シーン内にPrefabを配置して、そのPrefab側での編集で済む場合はPrefabを使う形にするとグッド。Prefabを使う方法だと、シーン内の別のゲームオブジェクトやコンポーネントへの参照をアサインする場合はシーンの編集になってしまうので、動的に参照を取得できる仕組みを用意しておくと安心です。
ひとりで開発する場合は、機能を複数並行して作成するときにブランチを分けたりしないのであれば、単一シーンでも良いかと思います。Prefabを使って細かいモジュールに分けておくことで、他のゲームを作る時にも使い回しがしやすくなります。使いまわせるものがあると開発にかかる時間も減らせますからね。
ライティングにこだわる場合は、シーンにベイクすることも多いのでシーンを分けるのが得策です。この場合はエリア単位でシーンを分けて、ゲームの進行状況に応じて追加ロードしていくことになります。ベイクせず、ライトのプローブだけでよければPrefabを使って動的に生成するのも選択肢に入ります。
まとめ
複数人開発を行う場合は、複数のシーンを読み込む形式の方がメリットが大きいと感じています。参照関係やメモリリークの対策、ロードする仕組みなどは必要ですが、シーンの役割を分けることで影響範囲も分かりやすくなるため、コンフリクト発生時のあの緊張感とストレスを減らせると思えば、複数のシーンを読み込む形式が良さそうです。
ひとりで開発していて、シーンのロード時間などに問題がないのであれば、単一のシーンを切り替えていく方法でも良さそうです。
となるとまずは開発に携わる人数で分けていくのが良いかもしれません。この辺りの分け方はゲームに依存する部分もあるので、チーム内でよく話し合ってから進めていくとマージ時の合体事故を減らせそうです。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】gitignoreのファイルで追跡するもの、しないものを設定しておくと安心 2025.09.08
-
次の記事
記事がありません
コメントを書く