2024/06/10 / Unity

Odin でコンテキストエディター作ってみた

Odin でプランナー向けのコンテキストエディターを作った話

unity plugin tool

こんにちは!パン君です。

インディーズのプロジェクトで Odin Inspector を使用して、
プランナーが Unity の知見をあまり持っていなくても触れるような プロジェクト専用の「コンテキストエディター」 を作成しました。

ここでいう「コンテキストエディター」は、

「ゲーム内の◯◯に関係するデータを、ひとつの画面でまとめて編集できるツール」

のイメージです。

  • キャラやステージのパラメータ
  • 掲載テキストや説明文
  • 報酬テーブルやフラグ設定

など まとまりとして扱いたい情報を、一箇所から編集できるようにした という話になります。


概要

もともとプロジェクトでは、データ構造を ScriptableObject や CSV で管理していましたが、

  • 「どのデータがどこにあるのか」が分かりづらい
  • パラメータを変えるために 何個もアセットを開く必要がある
  • プランナーが Unity の Project ウィンドウを漁るのに時間がかかる

という課題がありました。

そこで、

「◯◯の仕様を触るときは、とりあえずこのウィンドウを開けばいい」

という 専用の編集画面(コンテキストエディター) をOdinで作りました。

やったことをざっくりまとめると:

  • Odin の OdinEditorWindow を使って 専用ウィンドウを作成
  • プランナーが触る想定の ScriptableObject をまとめてバインド
  • 絞り込み・検索・ボタン操作などを Odin の属性でサクッと実装
  • 「触ってはいけない項目」は ReadOnly / Foldout / Box などでガード

という構成です。


やりたかったこと

このコンテキストエディターでは、主に次のような体験を目指しました。

1. 「どこを触ればいいか」が一目で分かる

  • プランナーが Unity に詳しくなくても、
    • 左側にカテゴリー
    • 右側に編集する内容
  • という形で、「エクセルを開く感覚」でパラメータを触れるようにしました。

具体的には:

  • セクションごとに FoldoutTitle 属性で区切る
  • 「ゲーム内に表示される文言」だけをまとめた枠を用意
  • 管理用の ID や内部フラグは ReadOnly で表示のみ

など、Odin の装飾系属性をフル活用しています。

2. 関連データを横断して編集できる

たとえば「◯◯イベント」のコンテキストだったら、

  • イベント全体の基本設定
  • 各ステージの難易度テーブル
  • 報酬テーブル
  • ガイド用のテキスト

など、別々の ScriptableObject に分かれている情報を、 1つのウィンドウに並べて編集 できるようにしました。

Odin の InlineEditorTableList を使うことで、

  • 参照先の ScriptableObject を、その場で展開して編集
  • 配列・リストをテーブル形式で編集

といった UI を、カスタム EditorWindow 側に貼り付けることができました。

3. 安全な範囲だけ触れるようにする

  • プランナーには見えてほしいが、触ってほしくないフィールド
  • 開発途中で変更すると危険なフラグ

こういったものは、

  • ReadOnly 属性でロック
  • HideIf / ShowIf でそもそも見せない
  • InfoBox で注意書きを出す

などの工夫を入れて、 「自由度は残しつつ、壊れにくい UI」にする ことを意識しました。


実装構成

技術的な構成は、おおよそこんな感じです。

1. ベースとなる Window クラス

  • OdinEditorWindow を継承した ContextEditorWindow を用意
  • MenuItem 属性でメニューから開けるようにする
Csharp
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using UnityEditor;
using UnityEngine;

public class ContextEditorWindow : OdinEditorWindow
{
    [MenuItem("Tools/Context Editor")]
    private static void Open()
    {
        GetWindow<ContextEditorWindow>("Context Editor");
    }

    // プランナーが触る対象をここに並べる
    [Title("イベント基本設定")]
    [InlineEditor(Expanded = true)]
    public EventConfig eventConfig;

    [Title("ステージ設定")]
    [TableList]
    public StageConfig[] stages;

    [Title("報酬設定")]
    [TableList]
    public RewardConfig[] rewards;

    // 必要なら、検索・フィルタ用のフィールドもここに置く
}

ウィンドウを開くだけで

  • 指定したScriptableObjectの中身が 同じ画面 に展開される
  • その場で値を編集、ほぞんが 反映される

という状態にできます。

2. ScriptableObject側の設計

もともとのデータ構造をScriptableObject化しておけば

  • プロジェクト全体では通常通りScriptableObjectとして利用
  • 編集時だけコンテキストエディターのウィンドウからアクセス

という二重の使い方ができます。

例えば :

Csharp
[CreateAssetMenu(menuName = "Game/Event")]
public class EventConfig : ScriptableObject
{
    [LabelText("イベント名")]
    public string eventName;
    
    [LabelText("開催期間")]
    public string durationText;
    
    [LabelText("説明文")]
    public string description;
    
    [LabelText("有効フラグ")]
    public bool isEnabled;
}

これを先ほどのContextEditorWindowのフィールドとして参照しておけば、
ウィンドウ側でInlineEditorしたときに、 Odinのデコレーション込みで表示されます

3. ちょっとしたUX改善

例:

  • 「選択中のステージだけテストシーンを起動する」ボタン
  • 「報酬テーブルをデフォルト値で初期化する」ボタン
  • 「特定 ID のデータを検索してフォーカス」ボタン

Odin の Button 属性を使えば、EditorWindow 内にメソッドをそのままボタンとして出せるので、 ちょっとしたツール感を簡単に足せます

実際に運用してみて

実際にプランナーに使ってもらって感じたメリットはこんな感じでした。

  • 「この仕様を触りたいときは、このウィンドウを開けばいい」という入口が固定された
  • Unity の Project ウィンドウや Inspector をさまよう時間が減った
  • パラメータの更新とコミュニケーションのログが取りやすくなった(「この画面のここを変えました」と言いやすい)
  • 誤操作されると困る部分は最初からロックしておけるので、事故が減った

一方で、課題としては:

  • コンテキストエディター自体のメンテナンスコストが発生する
  • データ構造を弄るときは、Editor 側の反映も忘れないようにする必要がある
  • UI を作り込みすぎると「専用ツール」になりすぎて、柔軟性が落ちる

といった点もありました。

最後に

Odin を使ったコンテキストエディターは、

  • 「プランナーが直接触れる Unity ツール」を作りたいとき
  • 「プロジェクト専用の編集画面」をサクッと用意したいとき

にかなり相性がいいと感じました。

Inspector 拡張だけでは足りないけれど、EditorWindow をフルスクラッチするのは大変
というケースでは、Odin の属性と EditorWindow を組み合わせるだけで、
「ちょうどいいライン」のツールが作りやすいです。

今後は、

  • もう少し UI/UX を整理したバージョン
  • 別プロジェクトでも使い回せるような抽象化

にもチャレンジしてみたいと思っています。

興味があれば、別の記事で具体的なコードや属性の使い方も掘り下げていくので、また読んでもらえたら嬉しいです。

← Odin を導入してみた← ブログ一覧へ戻るDiscord Bot の… →