Is there a Wild Card Variable in Unity c#?

I would like to create a blackboard like Unreal Engine. Blackboard is used to access variables inside the state machine for behavioural scripts. User can add variables of any data type they want. So inherited AI controllers can have different values depending on the need of the bahaviour scripts.

I was wondering if there are WildCard Properties/Variables here on Unity. So I can create a custom editor where the users can just add the data types they want such as int,string,Gameobject, Vector3, etc.

One of my ideas in approching this without wild card property is creating a class “BlackboardKey” and can be inherited to put variable depending on the data type. for example “BlackboardKeyVector”.
Blackboard key will have a function that returns a generic type of the value it contains.

Any thoughts on this?

.176402-452e83d8-cc41-4349-a7ac-a5f147beb163.png

Unity makes extensive use of SerilizedObjects and SerializedProperties. If you take a look at their implementation of a SerializedProperty, you can see that it holds variable data for each type of data that the property can serialise. There’s also a ‘propertyType’ field which returns an enum which is defined as (cut and past from ILSpy) :

public enum SerializedPropertyType
{
    Generic = -1,
    /// <summary>
    ///   <para>Integer property.</para>
    /// </summary>
    Integer,
    /// <summary>
    ///   <para>Boolean property.</para>
    /// </summary>
    Boolean,
    /// <summary>
    ///   <para>Float property.</para>
    /// </summary>
    Float,
    /// <summary>
    ///   <para>String property.</para>
    /// </summary>
    String,
    /// <summary>
    ///   <para>Color property.</para>
    /// </summary>
    Color,
    /// <summary>
    ///   <para>Reference to another object.</para>
    /// </summary>
    ObjectReference,
    /// <summary>
    ///   <para>LayerMask property.</para>
    /// </summary>
    LayerMask,
    /// <summary>
    ///   <para>Enumeration property.</para>
    /// </summary>
    Enum,
    /// <summary>
    ///   <para>2D vector property.</para>
    /// </summary>
    Vector2,
    /// <summary>
    ///   <para>3D vector property.</para>
    /// </summary>
    Vector3,
    /// <summary>
    ///   <para>4D vector property.</para>
    /// </summary>
    Vector4,
    /// <summary>
    ///   <para>Rectangle property.</para>
    /// </summary>
    Rect,
    /// <summary>
    ///   <para>Array size property.</para>
    /// </summary>
    ArraySize,
    /// <summary>
    ///   <para>Character property.</para>
    /// </summary>
    Character,
    /// <summary>
    ///   <para>AnimationCurve property.</para>
    /// </summary>
    AnimationCurve,
    /// <summary>
    ///   <para>Bounds property.</para>
    /// </summary>
    Bounds,
    /// <summary>
    ///   <para>Gradient property.</para>
    /// </summary>
    Gradient,
    /// <summary>
    ///   <para>Quaternion property.</para>
    /// </summary>
    Quaternion,
    /// <summary>
    ///   <para>A reference to another Object in the Scene. This is done via an ExposedReference type and resolves to a reference to an Object that exists in the context of the SerializedObject containing the SerializedProperty.</para>
    /// </summary>
    ExposedReference,
    /// <summary>
    ///   <para>Fixed buffer size property.</para>
    /// </summary>
    FixedBufferSize,
    /// <summary>
    ///   <para>2D integer vector property.</para>
    /// </summary>
    Vector2Int,
    /// <summary>
    ///   <para>3D integer vector property.</para>
    /// </summary>
    Vector3Int,
    /// <summary>
    ///   <para>Rectangle with Integer values property.</para>
    /// </summary>
    RectInt,
    /// <summary>
    ///   <para>Bounds with Integer values property.</para>
    /// </summary>
    BoundsInt,
    /// <summary>
    ///   <para>Managed reference property.</para>
    /// </summary>
    ManagedReference
}

So each serialisable data value is stored in a separate field, of that type. There’s no generics in use. I would suggest using a SerializedProperty, but unfortunately some of the fields are marked as internal, and it’s pretty specific to the SerializedObject.

But once you redo your own, then you can create a new PropertyDrawer that will allow you to look at the stored data type and then display the appropriate field type (e.g. IntegerField, ObjectField etc.)

So, a simple, cut down version might look like:

public MyProperty : ScriptableObject
{
    public SerializedPropertyType propertyType;
    public int intValue;
    public float floatValue;
    public string stringValue;
    public Vector2 vector2Value;
    public Vector3 vector3Value;
    // etc., etc.
}

Obviously, you only need to put in as many types as you will actually want.

As for the PropwertyDrawer, that’ll depend of whether or not you want to use IMGUI or UIToolkit. UIToolkit is easier to implement, but doesn’t fully implement the full IMGUI Editor properties yet. It’s close, but things like array lists are still of the old style.

First of all, I wanna thank everyone who posted their answers, It did help me a lot coming up with a approach for this problem. So here is the answer that I come up with, I hope it helps other people in the future. I’m not sure if this is the best approach, so just tell me if there are better ways in handling this.


So first things first there are a few obstacles that we need to face in serializing generic types:

  • the variable “object” is the generic variable of c# and cannot be serialized in the unity editor
  • Declaring Data types one by one will quickly over populate your class for the blackboard keys.
  • We can’t easily store generic classes under the same list

I used SimpleJSON for my saving system so I figured out that I may as well use this in serializing generic types. (SImpleJSON is a free plugin you can download from the net)

Here is my BlackboardKey class:

//===================
//   I posted only the important parts since my code is quite lenghty


public class Blackboard: MonoBehaviour
{
    public List<BlackboardKey> KeyArray = new List<BlackboardKey>();
}


[System.Serializable]
public class BlackboardKey
{
    //===============================================================
    //Identification for Blackboard Components

    public string                 Name;
    public EBlackboardKeyQuantity KeyQuantity;
    public EBlackBoardKeyType     BlackboardKeyType;

    //===============================================================
    //Used for serializing Values to the generic value type

    public string SerializedValue;
    public BlackboardObjectSerializer ObjectSerializer;

    //==============================================================
    //Value of this blackboard key
    private object Value;
}

The EBlackboardKeyQuantity is an Identification if the Blackboard key is a type of Array or a Single Variable.

The EBlackboardKeyType helps to identify if the DataType is a Type of (int, string, float, Vector, gameobject, etc).

The SerializedValue is the most important part, This is where we will put are JSON value so we can serialize our “object value;” later on (During awake or something)

The ObjectSerializer has a values of “Object” this is the base class for all Objects inside unity. Used to serialize GameObject, Monobehaviour, and other things.

Now I have a class for my CustomEditor which is responsible for setting the SerializedValue. So here is how I serialize values in the editor

//This is quite lenghty too but I will post the Important part

public class BlackboardEditor : Editor
{
public void SerializeSingleKey(Rect fieldRect,int Index, SerializedProperty Type, string SerializedValue)
    {
        EBlackBoardKeyType type = (EBlackBoardKeyType)Type.intValue;

        JSONObject objSaved = string.IsNullOrEmpty(SerializedValue) ? new JSONObject() : (JSONObject)JSON.Parse(SerializedValue);
        JSONObject obj = new JSONObject();

        switch (type)
        {
            case EBlackBoardKeyType.Int:

                int intValue = string.IsNullOrEmpty(SerializedValue) ? 0 : objSaved["Value"].AsInt;
                int Result = EditorGUI.IntField(fieldRect, intValue);

                obj.Add("Value", Result);
                Board.KeyArray[Index].SerializedValue = obj.ToString();

                break;

              // Put other variable types here
      }
}

for the custom editor I used a Reorderable list you can check this blog out.

So here is the final result:

I had fun making this since it is the first time I created a custom editor for anything lol. Spent couple of hours trying to study and making it. the UX for my blackboard is still kinda rough but it works and I’m happy with it. :smiley:

Hello,
Not in Unity itself but pure c# coding you can achieve something similar, they are called Generic classes here is a link to a tutotirla https://www.tutorialsteacher.com/csharp/csharp-generics

The use would be something like this

first create the generic class

class DataStore<T>
{
    private T[] _data = new T[10];
    
    public void AddOrUpdate(int index, T item)
    {
        if(index >= 0 && index < 10)
            _data[index] = item;
    }

    public T GetData(int index)
    {
        if(index >= 0 && index < 10)
            return _data[index];
        else 
            return default(T);
    }
}

now you can use different vairables type like

DataStore<string> cities = new DataStore<string>();
cities.AddOrUpdate(0, "Mumbai");
cities.AddOrUpdate(1, "Chicago");
cities.AddOrUpdate(2, "London");

DataStore<int> empIds = new DataStore<int>();
empIds.AddOrUpdate(0, 50);
empIds.AddOrUpdate(1, 65);
empIds.AddOrUpdate(2, 89);

Unfortunately there is no Wildcard in C# but the solution that you presented is the way to go (I would say). BehaviourTree asset is a node-base AI tool that is very similar to the Blackboard from unreal and you should really check out their approach Creating Shared Variables - Opsive. I hope this will help you

Are you looking for this?