【Unity】シーンを切り替えるエディタ拡張の作り方

f:id:tmls:20200711142713g:plain

シーンが増えてくると毎回Assetsフォルダからダブルクリックしてシーン移動するのは面倒ですよね。
そんな時はシーンを簡単に切り替えられるウィンドウを作ってしまいましょう。

エディタ拡張

Unityにはエディタ拡張という便利なものがあります。
独自で作ったスクリプトでUnityをカスタマイズできる機能ですね。

今回はこれを使ってシーン遷移用に独自のウィンドウを作ってみましょう。

下準備

「Editor」という名前のフォルダを作成します。
いつものように、Projectビューから右クリック > Create > Folderで作りましょう。
名前が「Editor」であれば場所はどこでも大丈夫です。

次にEditorフォルダの中に新しくスクリプトを作成します
右クリック > Create > C# Scriptです。
名前は何でも良いですがこの記事では「SceneWindow.cs」として進めます。

作成した「SceneWindow.cs」を開きましょう。
(ここでクラス名とファイル名が一致しているかも念の為確認してください。)

スクリプト作成

↓のスクリプトをコピペしましょう。
SceneWindowと書かれている場所は自分のクラス名に書き換えてください。

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

public class SceneWindow : EditorWindow
{
    // ボタンの大きさ
    private readonly Vector2 _buttonMinSize = new Vector2(100, 20);
    private readonly Vector2 _buttonMaxSize = new Vector2(1000, 100);

    //! MenuItem("メニュー名/項目名") のフォーマットで記載してね
    [MenuItem("MyGame/SceneWindow")]
    static void ShowWindow()
    {
        // ウィンドウを表示!
        EditorWindow.GetWindow<SceneWindow>();
    }

    void OnGUI()
    {
        // レイアウトを整える
        GUIStyle buttonStyle = new GUIStyle("button") {fontSize = 30};
        var layoutOptions = new GUILayoutOption[]
        {
            GUILayout.MinWidth(_buttonMinSize.x),
            GUILayout.MinHeight(_buttonMinSize.y),
            GUILayout.MaxWidth(_buttonMaxSize.x),
            GUILayout.MaxHeight(_buttonMaxSize.y)
        };

        // Titleボタンを作る
        if (GUILayout.Button("Title", buttonStyle, layoutOptions))
        {
            // シーンを保存するか確認
            if(!EditorSceneManager.SaveModifiedScenesIfUserWantsTo(new Scene[]{SceneManager.GetActiveScene()})) return;
            // Titleシーンを開く
            OpenScene("Title");
        }
    }

    // シーンを開ける関数
    private void OpenScene(string sceneName)
    {
        var sceneAssets = AssetDatabase.FindAssets("t:SceneAsset")
            .Select(AssetDatabase.GUIDToAssetPath)
            .Select(path => AssetDatabase.LoadAssetAtPath(path, typeof(SceneAsset)))
            .Where(obj => obj != null)
            .Select(obj => (SceneAsset) obj)
            .Where(asset => asset.name == sceneName);
        var scenePath = AssetDatabase.GetAssetPath(sceneAssets.First());
        EditorSceneManager.OpenScene(scenePath);
    }
}

使い方

ここまで来たらシーン遷移のウィンドウが使えます。
Unityの上のバーに「File」や「Edit」と並んで「MyGame」が増えていると思います。
そこから、「SceneWindow」を選択すればウィンドウが現れシーン遷移出来るボタンが使えます!

コード解説

using

最初に様々なusingがありますが、必要なものなので書いておきましょう。
中でもusing UnityEditor;は少し特別で、これを書いたスクリプトファイルはEditorフォルダの中に入れておく必要があります

public class SceneWindow : EditorWindow

EditorWindowというクラスを継承しています。
こうすることでUnityのWindowを作る事ができます。

[MenuItem("MyGame/SceneWindow")]

[ ]で囲われていますが、これはアトリビュートといいます。
アトリビュートは基本的に、関数や変数の宣言の直前に書きます。
今回はShowWindow()という関数の前に書いています。

このMenuItemアトリビュートをつけると、Unityの上の方にある「File」や「Edit」と同じような項目を増やすことが出来ます。
MenuItem("メニュー名/項目名")のように書きます。

f:id:tmls:20200711150152p:plain

void OnGUI()

ウィンドウに表示するものの設定はこのOnGUI()関数内で行います。
Unityが描画を行うタイミングで呼び出すので、これは必ずのこの名前にしてください。

GUIStyle buttonStype = ...

ボタンの見た目の調整はGUIStyleを使うことで決める事ができます。
今回は、フォントサイズを30に設定しています。

var layoutOptions = new GUILayoutOption[]

ボタンの配置(レイアウト)はGUILayoutOptionを使う事で設定できます。
実際には複数の設定をすることが多いので、GUILayoutOption[]で指定します。

今回はボタンの最小サイズ、最大サイズを設定しています。

if (GUILayout.Button("Title", buttonStyle, layoutOptions))

GUILayout.Button関数を使うとボタンを作る事ができます。
引数には、ボタンに表示する文字、GUIStyleGUILayoutOption[]を指定します。

ボタンをクリックすると返り値がtrueになるので、if文の中身はボタンが押されたときの動作を書くことが出来ます。

if(!EditorSceneManager.SaveModifiedScenesIfUserWantsTo(new Scene[]{SceneManager.GetActiveScene()})) return;

シーンの移動前に現在のシーンを保存するか尋ねます。(現在シーンに変更が無ければ尋ねません)

いつもの↓の画面ですね。
f:id:tmls:20200711153538p:plain

Cancelを押すとfalse、それ以外はtrueを返します。

OpenScene("Title");

「Title」という名前のシーンを開きます
OpenScene関数は独自実装ですが、やや複雑なので説明は飛ばします。
引数の値を変える事で開くシーンを変える事ができます。

ボタンを増やすには

// Titleボタンを作る
if (GUILayout.Button("Title", buttonStyle, layoutOptions))
{
    // シーンを保存するか確認
    if(!EditorSceneManager.SaveModifiedScenesIfUserWantsTo(new Scene[]{SceneManager.GetActiveScene()})) return;
    // Titleシーンを開く
    OpenScene("Title");
}

↑のコードがボタンを1つ作成している部分です。
これをコピペするなり、関数化して"Title"となっている部分を書き換えればボタンを増やせます!

おまけ:ゲーム再生ボタンを作りたい!

EditorApplication.ExecuteMenuItem("Edit/Play");

と書くことで現在のシーンの再生ができます。
タイトルシーンに移動 → ゲームを再生
みたいにすれば、さらに手間を省けるかもしれないですね!