NodeCanvas Forums › General Discussion › Feature Request: Variable popups in scripts
Tagged: Variable Blackboard Script
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.
Hey,
This is a good suggestion, but the problem to making this in a way to support all types (like BBParameter
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!
Join us on Discord: https://discord.gg/97q2Rjh
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”. 🙂
Join us on Discord: https://discord.gg/97q2Rjh