6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityAdvent Calendar 2021

Day 6

エディタのカスタムモードを作成する

Last updated at Posted at 2021-12-06

この記事は、Unity #2 Advent Calendar 2021 6日目の記事になります。

概要

現在、Unityでは起動時にコンパイルエラーなどがあるとセーフモードで立ち上げることができるようになっています。
この際表示されるエディタは通常とは少し異なり、再生ボタンなどがあった場所にセーフモードである旨が表示され、メニューバーの内容も通常とは異なります。
今回はこのようなオリジナルのモードを作成する方法について少しだけわかったので記事にします。

※現状これらの方法についてはマニュアルに記載されていないため、今後変更される可能性があります。

準備

使用しているバージョン : Unity 2021.2.5f1

まずはパッケージを作ります。これはモード変更機能が以下の場所を読むようになっているためです。

  • Unity.exeのパス/Data/Resources/default.mode (EditorApplication.applicationContentsPath + "/Resources/default.mode")
  • パッケージフォルダ内

パッケージの作成方法については話が逸れるので割愛します。
詳しくはこちらをご覧ください

今回はこのような構造にします。
image.png
Modeフォルダ内には、カスタムモードのレイアウトファイルである.modeファイルを配置してください。

モードを定義する

準備段階で作成したmodeファイルの中身を記述していきます。試しに今回はこのようなレイアウトにします。
また、メニューバーも内容を変更します。
image.png

左側 : タブ移動不可のHierarchy, タブ移動不可のInspector
中央 : タブ移動可のSceneView, タブ移動可のGameView
右側 : タブ移動不可のQuickSearch

custom_mode.mode
custom_mode = 
{
    label = "Custom Mode"
    version = "1.0.0"

    pane_types = []


    layout = 
    {
        vertical = true
        center_view = 
        {
            horizontal = true
            children = 
            [    
                {
                    size = 10
                    vertical = true
                    children = 
                    [
                        {
                            size = 20
                            class_name = "SceneHierarchyWindow"
                        }
                        {
                            size = 80
                            class_name = "InspectorWindow"
                        }
                    ]
                }       
                {
                    size = 70
					vertical = true
                    children = 
                    [
						{
							size = 80
		                    tabs = true
							children = 
							[
								{
									class_name = "SceneView"
								}
								{
									class_name = "GameView"
								}
							]
						}
                    ]
                }
                {
                    size = 20
                    vertical = true
                    children = 
                    [
                        { class_name = "QuickSearch" }
                    ]
                }
            ]
        }
    }

    menus = [
        {
            name = "File"
            children = [
                { name = "Exit" }
            ]
        }
        {
            name = "Custom Mode"
            children = [
                {
                    name = "Return to Unity"
                    command_id = "Commands/Return to Unity"
                }
            ]
        }
        {
            name = "Window"
            children = [
                {
                    name = "Return to Unity"
                    command_id = "Commands/Return to Unity"
                }
            ]
        }
    ]

    capabilities = {
        // Never save this mode as the current
        remember = false

        // Update the layout when switching to safe mode.
        layout_switching = true
        layout_window_menu = false
        status_bar_extra_features = false
        allow_asset_creation = false
        
        playbar = false
        layers = false
    }
}

この状態でImmediate Windowで確認すると読み込まれていることがわかります。
正常に読み込まれていない場合はアセンブリ更新時にパースエラーが出ているはずです。
image.png

モードファイル各要素説明

トップ階層

custom_mode = { }

トップの階層。custom_modeの部分が後ほどスクリプトから指定する際のIDになる。

表示名

label = "Custom Mode"

ModeService.modeNamesで取得する際の名前

レイアウト

layout = { }

エディタのウィンドウレイアウトを記述する階層

向き

// 縦
vertical = true

// 横
horizontal = true

これ以降の要素はその要素内に更にこの指定が無い限りはここで指定した向きで並べられる。
EditorGUILayout.BeginVertical()みたいなイメージ

場所

// 再生バーがある領域
top_view = { }

// 再生バー以下の領域
center_view = { }

子要素

children = [ ]

この中に複数表示ウィンドウを指定することができる。入れ子可能

サイズ

// 比率指定
size = (0 ~ 100)

// 最低サイズをピクセル指定
min_width = 1024
min_height = 768

そのウィンドウや領域のサイズ。

タブ移動可否設定

tabs = true

表示ウィンドウ指定

// シーンビューを表示
class_name = "SceneView"

表示対象のEditorWindow継承クラス名。
自作のWindowでもここに書けば表示できる。

メニューバー

menus = { }

メニューバーの各要素を記述する階層

メニュー名

name = "File"

メニューアイテムの名前

子要素

children = [ ]

この中に更にメニューの子要素を入れることができる。入れ子可能

コマンド

command_id = "Commands/Return to Unity"

メニューアイテム実行時に呼び出すコマンドを指定する。後述

セパレーター

{ name = "Undo" }
{ name = "Redo" }
null
{ name = "Copy" }
{ name = "Paste" }

要素の間にnullを入れることによって、そこはセパレーターになる

機能設定

capabilities = { }

各機能の設定を記述する階層

レイアウト切り替え

layout_switching = true

無効の場合はtop_viewとメニューバーのみ切り替わる

PlayMode

playbar = false

再生・一時停止・ステップのボタン群の表示/非表示切り替え

Layer

layers = false

レイヤドロップダウンの表示/非表示切り替え

モードをスクリプトから変更する

CustomModeEditor.csファイルの中に例として以下のように記述する

CustomModeEditor.cs
using UnityEditor;

// ReSharper disable once CheckNamespace
namespace CustomEditorMode.Editor
{
    public static class CustomModeEditor
    {

        [MenuItem("Custom Mode/Enable")]
        public static void EnableCustomMode()
        {
            ModeService.ChangeModeById("custom_mode");
        }

        [CommandHandler("Commands/Return to Unity", CommandHint.Menu | CommandHint.Validate)]
        private static void DisableCustomMode(CommandExecuteContext context)
        {
            ModeService.ChangeModeById("default");
        }
    }
}

モード変更

ModeService.ChangeModeById("mode id")を使用し、前述した.modeファイルのidを指定する。
ここでは例としてメニューから呼び出すようにしている。

コマンド

CommandHandlerアトリビュートをコマンドで発火させたい関数に付与し、idを前述した.modeファイルのcommand_idにする。
この際、関数の引数にCommandExecuteContextを入れるのを忘れないように。(ただし使用されているところは見つからなかった)

余談

ModeServiceの実装に関してはUnityCsReferenceにあるほか、色々とリポジトリ内探索をしていると新しい発見があるので面白いと思う。

最近は非エンジニアでもUnityで作業する場面が増えてきたように思うので、こういった機能を用いて専用の編集レイアウトを組んであげることで初手の情報量の多さを軽減できそう。
また、プロジェクト構造が決定されているのであればProjectWindowを表示させないことでプロジェクトが汚れるのを防ぐなど使い道はありそう。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?