Behavior Tree Service and Task Tick Inconsistency

I’m about to lose my mind :sob:

I’m using a service on a sequence node in my behavior tree, and the sequence is currently only connected to a single task in the debugging process. In my service, I’m constantly checking something and turning a bool type variable to true using a blackboard key. In my task, I’m constantly checking if that blackboard key’s value is true and if so, I’ll move on with another algorithm. But in that algorithm, the bot’s exact location when that bool type variable turns to true is important. So before I start implementing my next algorithm, I decided to check if there were a delay between the task detecting the vriable’s value change in my service and the detection of the value change in my task. There were indeed a short delay, so I wrote this code below:

(This code is a simplified version of the real thing, only the crucial aspects are included for it to fit in the screen. In the function named “Func”, I get the bot’s current location and I store it inside the variable named “Result”. The outcome is the same whether it’s inside a function or not. The branch node’s condition is set to a blackboard key which represents that bool type variable I mentioned on the bottom left.)

This almost solves the issue. When I draw spheres after the actual value change in my service and after the detection in my task, they match up exactly!.. most of the time :sweat_smile: Sometimes, not randomly, just in certain locations for some reason, the spheres are not drawn in the same place. (might be due to the bot’s velocity when it’s passing through certain locations) And interestingly, the inconsistency between the spheres’s locations increase when I adjust the time value of the timer either up or down. Maybe it’s because I use the same timer code for detecting when should that bool type variable should change it’s value, the timer in my service is also set to 0.01 seconds. Is there a resonance going on? :rofl:

Additionally, the inconsistency is even more intense if I handle the checking of the bool type variable’s value change via the behavior tree, by using a parallel composite. In that case, even using the code I’ve provided is no use.

Can it be possible to detect a blackboard key’s value change instantly? Am I overcomplicating something here? I hope I can get your help on my struggle fellas, so much thanks in advance! :smiling_face_with_three_hearts:

Hi!
Just out of curiosity, what happens when you set the Set Timer By Event Time to 0.02, set Max Once Per Frame to True, and save the Handle as a variable instead of connecting it directly to the Clear And Invalidate Timer function?

1 Like

I just wanned to leave this post as it is instead of editing my new findings over it to show my thinking process. Please don’t bother reading this to get more info on my issue, as they are included in the next post.


Unfortunately, no :cry: I’ve tried changing that setting and the value accordingly for the both timers, and one at each time. Seems like ticking that checkbox didn’t affect the outcome. But thanks to your suggestion, I actually discovered something very interesting.

Forget the paragraph below in square brackets :smiley: it’s just random. Random in… the outcome is the same for a given location for each value, it’s not related to time, but for each unique value, some certain locations are messed up. It’s like a seed. (lower ones are more consistent though, the most consistent value which gives the precise result that I want most of the time is 0.1, after 0.1, no matter how much I lower it, it doesn’t seem like there’s any difference)

[For the outcome to be more consistent, the time value of the timer in my task needs to be a multiply of the time value of the timer in my service. Even if I adjust the value in my task 0.001 either up or down, the result gets severely more inconsistent. But when I set it to 0.02 or 0.04, it does give the exact location of the bot when the bool type variable changes it’s value most of the time. For that reason, I’ve also tried setting the value in my service to something very small like 0.0001 and the results still seems to be the same if my observations are correct. After I change that value, I can set the value in my task to be the same, two or four times the amount of the value in my service. And the outcome is precise most of the time, but the consistency is the same.]

As for the handle, it doesn’t really affect much, can even not be included for this specific debugging process as what I was observing was the result of the function before that which gets triggered only once. (there’s also no funny business going on inside the function, there could also be the plain get actor location node in it’s place)

This thing confuses me a lot, and it’s obviously much harder to have a comment with only these info. But after further investigation, I just wasn’t able to gather more clues. Super intriguing :thinking:

:neutral_face: :expressionless: :neutral_face:

Sorry for so many edits, but I just wanned to tell something very funny that just happened. I think my eyes got damaged due to trying to figure this out for the entire day. I thought I saw it working when I set the value of the timer in my service to 0.001 and kept the one in my task at 0.01. Because it’s hilarious to me to think that my task detecting when exactly does a variable in my service changes it’s value like that, when it doesn’t if I set the one in my task to 0.001. Can you imagine? :rofl: Except for… that was actually the reality. :cowboy_hat_face: Now if you excuse me, I’m heading towards the nearest window :upside_down_face:

Upon inspecting more closely, I noticed my last attempt also wasn’t successful sometimes, even though rarely. Due to how obsurd it was, I already knew that my previous post wasn’t a solution. I think I’m unable to interpret my observations correctly, they don’t make any sense to me. Please let me explain my issue with my latest findings along with some visualizations, and hopefully I can get some explanations from you fellas if possible.

I constantly check a variable’s value in a task inside my AI behavior tree that changes it’s value in a service that runs on a sequence composite which only has a single task under it. The variable is stored in a blackboard key. My objective is to be able to perform the check in my task precisely, so that I can run the next algorithm the moment it changes it’s value in my service.

But there is a delay between my instance setting the new value of the variable and my task detecting it using a branch node. This is always the case when I simply use a plain branch node and call it continuously in my task, so I wrote the code I’ve provided in my original post. And I also use the same code with just different variables to detect when to change the value of the said variable in my service. When I set the time value of the timer in my task to 0.01 and the one in my service to 0.001, my task is almost always able to respond the moment the condition is met which’s dependent on the code in my service. Here’s a visualization of the precise outcome:

instance 1

The white sphere on the bottom is drawn right after that variable gets set to it’s new value in my service, and the red sphere on the top is drawn right after the branch node’s true output pin is executed in my task. When I do it the way I’ve explained above, this works most of the time. But sometimes those two spheres don’t get drawn in the same place. Here’s what I mean:

instance 2

(The bot was running from right to left in this instance)

This is not random, just in certain locations. You see, these spheres actually represent the location of the moving AI. And after my tests where I made the AI head to different directions, I observed that the spheres always misalign in the same locations. While in the locations my task handles the detection precisely, it always draws the spheres right on top of each other, no matter when I trigger the bot’s movement. There’s something very interesting to note here though, when I insert different values into my timers in my task and service, the results change. When I change the values in my task or service, the locations it messes up change like a seed. And the higher the values get, the frequency of the misaligned outcomes increase along with the misalignment intensity.

Additionally, the results are never accurate when I hande the detection via the behavior tree by using a parallel composite and a decorator, even if I implement my code on top of that.

I truly have no idea what’s going on :sob: I think using that code I’ve shown isn’t ideal either, since it will definetly cause severe lag when multiple bots try to run the same thing at the same time. There must be another way, a right way to achieve this. I hope you fellas can be able to help me in this case. :smiling_face_with_tear:

hi,

there might be some gaps between the service detection and the task.

the service gets to know the variable first.

Meanwhile the task is not able to know it,due to the timer (0.01 second to receive information)

and even if the timer gets set to 0 interval.it only increase the confusion.

if the information is important when a Boolean changed.

I wouldn’t consider a timer.

“Frame”should be base unit to consider.

I’ll figure a way to make sure they happen in a single frame.

like integrate the two tasks into a single one task or service,and use a decorator to check the Boolean…

1 Like

So sorry for the late response, I was just able to get back on my PC. And thanks a lot for the suggestion! :smiling_face_with_three_hearts:

The reason I’m using a service and a task for this is because the only approach I could come up with to make the AI not stop for a split second when it’s given a new destination while it’s already moving, is triggering the move to location node continuously (when I give the input to begin) in my service, and plugging a blackboard key into it’s dest pin. That blackboard key holds a vector type variable that’s value is determined in my task. This way, the moment a new destination is set in my task, the AI changes it’s direction right away! (also the stop on overlap option should be unchecked) I couldn’t find a way to make this happen inside my task as tasks need a finish execute node to be triggered again.

About setting frames to be the base unit, I couldn’t make that code of mine work with the delay until next tick node. I also can’t achieve that using timers (which you already don’t suggest me using), since decreasing the time value of the timer even lower causes severe lag.

I’m so stuck rn :melting_face:

I wanned to add one more thing. Remember when I said I also have the same code in my service just with different parameters that I use to detect when should that variable change it’s value? It also can miss where exactly it should set that variable to true randomly. And sometimes doesn’t even clear the timer even though the node executes :slightly_smiling_face: I though I could handle my loops using timers but apparently they’re not the way to go in this case, right?

1 Like

I took a thinking for sometime .
it also seems to damaged me for a certain amount…

eventually I have this out-come:
get rid of the service,
when begin the movement task.also bind an event dispatcher to the one who’s going to change variables.
and when it changed its variable also have it to fire the dispatcher.

So whenever the dispatcher triggered,it can run the Ai move to in the task agin.

this is what I had in mind,not tested…

1 Like

Yes! Using an event dispatcher and calling it once I have a new destination set does also result in a smooth rotation for the AI :smiling_face_with_three_hearts: Thanks a lot!

About the other code I had in my service, which was the code to determine when should that variable be set to true, at first I couldn’t make it work in my task no matter how hard I tried. In that code, I had a multi line trace node, and I used a for each loop node after it to evaluate each trace’s elements. But the execution flow refused to get past that for loop! BUT I managed to pull it off like this :sunglasses:


(Oh btw this is a simplified version of my code. Inside the function named “Func”, we can imagine as if the new destination gets set by overriding the vector type variable named “Dest”)

Though the thing is, even though this way the AI changes it’s direction exactly when my desired condition is met, sometimes it can miss completely due to the traces not being casted constantly. You see, when I make the traces visible, I see them flickering, which makes sense because this whole thing runs inside a task that naturally can’t be iterated instantly when it’s done. For that reason, I attempted that timer approach but like I said, I couldn’t move the execution past the for each loop node :smiling_face_with_tear:

I think I’m so close getting this done, thanks to you guys! Could it be possible to achieve my goal on making that multi line trace continuous inside my task?

Wait… why don’t I just… apply a timer to this one? Without the for each loop node :no_mouth: I just randomly got this idea in the middle of my sleep :rofl: I’ll try this tomorrow and update. Though please warn me if there’s a more ideal way of doing this :blush: Thanks again for all the help fellas, and thanks in advance!

1 Like

Sorry for the delay once again, I’ve implemented my last attempt the first time I got to launch my PC again. Unfortunately, it was unsuccessfull :cry: though I’m kinda glad it didn’t work because using timers for different bots at the same time would cause performance issues.

Thanks to you, I was able to eliminate the issue about communication delay between my service and task by having the whole code inside my task. But now, due to my new code which doesn’t allow me to use timers for a successful outcome, the multi line trace doesn’t get cast continuously, in fact there’s so much delay between two executions that it is even possible to see the visualized trace flickering.

I’m still stuck on this part. I hope my objective is actually something doable. Please let me know if you or any other fellas have any ideas, or we can mindstorm together if you’d like to! I would love to try you guys’s suggestions, even if you’re not sure about it. Thanks in advance! :smiling_face_with_three_hearts:

1 Like

yep I would love to.
but only looking at the code and description of the code is hard for me to build a picture in mind.

may you share what the line trace represents(is it eyes or…), and what the whole system actually do?

is there another game that’s similar?etc…

1 Like

Heyy! I took some time testing to make sure everything works correctly. Because… I actually made it work! I realized that I actually didn’t need a multi line trace for this task so you were right about that I just needed to have the whole code inside my task to avoid the communication delay between my service and task.

Here’s the simplified code I replaced with the second half of my previous code:

And this is the result :blush:

You see, I continuously cast a line trace between the player and the AI, and when that representational function named “Func” is triggered, the vector type variable named “Dest” in the first half of the code (which is the same except for that #1 pin of the first switch on int node is connected to this new section I included in this post) gets set to a new value and I call the event that fires the move to node.

Also this way the timer doesn’t cause any lag if I set it’s time value to a very low number! But still, I would love to learn if there’s a more ideal way of achieving my objective. Which was making the AI execute a function the moment that line trace hits something. Again, thank you so much! :smiling_face_with_three_hearts:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.