Unityの覚え書き

UnityとC#に関して徒然書いていく感じのブログ

Unityのシーン遷移は遅くない

はじめに

Unityを使ってるとシーン遷移が遅いってよく聞くので調べてみました。
Time.realtimeSinceStartupでシーン遷移前と後の時間を計ってるだけです。

検証

何もないシーンをSceneManager.LoadSceneで読み込んだ場合

カメラ以外のオブジェクトがないシーンを2つ用意します。(Scene0、Scene1と名付けました)
スクリプトはカメラにアタッチします。

f:id:miyukifueda5:20190329054207p:plain
Scene0

// Scene0.cs
// 最初に呼び出されるシーンです
// ここから他のシーンを呼び出します
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene0 : MonoBehaviour
{
    IEnumerator Start()
    {
        // Unityが安定するまで10秒待つ
        yield return new WaitForSeconds(10);

        SceneManager.LoadScene("Scene1");
        
        Timer.startLoadScene = Time.realtimeSinceStartup;
    }
}

f:id:miyukifueda5:20190329054514p:plain
Scene1

// Scene1.cs
// 何も無いシーンです
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene1 : MonoBehaviour
{
    IEnumerator Start()
    {
        Timer.endLoadScene = Time.realtimeSinceStartup;

        float time = Timer.endLoadScene - Timer.startLoadScene;
        Debug.Log($"Scene1の読み込み時間は{time}秒です。 ");
    }
}

[出力結果]
Scene1の読み込み時間は0.07846355秒です。

Cubeが10000個あるシーンをSceneManager.LoadSceneで読み込んだ場合

新たにScene2を作りCubeを複製して10000個作ります。

f:id:miyukifueda5:20190329055815p:plain
Scene2

ソースコードは先程のをちょっと書き換えるだけなので省略します。

[出力結果]
Scene2の読み込み時間は2.428547秒です。

感想

2秒以上かかりかなり遅いです。 何もないシーンとCube10000個あるとシーンだとかかる時間が全然違います。 シーン遷移が重いというより、オブジェクト読み込みに時間がかかっている(広義的にはそれもシーン遷移だけど(笑))
実際のゲームでは3Dモデルとか画像とかのアセットが大量に読み込まれるので、それが原因だと思います。

追加検証

Cubeが10000個あるシーンをSceneManager.LoadSceneAsyncで読み込んだ場合

気になったので、追加で調べてみた。
SceneManager.LoadSceneAsyncで非同期にシーンを読み込んだ後、シーン遷移単体にはどのくらい時間がかかってるのかを測定。 先程のScene0とScene2を流用します。 Scene0.csは非同期処理に合わせて時間の取り方を修正。 Scene2.csは変更なし。

// Scene0.cs
// 最初に呼び出されるシーンです
// ここから他のシーンを呼び出します
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Scene0 : MonoBehaviour
{
    IEnumerator Start()
    {
        // Unityが安定するまで10秒待つ
        yield return new WaitForSeconds(10);

        //SceneManager.LoadScene("Scene2");
        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Scene2");
        
        // シーンのロードが終わるまで待機
        while(!asyncOperation.isDone)
        {
            // ループ毎に時間を取ります
            Timer.startLoadScene = Time.realtimeSinceStartup;
            yield return null;
        }
    }
}

[出力結果]
Scene2の読み込み時間は0.5203323秒です。

感想

最初の検証と同じ時間になると思ったけど、結構差が開いた。 オブジェクトが多いとシーンの読み込みが終わってても遷移でごたつく? それでも2番めの検証の5分の1くらいの時間になってるから効果は大きい。
実際に使う時にはLoadSceneMode.Additiveで追加読み込みにしたりやAwakeでゲームオブジェクト全体を非アクティブにするような工夫が必要だと思う。

終わりに

以前から気になってたけど、ようやく調べられた。
シーン遷移を嫌って1シーンでゲームを完結させるプロジェクトに携わったことがあるけど、シーン分けて作る方法を模索した方がいいと思うんですよね。(途中のシーンから再生できないとか動作の確認大変なので)
次は1シーンだけで作る場合と普通にシーン分ける場合の比較記事各予定です。予定なので守らないかもしれないけど。守りませんでした!

追記

 この記事を投稿してからちょうど一年半経ちました。 この記事は思ったよりもアクセスがあり、多くの人に見られました。 だいたいアクセス数が5,000くらいですが、このブログへのアクセスのほとんどがこの記事です。

 元々の構想では、この記事の続きでUnityのシーンを高速に読み込むプロジェクトの作り方を書く予定でしたが、まだ書けてません。 後々準備ができ次第書こうかと思います。 ブログの方も新しいアカウントに移行しましたので、こちらをチェックして頂けると幸いです。

miyukifueda.hatenablog.com