シーンワークフローを改善(シーンを同時に複数表示)

2023年4月19日

複数のシーンをロード、アンロードすることで、1つのシーン上に同時に複数のシーンオブジェクトを存在させることができます。
チーム開発で複数のメンバーがそれぞれのシーンで開発するなどに使えます

チーム開発のコツ

ScriptableObject を使ってみる

リンク先のビデオチュートリアルも興味深いものになっています

Addressable Asset Systemを使ってみる

今回は、リンク先の情報をアレンジしています。サンプルシーンも確認してみましょう

サンプルシーン

キャプチャ

Managerオブジェクト
SceneLoaderオブジェクト
Addressables Groups

作成手順詳細は、リンク先を確認してください

コード

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;

public class SceneSelector : MonoBehaviour
{
    [SerializeField]
    SceneLoader sceneLoader;

    public AssetReference titleScene;
    public AssetReference gameScene;
    public AssetReference endScene;

    AsyncOperationHandle<SceneInstance> handle = new AsyncOperationHandle<SceneInstance>();

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            sceneLoader.ChangeTo(titleScene);
        }
        else if (Input.GetKeyDown(KeyCode.B))
        {
            sceneLoader.ChangeTo(gameScene);
        }
        else if (Input.GetKeyDown(KeyCode.C))
        {
            sceneLoader.ChangeTo(endScene);
        }
        else if (Input.GetKeyDown(KeyCode.Space))
        {
            Load();
        }
        else if (Input.GetKeyDown(KeyCode.U))
        {
            sceneLoader.Unload(handle);
        }
    }

    private async void Load()
    {
        handle = await sceneLoader.Load(endScene);
    }
}

次のコードはシーンウィンドウに存在するシーンの管理をListで行っているため、少し複雑になっています。
これは、複数のシーンの追加削除をアクティブに行うためです。それに伴っての付随するコードが含まれています

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour
{
    List<AsyncOperationHandle<SceneInstance>> handles = new List<AsyncOperationHandle<SceneInstance>>();

    SynchronizationContext context;

    private void Start()
    {
        context = SynchronizationContext.Current;
    }

    public void ChangeTo(AssetReference sc)
    {
        Task.Run(() =>
        {
            context.Post(async _ =>
            {
                foreach (var handle in handles)
                {
                    await Addressables.UnloadSceneAsync(handle).Task;
                }

                handles.Clear();

                await Load(sc);

            }, null);
        });
    }

    public void Unload(AsyncOperationHandle<SceneInstance> handle)
    {
        if (!handles.Contains(handle)) return;

        Addressables.UnloadSceneAsync(handle).Completed += p =>
        {
            if (p.Status == AsyncOperationStatus.Succeeded)
            {
                handles.Remove(handle);
            }
        };
    }

    public async Task<AsyncOperationHandle<SceneInstance>> Load(AssetReference sc)
    {
        var handle = new AsyncOperationHandle<SceneInstance>();

        await Task.Run(() =>
           {
               context.Post(async _ =>
               {
                   handle = Addressables.LoadSceneAsync(sc, LoadSceneMode.Additive);

                   await handle.Task;

                   handle.Completed += p =>
                    {
                        if (p.Status == AsyncOperationStatus.Succeeded)
                        {
                            handles.Add(handle);
                        }
                    };

               }, null);
           });

        return handle;
    }
}

Unity

Posted by hidepon