NodeCanvas Forums › Support › Passing variables to dynamic subtrees
Hi!
I’m trying to recreate a flow described here
But I’m lost on a step earlier. I’m able to store a tree in a BBParameter, run it in subtree node, but I’m a bit confused about passing variables into it’s blackboard. I tried storing parameters in the parent blackboard, hoping that they are going to be copied into the child, but that didn’t happened. I Tried using both dynamic variables and exposed public. I’ve event tried pulling out variables straight from parent, but still no dice. In the IGraphAssignableExtensions at line 34, I’ve found a comment, which left me wondering:
//we always start with the current graphs blackboard parent bb as the subgraphs parent bb
Why is this the case, when immediate parent is *this* graph, not it’s parent?
Hello there,
When using subtrees based on a variable like-so, please note that local graph variable mapping is not really possible if the subtree variable is unknown or changed in runtime. However, the GameObject Blackboard Variables (the Blackboard attached on the gameobject) is propagated down the sub-trees as normal. This GameObject Blackboard is common among all graphs and subgraphs and it’s variables can be used by all of those graphs, whereas the local graph variables can only be used by its own graph instead.
Please let me know if that answers your question (which I may have misunderstood).
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
Passing the value via GameObject blackboard still isn’t the solution I’m looking for, as it doesn’t allow me to crate behaviour trees docoupled from particular blackboard. I’ve managed to achieve something close to what I want by creating my own SubTree node, which searches the subgraph for variables denoted with “$” at the beginning and filling them with values from this level blackboard or special “VariableProvider”. The problem I have with this solution is that it stays completely parallel to the built-in subtree implementation, thus is liable to desynchronization with the base code after an NodeCanvas update. With some minor refactoring on your side it would be possible to inherit from SubTree and override some virtual methods. Please find my code attached.
Hello again,
I do understand and agree in what you mean by saying that ideally the subtree should be completely decoupled from the root tree and in case where no dynamic subtrees are used this can be the case indeed using the variables mapping feature/GUI, but dynamic subtrees based on a variable impose a challenge. Mapping is such a case can possibly only be done via name/type matching of variables (which can of course be prone to error if a variable is renamed as opposed to normal variables mapping where match is done by ID instead of name). As far as I can tell, name matching is also what you have done here? I would be interested to know what IDynamicSubtreeProvider and IDynamicSubtreeVariablesProvider do more specifically by the way.
With that said, I could probably come up with and add a different mapping GUI approach (based on variable name matching) in SubTree inspector in place of the existing one, specifically when the subtree is dynamic. This way we could have the exiting variables mapping method for when the subtree is a constant assignment and a different mapping method for when subtree is dynamic. Let me know what you think.
Finally, regarding refactoring with virtual methods, no problem in doing that. Which methods do you need made virtual more specifically? Also, your DynamicSubTree class which inherits from BTNodeNested will work fine when you upgrade to a newer version for example, or is it that you would prefer inheriting directly from SubTree class instead?
Let me know.
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
Oh, it is great to hear all of that! IDynamicSubtreeProvider
and IDynamicSubtreeVariablesProvider
are just interfaces for accessing appropriate subtree asset and variable mapping. Subtree provider returns just BehaviourTree
and variable provider a mapping of string to object. It isn’t doing any fancy extraction of variables from the tree and for now is hard-coded. I do agree, that it imposes a risk of messing up when variable name changes, but I guess there is nothing to be done about that, or is there?
My case is a patrol path with various types of point of interest connected to the path node. After arriving at the node, an AI extracts them and saves those objects (SubtreeProvider and VariableProvider, which are the same object in this case) to bb variables and executes subtrees attached to them with provided variables passed down. At the moment there is just looking in some direction with possibility of some other things like interacting with environment. See the code attached.
About inheritance I was thinking about inheriting directly from SubTree and it would just require one new method to pass the variables (example also attached).
Finally the idea of adding dynamic variable mapping sounds also great, it would be possible to just store the variables in immediate parent just before running the subtree and deleting them just after.
Hello again and thanks for the follow up 🙂
I will definitely take a look at an alternative way for dynamic variables mapping. I think it is still worth it even if it is only done by name instead of ID. You can derive from SubTree directly if you want, or you can derive from BTNodeNested<BehaviourTree>
like you’ve already done in your DynamicSubTree. Implementing a custom sub-graph node (thus deriving from BTNodeNested<T>) is generally speaking easy to do with a few lines of code (depends on what you want to achieve of course). Please let me know if there is anything I can do for the next version to help you in that, apart of course from “dynamic variables mapping” which I will take a look at that possibility anyway 🙂
Thanks.
Join us on Discord: https://discord.gg/97q2Rjh
I’m really looking forward to it!
Yeah, it is easy, but what bothers me is the required copy-pasting of the SubTree
, not actually reusing it’s functionality. Even if I inherited from it directly it would require me to copy-paste the entire OnExecute
method to inject my code in a particular place.