【Unity】カスタムエディタで配列のサイズを変更する方法
最近Unityのカスタムエディタを覚えたので、ゲーム制作でステータスを設定しやすいようにインスペクターをカスタマイズしています。
ところで、カスタムインスペクターで配列の要素を表示したり変更する方法や、配列の長さを表示する方法は見つかるのですが、配列の長さを変更する方法はなかなか見つかりませんでした。
上の画像はデフォルトのインスペクター上の表示ですが、「Element」をカスタムインスペクターで再現する方法は見つかるのですが、「Size」を変更する方法が分からない…(表示するだけなら簡単なのですが)
いろいろな記事を調べた結果、カスタムインスペクターで配列の長さを表示、変更する方法が分かったのでメモしておきます。
まだエディタ拡張を始めて数日の初心者なので、もっと簡単で良い方法があるのかもしれませんが、もしあれば教えて頂きたいです。
例として、Playerというクラスに Weaponという独自クラスの配列が入っている場合を想定して書いてみました。
Playerクラスの内容 ↓
weaponという配列を持ち、weaponにはさらにaccessoryが付いています。
using System;
using System.Collections;
using UnityEngine;
public class Player : MonoBehaviour
{
public Weapon[] weapons;
[System.Serializable]
public class Weapon
{
public string name;
public int power = 100;
public Accessory accessory;
}
[System.Serializable]
public class Accessory
{
public string name;
}
}
エディタ拡張の内容 ↓
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(Player))]
public class Player_CustomEditor : Editor
{
private int listSize = 0;//配列の長さを一時的に保存するための変数
public override void OnInspectorGUI()
{
serializedObject.Update(); //serializedObjectを最新に更新
var weapons = serializedObject.FindProperty("weapons"); //Playerクラスの配列weaponsを取得
Player player = target as Player; //Playerクラスのインスタンスを取得
listSize = weapons.arraySize; //配列weapons の長さを一時的に変数に保存しておく
listSize = EditorGUILayout.IntField("Size", listSize);//一時的に保存した配列の長さをカスタムインスペクタに描画(ここで書き換えも可能)
EditorGUILayout.Space(); //スペースを描画
//一時的に保存した配列の長さと、本来の配列の長さが同じかチェックする
if (listSize != weapons.arraySize)
{
//長さが違う場合は
weapons.arraySize = listSize; //長さの変更を適用
//ここでserializedObjectへの変更を適用し、再び更新する
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
else
{
//一時的に保存した配列の長さと、本来の配列の長さが同じ場合は 配列の要素を描画する
for (int i = 0; i < weapons.arraySize; ++i)
{
player.weapons[i].name = EditorGUILayout.TextField("name:", player.weapons[i].name);
player.weapons[i].power = EditorGUILayout.IntField("Power:", player.weapons[i].power);
player.weapons[i].accessory.name = EditorGUILayout.TextField("accessory name:", player.weapons[i].accessory.name);
EditorGUILayout.Space(); //スペースを描画
}
}
base.OnInspectorGUI(); //正しく動作しているか確認にするために、元のインスペクターを表示
serializedObject.ApplyModifiedProperties(); //serializedObjectへの変更を適用
}
}
長くなりましたが、重要な部分を抜き出すと下記のようになります。
配列の長さを一時的にlistSizeに入れておいて、listSizeと配列の長さが違う場合は、 serializedObject.ApplyModifiedProperties() 、 serializedObject.Update()
を呼ぶ、という方法です。
listSize = weapons.arraySize; //配列weapons の長さを一時的に変数に保存しておく
listSize = EditorGUILayout.IntField("Size", listSize);//一時的に保存した配列の長さをカスタムインスペクタに描画(ここで書き換えも可能)
//一時的に保存した配列の長さと、本来の配列の長さが同じかチェックする
if (listSize != weapons.arraySize)
{
weapons.arraySize = listSize; //長さの変更を適用
//ここでserializedObjectへの変更を適用し、再び更新する
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
else
{
//ここに配列の要素を描画する内容を書く
}
実行するとこのような感じで、上半分の拡張したインスペクターで配列の長さや要素を操作すると、下半分のオリジナルのインスペクターに反映されていることが分かります。