Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 8111

【Unity】生成したコードをPrefabに自動でアタッチする方法 - はなちるのマイノート

$
0
0

はじめに

今回は生成したコードをPrefabに自動アタッチする方法を紹介したいと思います。

概要

PrefabへのアタッチにはPrefabUtilityを利用すると簡単に実現できます。
docs.unity3d.com

privatestaticvoid AddComponent(string prefabPath, IReadOnlyList<string> scriptPaths)
{
    if (string.IsNullOrEmpty(prefabPath)) return;
    if (scriptPaths ==null) return;
    if (scriptPaths.Count ==0) return;

    // Prefabを読み込むvar prefab = PrefabUtility.LoadPrefabContents(prefabPath);

    foreach (var scriptPath in scriptPaths)
    {
        // スクリプトをMonoScriptとして読み込むvar scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(scriptPath);

        if (scriptAsset !=null)
        {
            var scriptType = scriptAsset.GetClass();
            if (scriptType !=null)
            {
                // Prefabへアタッチする
                prefab.AddComponent(scriptType);
            }
        }
    }

    // Prefabを保存する
    PrefabUtility.SaveAsPrefabAsset(prefab, prefabPath);
    PrefabUtility.UnloadPrefabContents(prefab);
}

ただ生成したコードをそのままアタッチするのは一筋縄ではいきません。一度コンパイルを挟まないといけないのです。

コンパイル後にアタッチする

コンパイル後に続きの動作をするためには、シリアライズして保存しておかないといけません。そこで便利なのがScriptableSingletonです。
docs.unity3d.com

ScriptableSingletonはコンパイルが走っても値を保持してくれます。

publicclassState : ScriptableSingleton<State>
{
    publicstring[] ScriptPaths { get; set; }
}
// 利用する側
State.instance.ScriptPaths =new []
{
    "Assets/Scripts/Sample.cs",
};

コードからコンパイルを要求するには以下のメソッドを用います。

CompilationPipeline.RequestScriptCompilation();

Unity - Scripting API: Compilation.CompilationPipeline.RequestScriptCompilation


そして[DidReloadScripts]を用いることで、コンパイルした後のタイミングで属性を付与したメソッドを実行することができます。
docs.unity3d.com

publicstaticclassHoge
{
    [DidReloadScripts]
    publicstaticvoid OnDidReloadScripts()
    {
        Debug.Log("Compiled");
    }
}

実験

パーツは全て整いました。今まで紹介したものを全て組み合わせて、実験をしてみます。

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.Compilation;
using UnityEngine;

namespace Sample
{
    publicclassSampleEditor : EditorWindow
    {
        [MenuItem("Sample/Sample Editor")]
        publicstaticvoid ShowWindow()
        {
            GetWindow<SampleEditor>("Sample Editor");
        }

        // コンパイル後に呼び出される
        [DidReloadScripts]
        publicstaticvoid OnDidReloadScripts()
        {
            if (Application.isBatchMode) return;
            if (State.instance.ScriptPaths ==null) return;
            if (State.instance.ScriptPaths.Length ==0) return;
            AddComponent("Assets/Prefabs/Sample.prefab", State.instance.ScriptPaths);
            State.instance.ScriptPaths =null;
        }

        publicvoid OnGUI()
        {
            if (GUILayout.Button("Create And Attach"))
            {
                // アタッチするスクリプトを設定してコンパイルを走らせる// 今回は省くがSample.csは生成したものとする
                State.instance.ScriptPaths =new []
                {
                    "Assets/Scripts/Sample.cs",
                }; 
                AssetDatabase.Refresh();
                CompilationPipeline.RequestScriptCompilation();
            }
        }

        privatestaticvoid AddComponent(string prefabPath, IReadOnlyList<string> scriptPaths)
        {
            if (string.IsNullOrEmpty(prefabPath)) return;
            if (scriptPaths ==null) return;
            if (scriptPaths.Count ==0) return;
            
            // Prefabを読み込むvar prefab = PrefabUtility.LoadPrefabContents(prefabPath);

            foreach (var scriptPath in scriptPaths)
            {
                // スクリプトをMonoScriptとして読み込むvar scriptAsset = AssetDatabase.LoadAssetAtPath<MonoScript>(scriptPath);

                if (scriptAsset !=null)
                {
                    var scriptType = scriptAsset.GetClass();
                    if (scriptType !=null)
                    {
                        // Prefabへアタッチする
                        prefab.AddComponent(scriptType);
                    }
                }
            }

            // Prefabを保存する
            PrefabUtility.SaveAsPrefabAsset(prefab, prefabPath);
            PrefabUtility.UnloadPrefabContents(prefab);
        }
    }
    
    /// <summary>/// コンパイルが走ってもデータを保持する情報です。/// </summary>publicclassState : ScriptableSingleton<State>
    {
        publicstring[] ScriptPaths { get; set; }
    }
}

PrefabPathは適宜替えていただいて、メニューバーのSample/Sample Editorよりボタンを押すと自動でPrefabへコードがアタッチされます。

またAssets/Scripts/Sample.csを自動生成したあとにこの処理を走らせてあげれば、実現したいコードは達成できるでしょう。


Viewing all articles
Browse latest Browse all 8111

Trending Articles