Maemaemae

Unityエディタ拡張:タグとレイヤーを一括登録する方法

Unityでゲーム開発を進めると、多数のタグやレイヤーを設定する必要があることはよくあります。特に中規模以上のプロジェクトでは、タグ・レイヤーの管理が煩雑になりがちです。この記事では、エディタ拡張を活用してタグとレイヤーを一括で登録する方法を紹介します。

この記事を読むと、以下のことができるようになります:

エディタ拡張とは

Unity エディタ拡張(Editor Extensions)は、Unity の開発環境自体をカスタマイズし、プロジェクト固有の機能を追加するための仕組みです。エディタ拡張を使うことで、次のメリットが得られます:

エディタ拡張スクリプトは通常、Editor という特別なフォルダ内に配置され、これらのスクリプトはビルドされたゲームには含まれません。つまり、開発効率を向上させるための機能を、最終製品のサイズやパフォーマンスに影響を与えることなく実装できます。

タグとレイヤーの一括登録スクリプト

以下は、タグとレイヤーを一括で登録するためのエディタ拡張スクリプトです。このスクリプトをプロジェクトに追加すると、Unity メニューから簡単にタグとレイヤーを設定できるようになります。

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

public class TagLayerSetupWizard : EditorWindow
{
    [MenuItem("Tools/Setup Tags and Layers")]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow(typeof(TagLayerSetupWizard));
    }

    void OnGUI()
    {
        GUILayout.Label("タグとレイヤーの一括セットアップ", EditorStyles.boldLabel);

        if (GUILayout.Button("タグとレイヤーを設定"))
        {
            SetupTagsAndLayers();
        }
    }

    void SetupTagsAndLayers()
    {
        // カスタムタグのリスト
        string[] customTags = new string[]
        {
            "Ball", "Flipper", "Plunger", "Wall", "Target",
            "FireTarget", "IceTarget", "LightningTarget", "EarthTarget", "WindTarget",
            "Bumper", "Ramp", "Gate", "Dragon", "Collectible",
            "Trigger", "DeadZone", "MultiballSpawner", "SpecialZone", "BonusArea"
        };

        // カスタムレイヤーのリスト
        string[] customLayers = new string[]
        {
            "Ball", "PinballElements", "Flippers", "Plunger", "Walls",
            "Targets", "DragonElements", "Triggers", "SpecialEffects", "Background",
            "InteractiveElements", "NonColliding", "PlayerOnly", "CameraIgnore", "PostProcess",
            "MiniGame", "DragonVisuals", "ElementalEffects", "Physics2D", "Physics3D",
            "DynamicObjects", "StaticObjects", "Debugging", "SensorOnly", "NonInteractive",
            "CinematicElements", "HiddenInGame"
        };

        // タグの追加
        SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
        SerializedProperty tagsProp = tagManager.FindProperty("tags");

        foreach (string tag in customTags)
        {
            bool found = false;
            for (int i = 0; i < tagsProp.arraySize; i++)
            {
                SerializedProperty t = tagsProp.GetArrayElementAtIndex(i);
                if (t.stringValue.Equals(tag)) { found = true; break; }
            }

            if (!found)
            {
                tagsProp.arraySize++;
                SerializedProperty newTag = tagsProp.GetArrayElementAtIndex(tagsProp.arraySize - 1);
                newTag.stringValue = tag;
            }
        }

        // レイヤーの追加
        SerializedProperty layersProp = tagManager.FindProperty("layers");

        for (int i = 0; i < customLayers.Length; i++)
        {
            // レイヤー8-31のみカスタム可能
            int layerIndex = 8 + i;
            if (layerIndex >= 32) break; // Unity は最大32レイヤーまで

            SerializedProperty layerProp = layersProp.GetArrayElementAtIndex(layerIndex);
            if (string.IsNullOrEmpty(layerProp.stringValue))
            {
                layerProp.stringValue = customLayers[i];
            }
        }

        tagManager.ApplyModifiedProperties();
        Debug.Log("タグとレイヤーを設定しました");
    }
}

スクリプトの使い方

実際にこのツールを使うための手順を見ていきましょう。

インストール手順

  1. Editorフォルダの作成: プロジェクト内に Editor フォルダを作成します。このフォルダはAssets直下でも、任意のサブフォルダ内でも構いません。

    Assets/Editor/
    

    または

    Assets/_Project/Scripts/Editor/
    
  2. スクリプトの作成: 上記のスクリプトを TagLayerSetupWizard.cs という名前で Editor フォルダ内に保存します。

  3. スクリプトの実行: Unity上部のメニューバーに新しく Tools メニューが追加され、その中に Setup Tags and Layers という項目が表示されます。このメニューをクリックすると、ウィンドウが開きます。

  4. タグとレイヤーの設定: ウィンドウ内の「タグとレイヤーを設定」ボタンをクリックすると、コード内で定義したタグとレイヤーが自動的に追加されます。

よくある問題と解決策

スクリプトの解説

このスクリプトがどのように動作するのか、主要な部分を解説します:

メニュー項目の作成

[MenuItem("Tools/Setup Tags and Layers")]
public static void ShowWindow()
{
    EditorWindow.GetWindow(typeof(TagLayerSetupWizard));
}

MenuItem 属性を使用して、Unityメニューバーに新しい項目を追加しています。ここでは Tools メニュー内に Setup Tags and Layers という項目を作成しています。

ウィンドウの描画

void OnGUI()
{
    GUILayout.Label("タグとレイヤーの一括セットアップ", EditorStyles.boldLabel);

    if (GUILayout.Button("タグとレイヤーを設定"))
    {
        SetupTagsAndLayers();
    }
}

OnGUI メソッドはエディタウィンドウの描画を担当します。ここではシンプルなラベルとボタンを配置しています。

TagManager.assetの操作

SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);

Unity のタグとレイヤーは ProjectSettings/TagManager.asset ファイルに保存されています。このファイルを SerializedObject として読み込み、プログラムから操作できるようにしています。

タグの追加

SerializedProperty tagsProp = tagManager.FindProperty("tags");
// 中略
tagsProp.arraySize++;
SerializedProperty newTag = tagsProp.GetArrayElementAtIndex(tagsProp.arraySize - 1);
newTag.stringValue = tag;

タグマネージャーの "tags" プロパティにアクセスし、配列のサイズを増やして新しいタグを追加しています。ただし、既存のタグと重複しないように事前にチェックを行います。

レイヤーの追加

SerializedProperty layersProp = tagManager.FindProperty("layers");
// 中略
SerializedProperty layerProp = layersProp.GetArrayElementAtIndex(layerIndex);
if (string.IsNullOrEmpty(layerProp.stringValue))
{
    layerProp.stringValue = customLayers[i];
}

レイヤーも同様にアクセスしますが、Unityでは8〜31の範囲のみカスタムレイヤーとして設定可能です。また、既に設定されているレイヤーは上書きしないように条件分岐を設けています。

変更の適用

tagManager.ApplyModifiedProperties();

最後に、変更内容を確定して保存します。

物理衝突マトリックスの設定

タグとレイヤーを設定した後、多くの場合はレイヤー間の物理衝突マトリックスも設定する必要があります。これも同様にエディタ拡張で自動化可能です。

以下は、物理衝突マトリックスを設定するメソッドの例です:

void SetupPhysicsLayerCollisions()
{
    // Ball レイヤーは特定のレイヤーとのみ衝突
    int ballLayer = LayerMask.NameToLayer("Ball");
    int pinballElementsLayer = LayerMask.NameToLayer("PinballElements");
    int flippersLayer = LayerMask.NameToLayer("Flippers");
    int wallsLayer = LayerMask.NameToLayer("Walls");

    // 全てのレイヤー間の衝突をオフにする(デフォルトは衝突する)
    for (int i = 0; i < 32; i++)
    {
        for (int j = 0; j < 32; j++)
        {
            // 必要に応じてレイヤー間の衝突を制御
            // Physics.IgnoreLayerCollision(i, j, true); // 衝突を無視
        }
    }

    // 特定のレイヤー間の衝突を有効にする
    Physics.IgnoreLayerCollision(ballLayer, pinballElementsLayer, false); // 衝突を有効
    Physics.IgnoreLayerCollision(ballLayer, flippersLayer, false);
    Physics.IgnoreLayerCollision(ballLayer, wallsLayer, false);

    Debug.Log("物理衝突マトリックスを設定しました");
}

このメソッドを SetupTagsAndLayers メソッドの最後に呼び出すことで、タグとレイヤーの設定と同時に物理衝突マトリックスも設定できます。

衝突設定のベストプラクティス

物理衝突マトリックスを設定する際のポイント:

  1. デフォルト設定を検討: すべてのレイヤーが互いに衝突するのがデフォルトですが、パフォーマンスを考慮して必要な衝突のみを有効にする「ホワイトリスト方式」も検討しましょう。

  2. 論理的なグループ化: 関連するオブジェクトは同じレイヤーに配置し、グループ単位で衝突制御を考えましょう。

  3. 頻繁に変更するレイヤーには注意: 実行時に頻繁に変更するレイヤーの衝突設定は慎重に行いましょう。

応用例と発展

このエディタ拡張は、さらに以下のように発展させることができます:

1. GUI による設定画面の強化

タグやレイヤーをコード内のハードコーディングではなく、エディタウィンドウのGUIから動的に追加・削除できるようにします:

private List<string> customTags = new List<string>();
private string newTagName = "";

void OnGUI()
{
    GUILayout.Label("タグ設定", EditorStyles.boldLabel);

    // 新規タグの入力欄
    newTagName = EditorGUILayout.TextField("新規タグ名:", newTagName);
    if (GUILayout.Button("タグを追加") && !string.IsNullOrEmpty(newTagName))
    {
        customTags.Add(newTagName);
        newTagName = "";
    }

    // タグリストの表示
    EditorGUILayout.LabelField("登録予定のタグ:");
    for (int i = 0; i < customTags.Count; i++)
    {
        EditorGUILayout.BeginHorizontal();
        customTags[i] = EditorGUILayout.TextField(customTags[i]);
        if (GUILayout.Button("削除", GUILayout.Width(60)))
        {
            customTags.RemoveAt(i);
            break;
        }
        EditorGUILayout.EndHorizontal();
    }

    // 実行ボタン
    if (GUILayout.Button("タグを登録"))
    {
        SetupTagsAndLayers();
    }
}

2. プリセットの管理

プロジェクトごとに異なるタグ・レイヤー設定をプリセットとして保存し、必要に応じて読み込めるようにします:

[System.Serializable]
public class TagLayerPreset
{
    public string presetName;
    public List<string> tags = new List<string>();
    public List<string> layers = new List<string>();
}

private List<TagLayerPreset> presets = new List<TagLayerPreset>();
private int selectedPresetIndex = 0;

// プリセットの保存と読み込み機能
void SavePreset(string presetName)
{
    TagLayerPreset preset = new TagLayerPreset();
    preset.presetName = presetName;
    preset.tags = new List<string>(customTags);
    preset.layers = new List<string>(customLayers);

    presets.Add(preset);

    // プリセットをJSON形式で保存
    string json = JsonUtility.ToJson(new PresetContainer { presets = presets });
    EditorPrefs.SetString("TagLayerPresets", json);
}

void LoadPresets()
{
    string json = EditorPrefs.GetString("TagLayerPresets", "");
    if (!string.IsNullOrEmpty(json))
    {
        PresetContainer container = JsonUtility.FromJson<PresetContainer>(json);
        presets = container.presets;
    }
}

[System.Serializable]
private class PresetContainer
{
    public List<TagLayerPreset> presets = new List<TagLayerPreset>();
}

3. プロジェクト間での共有

複数のプロジェクト間でタグとレイヤーの設定を共有できるようにします:

// プリセットのエクスポート
void ExportPreset(TagLayerPreset preset)
{
    string path = EditorUtility.SaveFilePanel(
        "プリセットをエクスポート",
        "",
        preset.presetName + ".json",
        "json");

    if (!string.IsNullOrEmpty(path))
    {
        string json = JsonUtility.ToJson(preset);
        System.IO.File.WriteAllText(path, json);
        Debug.Log("プリセットをエクスポートしました: " + path);
    }
}

// プリセットのインポート
void ImportPreset()
{
    string path = EditorUtility.OpenFilePanel(
        "プリセットをインポート",
        "",
        "json");

    if (!string.IsNullOrEmpty(path))
    {
        string json = System.IO.File.ReadAllText(path);
        TagLayerPreset preset = JsonUtility.FromJson<TagLayerPreset>(json);
        presets.Add(preset);
        Debug.Log("プリセットをインポートしました: " + preset.presetName);
    }
}

実装チェックリスト

タグとレイヤーの一括登録ツールを実装する際のチェックリスト:

  1. Editor フォルダが正しく作成されている
  2. ✅ スクリプトが正しく保存されている
  3. ✅ プロジェクトに合わせたタグ・レイヤーリストをカスタマイズした
  4. ✅ 物理衝突マトリックスの設定が適切に構成されている
  5. ✅ プリセット機能を追加する場合、保存と読み込みが正しく動作するか確認
  6. ✅ プロジェクト間で共有する場合、エクスポート・インポート機能が正しく動作するか確認

まとめ

Unity エディタ拡張を活用することで、タグとレイヤーの設定という単調な作業を自動化し、プロジェクト設定の一貫性を保てるようになります。さらに、この記事で紹介した手法は、タグとレイヤー以外のプロジェクト設定にも応用可能です。

エディタ拡張は以下の場面で特に効果を発揮します:

Unity のエディタ拡張機能は非常に強力で、自分たちのワークフローに合わせたカスタマイズが可能です。ぜひ、自分のプロジェクトに合わせたエディタ拡張ツールを開発してみてください。

参考資料


この記事は、Unity 2020.3以上を基準に作成されています。新しいバージョンでは設定方法が異なる場合があります。

Unityエディタ拡張タグ管理レイヤー管理ゲーム開発自動化