ムービーデータの納品方法を簡単にする

# はじめに

本記事は、[サムザップ Advent Calendar 2019 #2](https://qiita.com/advent-calendar/2019/sumzap2) の12/10の記事です。

株式会社サムザップの黒澤です。Unityエンジニアをしています

# きっかけ

Unity上で再生するムービーを作る際に外部会社に依頼することなどが多いと思いますが

その際に、以下に納品方法を簡単かつミスが少なくなる方法はないかと考えていました

その時にやった手法を説明したいと思います

今回ムービーを再生する手段として、CRIWAREのManaを利用させて頂いています

# 手法

* 外部会社さんとのやり取りは、基本git上でやり取りする
* 納品は全てアセットバンドルとする
* 再生を管理する設定は、Scriptable Objectを自動生成する
* フォルダにムービーデータを配置するだけで納品できるようにする

上記のことを踏まえて、実際に下記のように実装しました

# コード例

* データ側(ScriptableObject)

```c#:MovieBundleBuildData.cs
namespace Sumzap.Movie
{
    /// <summary>
    /// Movieバンドルデータ
    /// </summary>
    public class MovieBundleBuildData : ScriptableObject
    {
        /// <summary> TotalByte </summary>
        [SerializeField]
        private long totalbyte;

        /// <summary> SoundBundleData </summary>
        [SerializeField]
        private List<MovieBundleData> movieBundleDatas;

        /// <summary>
        /// トータルのバイト数
        /// </summary>
        public long Totalbyte { get { return totalbyte; } set { totalbyte = value; } }

        //---------------------------------------------------------------------------------//
        /// <summary>
        /// MovieBundleDatas
        /// </summary>
        /// <value>Movile Bundle file.</value>
        //---------------------------------------------------------------------------------//
        public List<MovieBundleData> MovieBundleDatas { get { return movieBundleDatas; } set { movieBundleDatas = value; } }
    }

    //---------------------------------------------------------------------------------//
    /// <summary>
    /// Movie bundle data.
    /// </summary>
    //---------------------------------------------------------------------------------//
    [Serializable]
    public class MovieBundleData
    {
        /// <summary>
        /// インデックス
        /// </summary>
        [SerializeField]
        private int index;

        /// <summary> usmファイル名. </summary>
        [SerializeField]
        private string usmFileName;

        /// <summary>
        /// インデックス
        /// </summary>
        public int Index { get { return index; } set { index = value; } }

        //---------------------------------------------------------------------------------//
        /// <summary>
        /// Usmファイル名
        /// </summary>
        /// <value>The UsmFileName.</value>
        //---------------------------------------------------------------------------------//
        public string UsmFileName { get { return usmFileName; } set { usmFileName = value; } }
    }
}
```

* エディタ側

```cs:CreateMovieBundleBuildData.cs
namespace Sumzap
{
    /// <summary>
    /// ムービーで使用するバンドルデータを作成するクラス
    /// </summary>
    public class CreateMovieBundleBuildData
    {
        //---------------------------------------------------------------------------------//
        /// <summary>
        /// メニューからBuildData作成
        /// </summary>
        //---------------------------------------------------------------------------------//
        [MenuItem("Assets/Sumzap/Movie/Create BuildData")]
        public static void CreateBuildData()
        {
            string selectPath = string.Empty;
            foreach(Object selectedObj in Selection.objects)
            {
                selectPath = AssetDatabase.GetAssetPath(selectedObj);
                break;
            }
            
            // ファイルが選択されていたらフォルダに変換
            if(File.Exists(selectPath))
            {
                selectPath = Path.GetDirectoryName(selectPath);
            }

            //----------------------------------------------------------------
            // ScriptableObject作成
            //----------------------------------------------------------------
            string basePath = selectPath;
            string buildDataPath = basePath + "/" + "MovieBundleBuildData.asset";
            string label = "MovieBundleBuildData";
            MovieBundleBuildData buildData;
            if(!File.Exists(buildDataPath))
            {
                buildData = ScriptableObjectToAsset.Create<MovieBundleBuildData>(buildDataPath, label);
            }
            else
            {
                buildData = AssetDatabase.LoadAssetAtPath<MovieBundleBuildData>(buildDataPath);
            }
            // 初期化
            buildData.Totalbyte = 0;
            // usmFiles
            List<string> usmFiles = FindFiles(selectPath, @"*.usm.bytes", SearchOption.AllDirectories, true);
            if(usmFiles.Count > 0)
            {
                List<MovieBundleData> usmDataList = new List<MovieBundleData>();
                usmFiles.ForEach(
                    (file, index) =>
                    {
                        MovieBundleData data = new MovieBundleData();
                        data.Index = index;
                        data.UsmFileName = Path.GetFileName(file);
                        FileInfo fileInfo = new FileInfo(Path.GetFullPath(file));
                        buildData.Totalbyte += fileInfo.Length;
                        usmDataList.Add(data);
                    });
                buildData.MovieBundleDatas = usmDataList;
            }
            else
            {
                buildData.MovieBundleDatas = new List<MovieBundleData>();
            }

            AssetDatabase.Refresh();
        }

        //---------------------------------------------------------------------------------//
        /// <summary>
        /// ファイル検索
        /// </summary>
        /// <returns>The files.</returns>
        /// <param name="path">ベースパス.</param>
        /// <param name="searchPattern">検索パターン.</param>
        /// <param name="searchOption">検索オプション.</param>
        /// <param name="includeDirectoryName">ディレクトリ名を含めるか.</param>
        //---------------------------------------------------------------------------------//
        public static List<string> FindFiles(string path, string searchPattern, SearchOption searchOption, bool includeDirectoryName = true)
        {
            List<string> files = new List<string>();
            string[] fileArray;

            fileArray = Directory.GetFileSystemEntries(path, searchPattern);
            if(fileArray != null)
            {
                foreach(string fileName in fileArray)
                {
                    files.Add(fileName);
                }
            }

            if(searchOption == SearchOption.AllDirectories)
            {
                string[] subFolders = System.IO.Directory.GetDirectories(path, "*", System.IO.SearchOption.AllDirectories);

                if(subFolders != null)
                {
                    foreach(string folderName in subFolders)
                    {
                        fileArray = Directory.GetFileSystemEntries(folderName, searchPattern);
                        if(fileArray != null)
                        {
                            if(includeDirectoryName)
                            {
                                foreach(string fileName in fileArray)
                                {
                                    files.Add(fileName);
                                }
                            }
                            else
                            {
                                foreach(string fileName in fileArray)
                                {
                                    files.Add(Path.GetFileName(fileName));
                                }
                            }
                        }
                    }
                }
            }
            return files;
        }
    }
}
```

# 使い方

フォルダにムービーを登録してもらったら、フォルダを選択して、メニューのCreate BuildDataを実行するだけです。
出来上がった、Scriptable Objectはこんな感じ

![スクリーンショット 2019-12-04 10.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540472/63d399b5-cce1-6b55-5f98-8c945405ce21.png)

# 最後に

この手のコードは、普段から書いていると簡単なのですが意外に忘れがちになってしまいます。

なので、備忘録として記事にしました。

明日は @ohbashunsuke さんの記事です。