I’ll admit that I am not surefooted when it comes to casting but I can’t seem to make event dispatchers work between many AI Third Party Characters. Right now I am only working with one but the plan is:
Have a bunch of AI Third Party Characters each running the same behavior tree.
When the behavior tree executes a specific task, have it communicate this to all other AI Third Party Characters.
Have all the other AI Third Party Characters evaluate if the sender is within a certain distance and line of sight and then do something!
Here is the snippet from my AI Third Party Controller:
Not sure if that can be done. Also biggest reason to have AI, behavior trees and blackboards is performance when you get 100+ characters like that.
So it may be impossible, or rather (quite common in unreal) you are fighting against design of engine.
At some point I gave up on fighting all those references up and down (like AI, umg, animation trees etc.)
And for every group of blueprints\actors i made single messaging system.
Quite simple:
there is dispatcher in easily referenced blueprint like game mode,
and there is event that fires that dispatcher also in game mode
every actor that want to send message calls that event in game mode
everybody that needs such info hooks into dispatcher
Dispatcher and event are simple, they pass over only 2 values:
who called it
and what is message.
ofc. i Format messages so they are easily readable by other scripts, for that i create enumerators, but when they passed over i change them to string and back to enum.
Easier to avoid silly spelling errors.
@Nawrot it makes sense to push it out to the game mode and I’ll try that first. After struggling more, I think I confirmedthat you CAN’T do it in the BT and BB for the reason you suggested, namely that the nodes are shared objects between all objects. Appreciate it!
Drix AIBK uses a messaging system that uses the AI hearing sense which is a good hack but I’d rather the messaging be implicit.
The other way I think is to have the DT change a key in the BB, then have the AI Controller detect that change and then call the event… but that also seems like a work around whereas the DT ought to be the origination of the call. Also as a newbie, I am not too sure how to detect a BB value change.
I ended up using the dispatchers in the game mode exclusively to solve my issue and it works fine. I’ve also learned the hard way (aka, had to redo a ton of casts) the need to modularize everything so that my components can be slapped onto whatever actor I need. Thanks @Nawrot
Now I’m new to BTs myself and am still figuring them out. But it sounds like Tasks (in blueprint) are instanced.
And I’m using an Initializing Task to bind to input that the user gives to the character. Such as Move to, attack, stop etc.
Another thing you can do is to use a component that acts as a mediator between the BT and everything else. So the first thing the BT does is to set up a reference to the mediator and set it as a BB value. So now you can call the mediator from any BT node to inform about new data or events, say if the BT decides to attack a target and some system not in the BT needs to know about that.
So a task that binds to dispatchers to funnel information from your character/controller to the BT (though you could also use Set Blackboard values).
And a mediator component to funnel information from your BT to the character/controller.
For example, I use the BT to determine if it is in range & LOS of a target, but I want my attack component to handle the combat (it’s a pretty simple system), so BT can attack -> tell mediator to start attack -> Mediator dispatches Start Attack which the attack component listens to.
When the target dies, the BT is informed about that through the mediator.
Again, new to AI in general myself but it’s working just fine.
Though I don’t know how I would solve the situation you have with wanting to communicate the action to other characters. Using my method, the BT task would tell the mediator to perform the communication, and then the proper channel does that communication. But just what that channel is and what it does, I’m not sure. If it is like a party of characters, like I have, I’d have the mediator inform some party manager, which then communicates that to each member.
That makes sense for internal communications and now that I’ve played with it, I definitely agree with offloading a majority of ‘actions’ to an actor component, storing facts to blackboard for quick retrieval, and then saving the BT for relatively simple logic decisions (or conversely, very frequent decisions). Most of my actions are are decided on the order of tens of seconds so I don’t need the tick rate of a BT.
@ste1nar For the “Tell mediator to start attack” part of your setup, how does that work? Does it have to be a direct function call on a reference in the blackboard or is there some way for the BT or BTT to dispatch the event itself?
It’s a direct function call from the Attack Task to the Mediator component, which is stored in the BB. To me it makes the most sense to directly call functions from the BT but that’s just subjective.
But I feel like it would be tricky to dispatch/delegate call from the BT, because you’d first have to set up the listeners. So the first time you enter the Attack Task, there’s nothing listening to it. And you can’t really get to the Attack Task an Initialize Task which is the first task to run to set things up, or vice verse. If you want to listen to the Initialize Task then that is very possible, but then you can’t get to it from the Attack Task. Unless you store the Initialize Task in the BB. hmm.
Dispatching from the BT feels like a round about way when direct calls, at least should, be just fine. Surely the BT should be aware of the objects it can communicate with?, where as dispatchers are more used for agnostic communication.
An addendum
I wrote that “So a task that binds to dispatchers to funnel information from your character/controller to the BT (though you could also use Set Blackboard values).”
Months after having implemented my BT, and a few weeks of not having time to work on the project, I’m now thinking that maybe it’s just better practice to have a component set BB values than to use a BT task.
What I currently have is an Initializing Task that sets a reference to the mediator object in the BB, as well as binding events.
As the program runs, the Initializing Task receives calls with some data and it performs queries which results in it setting or not setting new BB values.
That is where I am now reconsidering. Instead of having a Task that gets called with new data and makes decisions, Instead use an actor component that gets called and makes the decisions and then updates the BB values with “Set Blackboard Value”. So it now revers back to how it is usually handled in Epicstreams and other tutorials. But the nice things about having a component for that specific task is that you have one place to set BB values, so you don’t Set BB Value all over the place, both in the controller and character.
This BB Value Setter object can be its own object or that logic could be added to the Mediator.
Here’s a simplified chart, left is my current system, right is probably more proper.
Both cases needs to set a reference to the mediator in the BB for BT->Mediator communication to happen.