蒼水技術録

蒼水家技術録

蒼水が普段制作とか勉強とかして覚えたことを復習としてまとめてるものです。 それが最適解かどうかはわからないけど、何を目的として始めて、何が必要で、実際何をやって、どうなったか、まで全部過程を残すための技術ブログです。

Unityエディタ拡張編 #1 -フォルダを半自動的に生成する-

個人的な開発において、リソースの管理にIDを付けて管理しているのですが、そのデータの管理に決まった規則でフォルダを命名・作成を行うことでデータを整理しています。
それにあたり毎度同じ作業をすることになるが面倒なのでそれを半自動化するエディタ拡張の作成を試みたものです。

f:id:Yui_Aomi:20191214123024g:plain
実際に動かしたGIF

そもそもエディタ拡張とは?

今回はエディタ拡張編初回ということでこの点に関しても書いておきます。

エディタ拡張とはUnityのデフォルトの機能にはないものを自分でC#を記述して機能を追加したりして便利にできる機能です。
これはEditorフォルダを作成し、その中に拡張のために記述したC#を格納します。こんな感じでOKです。

f:id:Yui_Aomi:20191214124601p:plain

今回使用するGUILayout/EditorGUILayoutに関して

とりあえず公式リファレンスはこちら
docs.unity3d.com
docs.unity3d.com

これらのクラスはエディター拡張するにあたってボタンやら整列やらのレイアウトをするためのクラスになります。
これを使ってボタンを作ったりボタンをクリックしたかどうかをとったりして機能を実装していきます。

自分で追加していく機能部分の記述は基本的にOnGUI()という関数内に記述していきます。

エディタ拡張を行うにあたってEditorWindowクラスを継承する必要もあります。(専用のウィンドウを開くため)

フォルダ構成に関して

f:id:Yui_Aomi:20191214123904p:plain
フォルダ構成
フォルダはこのような構成に普段しています。
Assetsはもともとある親フォルダ。
その中に英字2文字の種別ID+ナンバリングで命名したフォルダにすぐ使える状態にしたPrefabを格納します。
さらにその中にResourceフォルダを作成しこの中にはもとになるモデル(FBX)やテクスチャ(PNG)、他マテリアルなどがまとめて格納されます。

こういった構成をナンバリングごとにやるのはめんどくさいなぁ....ということで今回の作成を行いました。

どういう機能を実装したいのか考える

個人的に思っていた不満として毎度同じ作業をするのがめんどくさいということです。
右クリックして、フォルダ作って、命名して......めんどくさい。

ではこれをどうしたいかといえば、ワンクリックで任意の名前のフォルダを中のフォルダもまとめて一発生成してしまいたいになります。

実装していくにあたってもう少し分解していくと

  • 名前を指定できる機能。パスによってフォルダを生成するため。またテンプレの挿入機能を付けてできるだけ操作を減らす方針で。
  • ボタンをポチるとフォルダが生成される機能。

この二つが大きな部分かなと思います。

自動生成のサンプルコード

これは自分用に作ったモノなのでもし使いたい方がいらっしゃいましたら改造して使用して問題ありません。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class ResourceFolderGenerator : EditorWindow {

    string path;

    [MenuItem("Tools/ResourceFolderGenerator")]

    static void Init() {
        GetWindow<ResourceFolderGenerator>();
    }

    private void OnGUI() {

        //追加するフォルダパスの指定
        GUILayout.Label("Type Folder Path.");
        path = EditorGUILayout.TextField(path);

        EditorGUILayout.BeginHorizontal();

        //親階層のパス挿入用(背景)
        if (GUILayout.Button("Bg"))
        {
            {
                path = "Bg/Bg_00000/Resource";
            }
        }


        //親階層のパス挿入用(武器)
        if (GUILayout.Button("Wp"))
        {
            {
                path = "Wp/Wp_00000/Resource";
            }
        }

        //親階層のパス挿入用(エフェクト)
        if (GUILayout.Button("Ef"))
        {
            {
                path = "Ef/Ef_00000/Resource";
            }
        }

        EditorGUILayout.EndHorizontal();


        //追加決定ボタン
        if (GUILayout.Button("Generate")) {
            FolderPath(path);
        }
    }

    static void FolderPath(string folderPath) {
        string path = "Assets/" + folderPath;

        if (!Directory.Exists(path)) {
            Directory.CreateDirectory(path);
        }

        AssetDatabase.ImportAsset(path);
    }
}

要所の解説

GetWindow<>()

GetWindow<>()は継承したEditorWindowクラスからウィンドウを表示するための部分です。
GetWindow<自分のクラス名>()でウィンドウを呼び出すことができます。

ちなみに継承は(自分のクラス名):(継承クラス名)で継承できます。

Label()

Labelは単純に文字列を表示するためのもので””で囲まれた部分に入れたものが文字列として表示されます。

f:id:Yui_Aomi:20191214131552p:plain
Labelによる文字列の追加

TextField()

TextField()では文字列を入力できるようにするフィールドを作成してくれます。
これにより任意の文字列を渡すことができるようになります。

f:id:Yui_Aomi:20191214132634p:plain
文字列の入力部分

Button()

Buttonはボタン一個一個の処理を行っています。""で囲んだ部分はボタン内に文字が表示できます。
Buttonは返り値がBoolで帰ってきますので、押されているときpathにテンプレートを代入するものです。
これによりわざわざ全部打ち込まなくてもある程度の部分を入れてくれるので楽になりました。
あとは自分でナンバリングを変えればOKです。

Begin/EndHorizontal()

Begin~EndHrizontal()ではこの間にはらんだ部分を水平に整列します。
ボタンを今回データ種類としての3種類+生成用1種の計4つありますが、うち前者を横に3つ並べるための部分です。

f:id:Yui_Aomi:20191214132021p:plain
整列したボタン

FolderPath()関数

これはフォルダを生成するためのメイン部分になります。
テキストフィールドに入力した文字列をAssets直下に作成させるためAssetsと入力したパスをくっつけます。
そして同じパスが存在しない場合にそのパスに従ってフォルダを生成させます。

まとめ

エディタ拡張は技量さえあればガンガン便利に拡張できるのでガンガン拡張していきたい所存。
めんどくさいことはやりたくないぞい....。

動作環境:Unity2019.1.2f