[Unity] SceneManagerでロードシーンを入れ変える

SceneManagerのLoadSceneを使用して2つのシーンを遷移する方法のメモ。

Unityでシーンを遷移する場合は、SceneManagerのLoadSceneを使用します。
が2つのシーンを遷移させるときにそのまま
SceneManager.LoadScene(A);
SceneManager.UnloadScene(B);

のようにすると

間にこんな感じで1フレームすきまができてしまいます。
また、普通にLoadSceneすると大きなファイルの場合ロードに時間がかかってしまうため
間の余白なく次に移動するのがうまくいかなくなってしまいます。

これの対応のため、LoadSceneではなくLoadSceneASyncという非同期のロードコマンドを使用します。
以下コード

スペースを押すとシーンを事前ロードし、離すとモデルを入れ替えます。

注目点は2カ所。
ScenePreLoadの allowSceneActivation と、SceneLoadの yield return null;

 

allowSceneActivationは、いわゆるシーンの裏読みみたいなもので、事前にファイルをギリギリまでロードしておいて表示はしないでおくよ というフラグになります。
これがfalseの場合、上のようにロードはされていても灰色の is loading 状態になり
ロードはされません。

続いてSceneLoad。
IEnumerator というのは「コルーチン」と呼ばれる機能で 処理の途中で一旦中断したりあとからその行から再開できたりする 性質を持っています。
Update内で1フレーム1処理で動いてるのとは別に、処理を続けたり途中で止めたりすることができます。

LoadSceneの動作は、そのフレームでは実行されず次のフレームで実際にロードされます。
対してUnloadSceneはそのフレームでシーンがアンロードされます。
そのためLoadSceneとUnloadSceneを同じUpdateなり関数なりに書いてしまうと
最初のように1フレーム抜けた状態が発生してしまうわけですね。

コルーチンの処理内の yield return null は、そこで一度中断して、1フレーム後に次の処理を再開
してくれという意味になります。
なので、コルーチンの中断前で AsyncのロードフラグをOn(次フレームでロードされる)にした上で
yeildで1フレーム中断を挟んでからアンロードすれば

こんな感じで間のフレームもなく切り替えをすることができます。
どの段階でPreLoadしておくかはシーンサイズやら処理内容によって考えなければいけませんが
これでシームレスに黒フェードとかをはさまなくても次のフレームに移れそうです。やったぜ。

コルーチンを使ったシーンロードは、
シーンをロードした後にその中の特定のオブジェクトを取得したい場合にも使用します。
SceneLoadした段階ではシーンは実際にはロードされていないのでGetRootGameObjectsしようとしても
シーンはIsValid = false の状態になってしまい、正しく取得することができません。

なので

こんなかんじで、コルーチンで1フレーム中断をはさんでから
シーンのオブジェクトを取得するようにすれば正しく実行することができます。
これに気が付かずしばらくハマりました(汁

どのタイミングで何をしているのかきちんと把握していないと、変なところで躓きますね。
まだまだ勉強あるのみ!

参考

コメントを残す

メールアドレスが公開されることはありません。

*