Hi there!
Is there a way to assign mapped variables programatically? I have a large amount (~50), and also want to interchange behavior trees.
I feel like there might be a smarter way to do it, as creating and mapping shared variables is somewhat cumbersome. But I can't figure one out. The main one I tried was making a Flag task, with an enum value. So I didn't need to keep making and mapping variables in the BD Editor, I'd just make a new enum value and could check it. However this had its own set of problems. So, I am hoping I can programatically assign the mapped variables myself, and at least can partially automate it?
Edit: A little digging and I figured out the below. It seems to be working fine, is there any issues I'm overlooking?
Edit 2: So a follow up question, is it possible to create SharedVariables programatically? I had the thought that I could use Attributes to tag properties in my class, and then when I press a button in the Editor, clear the BehaviorTree's SharedVariables and recreate them from my Attributes? Though this could possibly be problematic for Tasks in the tree, which might be references?
Edit 3: I've made some progress, but I believe I'm now blocked by private fields (and a possible misunderstanding of Behavior Designer). Here's the code I've got so far:
It seems to work up to a point: the inspector updates with the new shared variables. However it eventually reverts to what has been serialized. So, two questions: Is there a way to force reserialization, and secondly: Is this even going to work with trees already referencing existing shared variables?
Is there a way to assign mapped variables programatically? I have a large amount (~50), and also want to interchange behavior trees.
I feel like there might be a smarter way to do it, as creating and mapping shared variables is somewhat cumbersome. But I can't figure one out. The main one I tried was making a Flag task, with an enum value. So I didn't need to keep making and mapping variables in the BD Editor, I'd just make a new enum value and could check it. However this had its own set of problems. So, I am hoping I can programatically assign the mapped variables myself, and at least can partially automate it?
Edit: A little digging and I figured out the below. It seems to be working fine, is there any issues I'm overlooking?
C#:
void MapAllBehaviorTreeSharedVariables() {
Type type = GetType();
string propertyFormat = type.FullName + "/{0}";
foreach (BehaviorTree behaviorTree in GetComponents<BehaviorTree>()) {
List<SharedVariable> variables = behaviorTree.GetAllVariables();
foreach (SharedVariable variable in variables) {
if (type.GetProperty(variable.Name) == null) { continue; }
variable.PropertyMapping = string.Format(propertyFormat, variable.Name);
variable.PropertyMappingOwner = gameObject;
}
}
}
Edit 2: So a follow up question, is it possible to create SharedVariables programatically? I had the thought that I could use Attributes to tag properties in my class, and then when I press a button in the Editor, clear the BehaviorTree's SharedVariables and recreate them from my Attributes? Though this could possibly be problematic for Tasks in the tree, which might be references?
Edit 3: I've made some progress, but I believe I'm now blocked by private fields (and a possible misunderstanding of Behavior Designer). Here's the code I've got so far:
C#:
[AttributeUsage(AttributeTargets.Property)]
public class MappedPropertyAttribute : Attribute {
public readonly Type Type;
public MappedPropertyAttribute(Type type) {
Type = type;
}
}
void UpdateBehaviorTreeMappedProperties() {
Type type = GetType();
PropertyInfo[] properties = type.GetProperties();
string propertyFormat = type.FullName + "/{0}";
List<SharedVariable> variables = BehaviorTree.GetAllVariables();
variables.Clear();
foreach (PropertyInfo property in properties) {
object[] attributes = property.GetCustomAttributes(typeof(MappedPropertyAttribute), false);
foreach (MappedPropertyAttribute attribute in attributes) {
SharedVariable mappedProperty = (SharedVariable)Activator.CreateInstance(attribute.Type);
mappedProperty.IsShared = true;
mappedProperty.IsGlobal = false;
mappedProperty.IsDynamic = false;
mappedProperty.Name = property.Name;
mappedProperty.PropertyMapping = string.Format(propertyFormat, property.Name);
mappedProperty.PropertyMappingOwner = gameObject;
variables.Add(mappedProperty);
}
}
BehaviorTree.GetBehaviorSource().SetAllVariables(variables);
}
It seems to work up to a point: the inspector updates with the new shared variables. However it eventually reverts to what has been serialized. So, two questions: Is there a way to force reserialization, and secondly: Is this even going to work with trees already referencing existing shared variables?
Last edited: