この記事は、Unity #2 Advent Calendar 2021 6日目の記事になります。
概要
現在、Unityでは起動時にコンパイルエラーなどがあるとセーフモードで立ち上げることができるようになっています。
この際表示されるエディタは通常とは少し異なり、再生ボタンなどがあった場所にセーフモードである旨が表示され、メニューバーの内容も通常とは異なります。
今回はこのようなオリジナルのモードを作成する方法について少しだけわかったので記事にします。
※現状これらの方法についてはマニュアルに記載されていないため、今後変更される可能性があります。
準備
使用しているバージョン : Unity 2021.2.5f1
まずはパッケージを作ります。これはモード変更機能が以下の場所を読むようになっているためです。
- Unity.exeのパス/Data/Resources/default.mode (EditorApplication.applicationContentsPath + "/Resources/default.mode")
- パッケージフォルダ内
パッケージの作成方法については話が逸れるので割愛します。
詳しくはこちらをご覧ください
今回はこのような構造にします。
Modeフォルダ内には、カスタムモードのレイアウトファイルである.modeファイルを配置してください。
モードを定義する
準備段階で作成したmodeファイルの中身を記述していきます。試しに今回はこのようなレイアウトにします。
また、メニューバーも内容を変更します。
左側 : タブ移動不可の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で確認すると読み込まれていることがわかります。
正常に読み込まれていない場合はアセンブリ更新時にパースエラーが出ているはずです。
モードファイル各要素説明
トップ階層
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ファイルの中に例として以下のように記述する
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を表示させないことでプロジェクトが汚れるのを防ぐなど使い道はありそう。