- Home /
Custom PropertyDrawer fails because my ScriptableObject property is not initialized in time
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;
}
}
Answer by lindsaytalbot · Jun 20, 2017 at 03:19 PM
For anyone else who finds this issue
SerializedObject obj = new SerializedObject(property.objectReferenceValue); var prop= obj.FindProperty("propName");
Life saver. Thank you. I've been converting serialized classes into scriptable objects, and could not for the life of me figure out why my PropertDrawers for those classes were broken. This fixes things now! Thanks!