Experimental Node Inspector

Today, I’ve been working on the node inspector of a BananaTree node. The inspector displays information about the selected node. It’s most important use, though, is to set variables of a node. Every property in an action that has a public getter and setter would be considered as a variable. This information could be retrieved through reflection. For now, I’m playing with string properties and I’m quite happy with the result. Variables are automatically added to the node data based from the action node class (properties) if they are not yet found. Its value can also be set through the inspector.

Node inspector, woot!
Node inspector, woot!

I stumbled upon a very useful discovery. Serialized generic classes can be used in Unity with a little help. We know that Unity can’t serialize Dictionary. I need something that works like a Dictionary for the named variables but stores the serializable items in a List. Let’s say we have the following class that stores a single string variable:

    [Serializable]
    public class StringVariable {

        [SerializeField]
        private string name;

        [SerializeField]
        private string stringValue;

        /**
         * Default constructor
         */
        public StringVariable() {
        }

        /**
         * Constructor with specified name and value
         */
        public StringVariable(string name, string value) {
            this.name = name;
            this.stringValue = value;
        }

        public string Name {
            get {
                return name;
            }
            set {
                name = value;
            }
        }

        public string Value {
            get {
                return this.stringValue;
            }
            set {
                this.stringValue = value;
            }
        }

    }

A list of StringVariable instances can be specified as:

public class SomeComponent : MonoBehaviour {
    [Serializable]
    private List<StringVariable> stringVariables;
}

I don’t like this because I’ll have to bake functions like GetStringVar(string name) into the component. I don’t just have string variables. I’ll have int, float, GameObject, Vector3 later on. GetIntVar(), GetFloatVar(), GetVector3Var(), …? No way. This is where I tried to make a generic container class that stores items in a list but provides Dictionary like methods. The first step is to provide an interface to mark classes that it has something that returns a name.

    public interface Named {

        /**
         * Returns a name
         */
        string Name {get;}

    }

StringVariable now implements this interface:

    public class StringVariable : Named {
        ...
    }

This is my generic container that maintains items in a list:

    [Serializable]
    public class VariableMap<T> where T : Named {

        [SerializeField]
        private List<T> itemList;

        /**
         * Constructor
         */
        public VariableMap() {
        }

        /**
         * Adds an item
         */
        public void Add(T item) {
            this.itemList.Add(item);
        }

        /**
         * Removes an item
         */
        public void Remove(T item) {
            this.itemList.Remove(item);
        }

        /**
         * Returns the item with the specified name
         */
        public T Get(string name) {
            int count = itemList.Count;
            for(int i = 0; i < count; ++i) {
                if(itemList[i].Name.Equals(name)) {
                    return itemList[i];
                }
            }

            // not found
            return default(T);
        }

        /**
         * Returns whether or not the map contains an item with the specified name
         */
        public bool Contains(string name) {
            int count = itemList.Count;
            for(int i = 0; i < count; ++i) {
                if(itemList[i].Name.Equals(name)) {
                    return true;
                }
            }

            return false;
        }

    }

Everything’s good so far but I had a problem. This does not work (it does not display in Unity inspector):

public class SomeComponent : MonoBehaviour {
    [Serializable]
    private VariableMap<StringVariable> stringVariables;
}

I tried a little magic:

    [Serializable]
    public class StringVariableMap : VariableMap<StringVariable> {
    }

Now this works in Unity:

public class SomeComponent : MonoBehaviour {
    [Serializable]
    private StringVariableMap stringVariables;
}
Serialized generic class!
Serialized generic class!

This is so cool! This has countless possibilities. Its weakness, though, is it implies that I’ll have classes like IntVariableMap, FloatVariableMap, GameObjectVariableMap, etc. But this is a small price to pay. My main goal is to put the code of the custom container in one class and I have done that.

If you have a better idea, please do tell me.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s