次のようにレイヤー(整数)の値をインスペクターから選択式で設定させる方法はないの?
やり方はいくつかあるけど、構造体を自作すれば可能だわ。
スクリプト中で使用するレイヤー値をインスペクターからドロップダウンで選択可能にする方法の解説記事です。
Unityのレイヤーは0〜31の値で表現される整数値です。通常、スクリプト側からはint型として扱われます。
参考:GameObject-layer – Unity スクリプトリファレンス
しかし、上記レイヤー値をインスペクター側から設定する場合、数値を直接入力しなければなりません。
これをレイヤー名などのドロップダウン形式で指定可能にする方法はいくつかありますが、本記事では独自構造体とエディタ拡張で実現する方法を紹介します。
構造体として実装することで、次のようにレイヤー名(文字列)によるアクセスなどスクリプトの可読性向上も期待できます。
- Unity 2022.3.0f1
目次 非表示
スクリプトの完成系
まず初めに、レイヤーをインスペクターから選択式で指定可能にする構造体のスクリプトを示します。
上記をLayer.csとしてUnityプロジェクトに保存すると使用可能になります。
スクリプトの使用例
以下、前述のLayer構造体の使い方の例です。
上記をUseExample.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチすると機能します。
実行結果
インスペクターからは、次のようにドロップダウンとしてレイヤーを指定可能になります。
また、ゲームを実行すると、コンソールログにレイヤー情報が出力されます。
レイヤーをint型に変換した数値やレイヤー名を取得できています。また、Layer構造体に対してint型やレイヤー名(string型)で値を指定できることも確認できました。
スクリプトの説明
前述のLayer構造体とエディタ拡張の実装について説明していきます。
Layer構造体
構造体はシリアライズ可能な型として定義します。また、内部的にはレイヤー値を表すint型フィールドを持つものとして定義します。
レイヤー値をint型整数として取得可能にするために、次のプロパティを実装しています。
レイヤー値の取り得る範囲は0〜31のため、セットされる時は範囲チェックを行っています。範囲外なら例外ArgumentOutOfRangeExceptionをスローするようにしました。
また、レイヤー名でレイヤー値を読み書きするプロパティも実装しています。
数値からレイヤー名への変換はLayerMask.LayerToNameメソッド、逆にレイヤー名から数値への変換はLayerMask.NameToLayerメソッドで行えます。
Nameプロパティはこれらを使いやすくラップしています。
参考:LayerMask-LayerToName – Unity スクリプトリファレンス
参考:LayerMask-NameToLayer – Unity スクリプトリファレンス
また、int型のレイヤー値と暗黙的な変換を行えるように、次のオペレータを実装しています。
Property Drawerの説明
次のコードでLayer構造体のインスペクター上の表示をカスタマイズするためのProperty Drawerを定義しています。
そして、レイヤー一覧をドロップダウンで選択可能にするコードは以下部分です。
EditorGUI.LayerFieldメソッドを呼び出すことで、レイヤー選択のUIを簡単に描画できます。
参考:EditorGUI-LayerField – Unity スクリプトリファレンス
運用上における注意点
当記事で紹介したLayer構造体の運用上における注意点についても示しておきます。
整数値としてシリアライズされるので、レイヤー名が変更されると表示も変わる
Layer構造体は内部的にはint型フィールドとしてレイヤー値を保持しています。
そのため、シリアライズ内容を覗いてみると、次のように数値のみがデータとして存在します。
そのため、レイヤー名を変更したり移動したりすると、表示上のレイヤー名も変化します。
Layer構造体の注意点として挙げましたが、これはゲームオブジェクトのレイヤー名にも言える事です。
LayerMask構造体と併用する時は注意
LayerMask構造体と併用する場合は、値の変換に注意する必要があります。
int型のレイヤー値を扱う場面全般に言えることですが、レイヤーをLayerMaskに指定する場合はシフト演算などで指定する必要があります。
参考:LayerMask – Unity スクリプトリファレンス
さいごに
レイヤー値をインスペクターから選択可能にするには、エディタ拡張のEditorGUI.LayerFieldメソッドを使えば簡単です。
本記事では、どのスクリプトでも汎用的かつ簡単にレイヤー情報を扱えるようにするためにLayer構造体として実装する方法を紹介しました。
簡単のため必要最小限の機能に留めましたが、場面に応じてカスタマイズして使うと良いでしょう。