You are currently viewing [Unity]シーン保存したとき自動でBuildSettings(SceneInBuild)に登録する方法
609アイキャッチ画像

[Unity]シーン保存したとき自動でBuildSettings(SceneInBuild)に登録する方法

はじめに

まずこの記事はJenkinsなどは使わずUnityだけを使用してビルドする場合を考えています。

Unityでシーンを追加していざビルドしよう!となったときにシーンを設定し忘れて出てほしいシーンが出ないときありますよね?
僕は何回かありました。今回はこの設定の部分を自動化しようと思います。

やってみた結果(読んでわかること)

AssetPostprocessorクラスを使用してアセットがインポートされたときにそれがシーンならばSceneInBuildを更新するような処理を作成しました。

開発環境

  • Windows10
  • CPU:i5-14600KF
  • GPU:RTX4060ti
  • メモリ:32GB
  • Unity – 2022.3.54f1
  • Visual Studio 2022

使用アセット

なし

やったこと

冒頭でも記載した通りUnityEditorのAssetPostprocessorを使用します。
以下にコードを記載します。
これを適当なEditorフォルダ下に配置することで動作するようになります。
一部環境に合わせて変更する箇所がありますのでそのあたりはご自分の環境に合わせて変更をお願いします。

AssetPostprocessorについて

AssetPostprocessor:Unityリファレンス
https://docs.unity3d.com/ja/2020.2/ScriptReference/AssetPostprocessor.html

このクラスを継承することでインポート(シーンの追加)を検知してスクリプトを実行することができます。
今回はこの機能を使用してシーンファイルが追加されたらスクリプトを実行してPlayerSettingsを更新しようと思います。

実装

先にコード全体を貼っておきます。
下にポイントになりそうな個所をかいつまんで解説していこうと思います。

public class BuildSettingScenesUpdater : AssetPostprocessor
{
    // 環境に合わせて変更
    private const string c_pSceneDir = "_App\\Scenes";

    public static void OnPostprocessAllAssets(
        string[] pImportedAssets,
        string[] pDeletedAssets,
        string[] pMovedAssets,
        string[] pMovedFromAssetPaths)
    {
        if (!_CheckExists())
            return;

        // 更新のあったアセット
        var assets = pImportedAssets
            .Union(pDeletedAssets)
            .Union(pMovedAssets)
            .Union(pMovedFromAssetPaths);
        
            if (_CheckInSceneDir(assets))
        {
            // アセットの追加(シーンの追加)があったので更新
            _CreateSaveScenesList();
        }
    }

    /// <summary>
    /// "c_pSceneDir"で設定したフォルダが存在するかどうかの確認
    /// </summary>
    private static bool _CheckExists()
    {
        string pSceneDirFullPath = _GetFullPath(c_pSceneDir);

        if (!Directory.Exists(pSceneDirFullPath))
        {
            Debug.LogError("Not Found Dir :" + pSceneDirFullPath);
            return false;
        }

        return true;
    }

    /// <summary>
    /// Sceneディレクトリ以下のアセットが編集されたか
    /// </summary>
    private static bool _CheckInSceneDir(IEnumerable<string> pAssets)
    {
        return pAssets.Any(pAsset => Path.GetDirectoryName(pAsset) == _GetAssetsPath(c_pSceneDir));
    }

    /// <summary>
    /// 更新後のシーンリストを
    /// </summary>
    private static void _CreateSaveScenesList()
    {
        // Assets/設定したパス(c_pSceneDir)
        string pSceneDirAssetsPath = _GetAssetsPath(c_pSceneDir);

        // 指定フォルダ内のシーンファイルだけを対象に
        var pScenes = AssetDatabase.FindAssets("t:Scene", new string[] { pSceneDirAssetsPath })
            .Select(pGuid => AssetDatabase.GUIDToAssetPath(pGuid))
            .OrderBy(pPath => pPath)
            .Select(pPath => new EditorBuildSettingsScene(pPath, true))
            .ToList();

        EditorBuildSettings.scenes = pScenes.ToArray();
        AssetDatabase.SaveAssets();
    }

    /// <summary>
    /// UnityApplicationのdataPathを引数の"path"に連結
    /// </summary>
    /// <param name="pPath"></param>
    /// <returns></returns>
    private static string _GetFullPath(string pPath)
    {
        return Application.dataPath + "\\" + pPath;
    }

    /// <summary>
    /// パスに"Assets/"を追加
    /// </summary>
    /// <param name="pPath"></param>
    /// <returns></returns>
    private static string _GetAssetsPath(string pPath)
    {
        return "Assets\\" + pPath;
    }
}

細かいポイント解説

●OnPostprocessAllAssetsnについて

AssetPostprocessorクラスのメソッドになります。
アセットがインポート(更新)されたら呼び出されます。

●_CreateSaveScenesList()の中の処理について

var scenes = AssetDatabase.FindAssets("t:Scene", new string[] { sceneDirAssetsPath })
                .Select(guid => AssetDatabase.GUIDToAssetPath(guid))
                .OrderBy(path => path)
                .Select(path => new EditorBuildSettingsScene(path, true))
                .ToList();

AssetDatabaseクラスを使用して指定したフォルダ内のシーンファイルを取得します。
ちなみにここの”t:Scene”というコマンドProjectWindow、HierarchyWindowの検索ボックスでも同じように使用できます。おそらく同じような処理を行っているんだと思います。

AssetDatabase.FindAssets("t:Scene", new string[] { sceneDirAssetsPath })

AssetDatabase.GUIDToAssetPath:Unityリファレンス
https://docs.unity3d.com/ja/2019.3/ScriptReference/AssetDatabase.GUIDToAssetPath.html

フィルター検索の文字列を使ってアセットデータベースを検索します。返り値はアセットがそのまま帰ってきます。

Select(guid => AssetDatabase.GUIDToAssetPath(guid))

アセット名でソートします。
ここの条件を変更したら自分の好きなソート順で設定できます。

OrderBy(path => path)

Scene In Buildに設定できる形に変換します。
EditorBuildSettingsScene(シーンのパス, シーン有効かどうか)
以上のような引数の設定になってます。

Select(path => new EditorBuildSettingsScene(path, true))

EditorBuildSettings.scenesで設定したシーンのリストを
AssetDatabase.SaveAssets();で保存します。

EditorBuildSettings.scenes = scenes.ToArray();
AssetDatabase.SaveAssets();

さいごに

これで指定したフォルダにシーンファイルが追加されたときに自動でScenes In Buildが更新されるようになりました。
もう設定のし忘れでビルドをやり直すこともありません。

ちなみに自分はこのコードと合わせてシーン一覧をenumにしてどこからでもindexからシーンを参照できるような仕組みを作って一緒のタイミングで更新しています。

引用

AssetPostprocessor
https://docs.unity3d.com/ja/2022.3/ScriptReference/AssetPostprocessor.html

[Unity] BuildSettingのScene定義をよしなにしたい

https://qiita.com/lycoris102/items/bc40213b48d22c8c064f

コメントを残す