- Home /
Creating a PropertyDrawer for a fixed size int array
Disclaimer: I'm (very) new to Unity. Probably getting in over my head, but I find that to be the quickest way to learn.
Using Unity 4.5, scripting in C#
TLDR; I need to create a property drawer that shows 4 specific elements of a fixed size array, doesn't allow array resizing, and has custom labels. My attempts so far only let me overwrite the drawer for the individual array elements. HALP!!! /TLDR;
I have the following class: Assets/Scripts/Board/Cell.cs
using UnityEngine;
using System.Collections;
namespace Board {
public class Cell : MonoBehaviour {
const int MIN_PENALTY = 0;
const int MAX_PENALTY = 2;
[BoardCellPenaltiesAttribute] public int[] penalty;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public int getPenalty(int dir) {
if (dir > 0 && dir < penalty.Length) {
return penalty[dir];
}
return 0;
}
public void setPenalty(int dir, int val) {
if (val >= MIN_PENALTY && val <= MAX_PENALTY) {
penalty[dir] = val;
}
}
}
}
I created the following Attribute: Assets/Scripts/Z_Editor/Attributes/BoardCellPenaltiesAttribute.cs
using UnityEditor;
using UnityEngine;
public class BoardCellPenaltiesAttribute : PropertyAttribute {
public BoardCellPenaltiesAttribute () {}
}
Finally I have this PropertyDrawer:
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer (typeof (BoardCellPenaltiesAttribute))]
public class BoardCellPenaltiesDrawer : PropertyDrawer {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.HelpBox (position, property.type.ToString () , MessageType.None);
}
}
All the tutorials I've tried say this method should allow me to create a drawer for the whole array. What I see is the dropdown for Penalties, a size input box, then one helpbox per array element. The help box prints a type of int, not int[].
Why is my attribute applying to each element of the array rather than the array itself, and how can I override the drawer for the entire array? Ultimately I'm trying to prevent the editor from resizing the array and also show custom labels and edit boxes for 4 and only 4 elements of the array. Esoteric I know.
Hi TBernard
It should be pretty straight-forward draw your 4 items in the inspector using a PropertyDrawer. You can simply use the SerializedProperty method GetArrayElementAtIndex to get the SerializedProperty at a given index and feed it into a PropertyField.
I would suggest, however, perhaps you are better served storing 4 fields inside BoardCellPenaltiesAttribute, ins$$anonymous$$d of an array.
@VesuvianPrime - Thanks. I actually tried GetArrayElementAtIndex() but I get this error:
Retrieving array element but no array was provided
UnityEditor.SerializedProperty:GetArrayElementAtIndex(Int32)
It seems the property being passed into the OnGUI function is not the serialized array, but rather each of it's members.
Also, I know it's odd use of an array, but its going to simplify how I interact with the object down the road.
The SerializedProperty co$$anonymous$$g into the OnGUI method should be the serialized BoardCellPenaltiesAttribute. You can get the children of it using FindPropertyRelative, just make sure you're flagged your fields as [SerializeField].
Answer by TBernard · Jan 31, 2015 at 10:56 PM
After beating my head against this wall for a day I finally noted THIS gem in the introductory blog post.
Namely, "You can't make a PropertyDrawer for arrays or generic lists themselves." and "elements inside arrays and lists do work with PropertyDrawers"
Guess it can't be done. Time to look at different approaches.
I'm pretty confident it can be done. Just make a hierarchy that looks like:
[Serializable]
BoardCellPenaltiesAttribute : PropertyAttribute
{
[SerializeField] public int[] myFixedArray;
}
And then in your PropertyDrawer you can do stuff like:
[CustomPropertyDrawer (typeof (BoardCellPenaltiesAttribute))]
public class BoardCellPenaltiesDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
SerializedProperty arrayProp = property.FindPropertyRelative("myFixedArray");
SerializedProperty firstIntProp = arrayProp.GetArrayElementAtIndex(0);
EditorGUI.PropertyField(position, firstIntProp, label);
// etc
}
}
There's a little more work to do, namely overriding the height of the property drawer (4 rows?) but this kind of approach should do exactly what you want.
@VesuvianPrime - Ah I see. I suppose if I made my array part of a serializable object then yes I could attach the drawer to that object. That's different then the custom attribute approach I was trying to use where the data was in a normal int array and a custom [BoardCellPenaltiesAttribute] was used to change how the editor shows it. That might be the approach I have to take. Its either that or a custom inspector anyway. Thanks.