Hi! I try to made a custom property drawer to have a 2D grid in the inspector (I need a 3D grid actually, like a voxel buffer).
I have 3 ScriptableObjects :
- Level,
- TileGrid,
- Tile,
Each level has a reference to a tilegrid. I want the grid displaying in the inspector on level ‘.asset’ file selection, so I made a custom PropertyDrawer related to TileGrid class.
My issue is that, when my OnGUI method is executed, an error raises when the program trying to access to a serialized property of tilegrid instance: the error say that there is no tilegrid instance. In my opinion, this is because my level instance has no correct default tilegrid value (null).
I noticed that, when I select a ‘.asset’ level file in Unity Editor, the OnGUI function is executed before the OnEnable method of TileGrid (this is where I initialize the default tilegrid value and I don’t see how to do it differently). Is someone has a solution about this?
EDIT: Confusion of mine, OnEnable is called only on object load. So how to define default ScriptableObject properties values inside an other ScriptableObject ? Is it even possible ?
Tile :
[System.Serializable]
[CreateAssetMenu (menuName ="Gamedata/Tile")]
public class Tile : ScriptableObject
{
public string meshFile;
public string textureFile;
}
TileGrid :
[System.Serializable]
public class TileGrid : ScriptableObject
{
public int dimX = 4;
public int dimY = 4;
private int dimZ = 1;
public Tile[,,] tiles;
void OnEnable()
{
if(tiles == null)
{
tiles= new Tile[dimX, dimY, dimZ];
for(int z =0; z<dimZ; z++) {
for(int y = 0; y<dimY; y++) {
for(int x = 0; x<dimX; x++) {
tiles[x, y, z] = ScriptableObject.CreateInstance<Tile>();
}
}
}
}
}
}
Level:
[CreateAssetMenu(menuName = "Gamedata/Level")]
public class Level : ScriptableObject {
public TileGrid grid;
void OnEnable()
{
if (grid == null)
grid = ScriptableObject.CreateInstance<TileGrid>();
}
Custom PropertyDrawer:
[CustomPropertyDrawer(typeof(TileGrid))]
public class TileGridProperty : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PrefixLabel(position, label);
int dimX = property.FindPropertyRelative("dimX").intValue; // ERROR occurs
int dimY = property.FindPropertyRelative("dimY").intValue;
int dimZ = property.FindPropertyRelative("dimZ").intValue;
position.y += 18f;
position.width /= dimX;
position.height /= dimY;
SerializedProperty tileGrid = property.FindPropertyRelative("tileGrid");
for(int z=0; z < dimZ; z++) {
SerializedProperty arrayZ = tileGrid.GetArrayElementAtIndex(z);
for(int y=0; y < dimY; y++) {
SerializedProperty arrayY = arrayZ.GetArrayElementAtIndex(y);
for(int x=0; x < dimX; x++) {
SerializedProperty arrayX = arrayY.GetArrayElementAtIndex(x);
SerializedProperty tile = arrayX.GetArrayElementAtIndex(0);
EditorGUI.PropertyField(position, tile, GUIContent.none);
}
}
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 18f;
}
}