-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interrupting flow #6
Comments
I see what you mean. I will definitely work on making this possible, maybe with an event driven approach as it's done in Unreal. Allowing abortion will require some design changes so it may take a bit longer than other smaller improvements I have planned. Obviously there are a few extra steps to this solution: because it won't abort the previous sequence, you may have overlapping behavior. So it depends on how things are on your end, but if you are just waiting you can put another condition after the wait is completed to check if you are still in, say, 'wandering state' and return fail() if you are not, so the sequence doesn't continue. Another thing is putting a while loop inside your decorator and keep ticking as long as 'wandering' is true. So ultimately, you have a lot of control over how you design it: my suggestion is to prefer short, repeated actions rather than tasks that take very long to complete. This is the way I see a behavior tree should be designed, but what you suggested is definitely something that other implementations have and that should be possible for the user to do. Also keep in mind that using the Behavior Tree like this makes it kinda like a state machine. So if you wanna design things in that way, a state machine is probably more suitable (I recommend https://gitlab.com/atnb/xsm) |
Yeah, trying parallel nodes, I was able to develop some AI which addressed my problem reasonably well. I think taking your advice of thinking about behaviour trees less in the terms of finte state machines helps too. I am fairly new to them. That said, I still think there's value in the Unreal-style approach of branch aborting, especially as trees start to balloon in complexity. |
Good :) Parallels are the "worst" in terms of performance so, if you can, think of other ways. |
Thanks for your great addons! I have being using it for a couple of weeks, and still looking forward to more future updates. |
It's amazing to see this! I'm glad my addon turned out useful and I'm excited to see what you've done with it. (By the way, this is not really an issue nor it is related to the issue above, so next time open a new discussion instead) |
This issue will be addressed in the 1.2.rc4 version. |
Nice! |
I have started updating the 1.2.rc4 branch. There are some changes already, although the features is not there yet. However, I made a much more complex example to show how to achieve some of the behaviors you people were talking about! That shows how the tree can be made responsive and flexible. I think that even without a "interrupt flow" function this is getting the job done nicely and encapsulates very complex logic with just a few nodes. |
Hello, weighing in on this quite late - just here to say that I've had some success implementing this locally without too much refactoring, and I wanted to share my approach in case it is useful toward the official implementation (or to others finding this thread). In bt_node.gd (unrelated sections elided): signal completed(result)
const ABORTED = -1;
func abort():
fail()
complete(ABORTED)
func complete(value):
if running():
return
emit_signal("completed", value)
func tick(agent: Node, blackboard: Blackboard) -> bool:
# .... etc ...
if result is GDScriptFunctionState:
assert(running(), "BTNode execution was suspended but it's not running. Did you succeed() or fail() before yield?")
result.connect("completed", self, "complete")
result = yield(self, "completed")
if result is int and result == ABORTED:
return and then in BehaviourTree: # halt the behaviour tree
func interrupt() -> void:
bt_root.propagate_call("abort")
# halt the behaviour tree and restart it
# (useful for scenarios where an agent is surprised, eg taking damage, enemy arrives in range etc)
func hard_restart() -> void:
interrupt()
is_active = true
start() The central change there is that the Of course there are some downsides to this approach - the function that the node was waiting on will still continue its execution uninterrupted, which might have strange side effects. This won't come up if nodes are designed to only do one thing (like, a node whose job is to wait and then execute a side effect should probably be split up into a waiter and an executor node) but perhaps this is too big of a tripping hazard to include without further safeguards. I also don't know how performant it is; my project only includes a handful of actors so it might have additional problems when dozens/hundreds of agents are in the scene. Thanks @GabrieleTorini for the great module - it's so useful and extensible, it's been a great help to my hobby projects. I hope this is useful to you! |
Thanks! This is definitely a great addition. I'm glad you're happy with the plugin. It was a big experiment, and thinking back I think it could be done in an entirely different way, but as long as it's stable and gets you to make your AI, I'm satisfied! |
Hey there, I'm using this piece of code for hard restarting the bt but it doesn't work for me. At least it doesn't work when the current leaf is under RepeatUntil. Have you checked it with RepeatUntil too ? |
This may already be covered, but the current implementation doesn't provide any obvious solution on how to do this. If you an AI agent perform a sequence using things like wait timers or other yields, there doesn't seem to be any way to get them to re-evaluate from a higher level node based on external stimuli. An example might be an AI who simply wanders around, but if they get attacked, you would want their wander sequence interrupted and may instead go into an attack sequence.
The text was updated successfully, but these errors were encountered: