I’ve created a behavior tree with a “Selector” node and added a Behavior Tree Service (BTS) with a tick interval of 0.5 seconds. The selector logic selects an enum state based on some game logic criteria and then I use a bunch of task nodes below. The problem is that on the very first iteration, the selector node and the behavior tree service never get run unless there is a “wait” node within the child tree. What’s happening is that the initial blackboard value is set to ‘none’ and there is no appropriate selectors for it, so the tree gets stuck and the BTS never gets ticked. I think it only fires a tick when an internal counter reaches 0.5 seconds and it starts at 0.0 seconds. The internal counter increments from 0.0, but since the child tree can’t be evaluated, the counter never actually increments and the BTS gets stuck. The ‘fix’ is to put a wait 1 second node at the end of the tree… but this is a bad work around. The BTS should tick even if none of its children succeed or can be evaluated.
You could initialize your blackboard value before you run your behavior tree, or alternatively you could wait until your blackboard value is set before calling run.
A null pointer or uninitialized value can be annoying, I definitely agree that it shouldn’t crash the script, but it also helps point to a design pattern consideration. One of the two methods I mentioned might be more graceful for your implementation than a benign wait.
I don’t believe this is a bug, though I may be misunderstanding your setup and the result from it. If you run a Service before the key is set, as Breyarte explains in his workflow below, I would expect the Selector to to fail.
As I said, I may not understand fully what you’re describing, however. If you can post some images of your BT and BTS graphs, as well as any other pertinent graphs from Tasks or Decorators below, I can run through it and see if this is expected or if there’s a bug in there. Thanks!
Here’s the behavior tree with the problem.
Just a heads up: I will be running a booth at SEA-VR 2015 for the next day and a half, so I won’t be able to respond to any queries until Thursday.
So what happens if you exclude the Wait? Have you paused and stepped backwards through this during PIE? It seems possible it’s running through everything and simply failing because it the AttackMode key is not set yet, and you don’t have a default, no-value condition to tell it to do anything else. If that’s the case, that’s expected. Or are you seeing something different?
If I exclude the wait, the service never ticks. The service is supposed to switch the enum value within the blackboard from “none” to a valid one, and then the tree selects the right branch based on the blackboard condition.
It just occurred to me that perhaps the order of execution in each node is determined by the order of the node elements. The service is below the selector, so it gets executed after the selector is processed. Maybe the problem was more of a lack of intuitive understanding on my part instead of a bug?
Can I see the inside of your Service? It’s difficult for me to follow what you’re saying without that info. The Service should fire when the node it’s on is reached, regardless of what’s below it.
It might be helpful if you can put this into a small test project and upload it somewhere for me so I can take a look. Let me know if you’re able to do that for me.
Incidentally, it is dangerous to not include something that can succeed as the last option in a Selector chain. Without a success, the Selector will continue trying each of its nodes indefinitely, and in a circumstance where each will only succeed if a value is set to something other than Null, you can enter a loop that won’t exit in circumstances such as this. I don’t believe that’s the problem here, just mentioning it =)
These are the areas of the behavior tree service I took screenshots from
Try running this setup both on Event Receive Tick and Event Receive Activation:
I’ll double check, but Event Receive Tick probably isn’t going to fire as soon as the Service is hit. It’s probably waiting for the next available Tick.
If that doesn’t resolve the issue, please create a small test project and upload it somewhere, and get me a download link so I can see what’s happening in full. Thanks!
Alright, this is weird. I had to upgrade my engine from 4.9.1 to 4.9.2 and then I created an empty project and recreated what I thought would reproduce this bug – except I’m unable to reproduce it. I tried replicating the project and problem in 4.9.1 but that also worked as expected. Maybe it’s project specific? Then I migrated the repro BT into my main project and that worked as well. Not project specific. Maybe it’s BT specific? It is. I was able to trace it down to one thing and reproduce it:
If a sequence node feeds into the selector node, and the selector node has a BTS, then the selector node will not execute the service – unless you place a ‘wait’ node in the child tree.
I’ve created the necessary blueprints and assets to replicate this issue and added it to the zip file. This can be extracted into a content folder within a third person template project. When you open the behavior tree, you can see the issue.
Everything you’re showing me is acting as expected. So 3 things:
- You’re using a Sequence > Selector combo off your Root. This is a bit unusual. While this can work, without any safety checks or default responses, it can lead to the entire BT failing. If every child of the Selector fails, the Selector fails and progression moves back up to the Sequence. Then, because the Sequence’s child failed, the Sequence fails back up to the Root. None of this will fire again. If you instead use a Selector with the Service off the Root, and 4 Sequences (each running the desired Task), you’ll have a safer method because it will continue attempting to run the Sequences.
- Your Service isn’t set to call Tick when it is activated. Adjust this and your setup will work (though I would still recommend adding more default checks and adjusting your Selector and Sequence order)
- Your Selector is set to fail in any case in which AttackMode is not set to one of those 4 values. This is avoided by adding the Wait node as you noted, but a different option (that wouldn’t require any sort of waiting) would be to have a fifth option that fires when AttackMode Is Equal To None.
Hope that helps! Looks like this isn’t a bug but an order of operations and sequence of BT nodes problem. Let me know if I’m missing anything to think otherwise. Thanks!
Ah, thanks for the help! I didn’t know about that hidden checkbox. Checking that fixes the problem.
The attachment I sent is not my whole BT, it was a section which was about four layers deep and was just the bare essentials to demonstrate the problem I was getting. In practice, I have a bunch of tasks before and after the selector. But I’ll take your notes to heart and re-examine my BT structure to make sure it makes sense.
This was the fix
The “none” value is more of an exception catching value, so if something failed to set the attack mode value in the blackboard, I’d like to know so I can fix my code / blueprints.
Anyways, thank you again for the assistance! I still have a lot to learn about behavior trees