Forums › 💬 NodeCanvas › 🗨️ General Discussion › Feature Request: Variable popups in scripts
I know I’m asking a lot, but it would be really superb if Blackboard variable could be used in custom scripts in a way I can add and edit them using inspector. I quickly created a simple implementation that works for basic types of variables, but it’d be better if I could use Variable class (or something similar) to support all types of variables.
[attachment file=”ncvariable_example.png”]
Hey,
This is a good suggestion, but the problem to making this in a way to support all types (like BBParameter does), is actually the fact that Unity can’t serialize generics in the first place.
So one solution to make this work, would be to allow such linked parameters (BBParameters) only in a special MonoBehaviour derived base class, that also handles the serialization and deserialization (with ISerializationCallbackReceiver), as well as proper initialization of those parameters in Awake and Validate.
I presume that the goal here is to be able to use some kind of a special variable in the monobehaviour, that shows up in the inspector so that it can also be linked to a variable of provided blackboard?
May I also ask how you ended implementing your version of this?
Cheers!
Yes exactly that’s what I meant.
I needed something simple and fast for my game so I quickly created this simple classes:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[Serializable] public class NCVariable { public string Name; public string FieldName; public int IntValue; public float FloatValue; public bool BoolValue; public string StringValue; public Vector3 VectorValue; } [Serializable] public class NCVariableArray { public Blackboard Board; public List<NCVariable> Variables = new List<NCVariable>(); } |
and then added editor for it:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
[CustomPropertyDrawer(typeof(NCVariableArray))] public class NCVariableArrayEditor : PropertyDrawer { private const string BLACKBOARD = "Board", VARIABLES = "Variables"; private string[] _variableNames; private Dictionary<NCVariable, int> _selected = new Dictionary<NCVariable, int>(); private NCVariableArray _target; private ReorderableList _list; private ReorderableList GetList(SerializedProperty property) { if (_target == null || _target.Board == null) return null; _variableNames = _target.Board.GetVariableNames(); return _list ?? (_list = new ReorderableList(property.serializedObject, property, true, true, true, true) { drawElementCallback = (rect, index, active, focused) => { var element = _list.serializedProperty.GetArrayElementAtIndex(index); rect.y += 2; rect.height -= 4; var variable = _target.Variables[index]; var position = new Rect(rect.x, rect.y, rect.width / 3 - 5, rect.height); if (!_selected.ContainsKey(variable)) { _selected.Add(variable, 0); var selected = _variableNames.Select((v, i) => new {Var = v, Index = i}) .FirstOrDefault(v => v.Var == variable.Name); if (selected != null) _selected[variable] = selected.Index; } _selected[variable] = EditorGUI.Popup(position, _selected[variable], _variableNames); variable.Name = _variableNames[_selected[variable]]; position = new Rect(rect.x + rect.width / 3, rect.y, 2 * rect.width / 3, rect.height); var targetVar = _target.Board.GetVariable(_target.Variables[index].Name); var value = variable.GetType().GetFields().LastOrDefault(f => f.FieldType == targetVar.varType); if (value == null) { EditorGUI.HelpBox(position, "Variable type not supported", MessageType.Warning); return; } variable.FieldName = value.Name; var valueProperty = element.FindPropertyRelative(value.Name); EditorGUI.PropertyField(position, valueProperty, GUIContent.none); }, drawHeaderCallback = rect => { EditorGUI.LabelField(rect, "Variables"); }, }); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { var list = GetList(property.FindPropertyRelative(VARIABLES)); var height = list == null ? .0f : list.GetHeight(); return height + EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (_target == null) { _target = fieldInfo.GetValue(property.serializedObject.targetObject) as NCVariableArray; if (_target == null) return; } EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), property.FindPropertyRelative(BLACKBOARD)); if (_target.Board == null) return; position.y += EditorGUIUtility.singleLineHeight; var list = GetList(property.FindPropertyRelative(VARIABLES)); if (list == null) return; _list.DoList(position); } } |
Maybe it’s not practical (I’m storing additional variables that aren’t needed and only take memory, and I only support only few types), but for my purposes it suffice. Maybe if I have time to implement something more sophisticated I’ll try to cram all fields into one ‘object’ field and serialize it.
Also I love that you have ‘varType’ field. So cool 😀
Thanks, and cheers!
Thanks for the following up and letting me know on how you did it!
I will dig this up a bit more and hopefully find a good solution. I can see how it can be a generally useful “feature”. 🙂
