NodeCanvas Forums › Support › Setting up AI with FSM top-level and BT's sub level + related questions
I just picked up Node Canvas last night and I’m eager to jump in and get it to work. I read a great question in the general forum where you answered with a recommendation to use FSM / BT Hybrid model (https://nodecanvas.paradoxnotion.com/forums/topic/large-bt-advice/) I think this sounds great and trying to make this work with a basic Spider AI. I don’t see any general examples of this in the examples package so hopefully this is new territory for the forum (if not, feel free to point me to a previous thread – I don’t see a search tool 🙂
So my spider AI has two basic behaviors on the FSM, “Wander and Wait” and “Attack Target”.
Wander and Wait is meant to wander between patrol points, waiting for a random interval after reaching each one. Every tick, it will also check to see if there is a valid target by using a transform extension method I wrote called GetDamageable which looks for a valid IDamageable in a certain radius/vision angle from the spider.
Attack target puts it into attack mode, and for starters, I just want it to relentlessly move towards the target and attack it zombie-style as that should be the simplest case.
This is an image of my basic FSM
And here is a snip of my wander and wait BT – (this is just a stub)
And here is my spider prefab, showing Damageable which implements IDamageable:
So a couple of questions here:
1) IDamageable seems like it should be able to be passed into a Blackboard variable because I’m using that in my WanderAndWait each tick to find a valid target using a static Method called GetDamageable. Once I find a target, it’s also how I want to store my target.
public static IDamageable GetDamageable(this Transform transform, IDamageable currentTargetDamageable, IDamageable myDamageable, float threshold, float range, float steps, float maxAngle)
For this function to work I need to supply 1 IDamageable in this call in the form of “myDamageable”. IDamageable contains information like the Team of the entity (so it will only be hostile to enemies not friends) and isDead (so it’s not aggroing dead things).
public interface IDamageable
{
bool isDead();
int getTeam();
Transform GetTransform();
void Damage(IDamageable other, float value);
}
Question – How do I store a non-standard component like Damageable/IDamageable as a blackboard variable – so I don’t have to do transform.GetComponent<Damageable>() each time I call GetDamageable?
2) Once I find a valid target my WandW BT moves to “Move To AttackTargetFSM State” – how do I hook this up to the parent level FSM and tell it to move to AttackTarget?
With those 2 questions answered, this should give me a decent foothold on getting a first case setup.
Thanks!
Hello!
I saw your other post 🙂 Indeed FSM top level and SubBTs is what I think is best combination of FSMs and BTs.
Thanks a lot for your thorough explanation and details. To answer your questions:
1. NC can work with custom types and interfaces prety well. The first thing you would like to do, is open up the Preferred Types editor (Window/NodeCanvas/Preferred Types) and add your interface or any other type in the list. From there on, you will be able to create blackboard variables of IDamagable type for example.
Also, you are able to create BBParameters of any type including interfaces. So you are free to do something like this for example within a custom Task:
1 2 3 4 5 6 7 8 9 10 11 |
public class Example : ActionTask{ public BBParameter<IDamagable> target; protected override void OnExecute(){ Debug.Log(target.value.isDead()); EndAction(true); } } |
And of course you are able to link the above parameter to any blackboard variable of the same or assignable type as well! 🙂
So for example this BBParameter
Furthermore, you are also able to create Tasks with a specific ‘Agent Type’ by using the generic version of tasks like for example:
1 2 3 4 5 6 7 8 |
public class Example : ActionTask<Damagable>{ protected override void OnExecute(){ EndAction( agent.isDead() ); } } |
Doing the above, is relevant to THIS link in the documentation by the way.
2. To make the transition happen from Wander to Attack state, there are a lot of ways. What I would do, would be to have a variable “Target” on the blackboard. Within the Wander BT state, when a target has been found, set that variable and have a transition condition from one state to the other checking whether or not the “Target” variable is null. If it’s not null, thus we have a target found, the transition from Wander to Attach would take place.
Let me know if you have any more questions or need any clarifications at all 🙂
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
Awesome thank you this is very helpful. I wrote my own “CheckVariable_IDamageable” class before seeing your reply about the Preferred Types editor-that thing is really slick!
I do have a follow up question below, but for context this is how my graphs look now.
While in Wander/Wait, he’s constantly checking for a player in his view cone (for right now parameters hardcoded in Find Target condition). I suppose I probably don’t need that Dynamic sequencer anymore. Most of the time that will fail and he will then roll a float between 0 – 1 to see if he should idle. He has a 70% chance to satisfy that check which means he will skip out of that selector and move on to wandering, doing the roll/wait check only upon reaching his point. (This was a little counter intuitive to me at first but I think I’m getting it now 🙂
And then in the FSM as soon as the Target variable is !null it switches out of that BT and into the Attack Target BT.
Ok Follow up question:
When the spider sees the player, I want it to do a one time action of “warning” (play an animation where it rears up a bit on its hind legs, plays a scary sound etc) before it pursues, and attacks the player (and currently it will *always* pursue after this).
What I’m wondering is should this be part of the AttackTarget BT, or should this be a separate State in between Wander and Wait and Attack Target. This model of FSM + BT is new to me, and I come from a background of FSM, so by default I was thinking a separate state, but I want to make sure that I’m using BT’s to their full potential as well.
If it would fit on the BT, how do I set that up so that it only happens once at the start of the state (while the pursuing and attacking logic keeps firing)? Or is this desire simply an indication that I should use a state instead of a BT?
Ok, now to build out my AttackTarget state!
I’ll upload a little video when I get all this done to show them in action, and that’s probably also the time I’ll leave my review 🙂
Hey,
Glad to see you are setting this up nicely 🙂
Putting the “warning” action within a new state in itself, is certainly going to work, but I would personlay not opt to do it, since this “warning” is not really a state of the spider’s logic. I see it more like part of the Attack state, considering that this “warning” is tied to the logic of the spider getting ready to attack. Thus, I would make this warning action part of the Attack BT state.
To make something happen only once within the BT, you can use the “Filter” decorator node just above your action node and set it to “Limit Number of Times” to 1 and probably put it as first child under a Sequencer of the BT. Thus, every time the Attack BT state is entered, the action will be filtered and fired only once, until the BT State is re-entered again.
Let me know if that’s what you are after and thanks for sharing 🙂
Cheers!
Join us on Discord: https://discord.gg/97q2Rjh
Hey thanks! I’ll give this a try this evening. Not only do I want to get something functional, I also want to get a good understanding of “Best Practices” so I can scale and avoid a bunch of rework later. Your explanation of “Why” to use a BT here makes perfect sense, and I’ll try out the “How” in a bit.
It’s funny I haven’t seen other tools approach AI in this way. I own BehaviorDesigner and ICode, the former is pure BT and the latter is FSM. Doing BT for everything, even nested, was hard to get my head around (I came from using FSMs in other engines for work), but using only FSMs with ICode got a bit cumbersome as well. I see that BehaviorDesigner has an ICode integration but … yeah that’s two programs with their own styles I need to balance and frankly, more risk if one of them stops being supported.
I’m really liking your technical approach with FSM / BT balance and really happy with my purchase so far, and haven’t even gotten to the dialog tool yet, though I can see that being useful to me later.
Didn’t have as much time tonight as I wanted, but the filter node works great, got them doing an alert sound and animation, and waiting a period before they pursue. They currently leave pursuit when getting beyond a pursuitTetherDistance.
One obvious problem there is that if the player is still close and in LOS they will simply try to pursue again, so the next thing I need to do is put some kind of cooldown or delay before they start searching again, and have them path back to their spawn at that time.
Then I need some actual attack behavior 🙂 Not too exciting but I made a video clip anyways.
Hey,
Thanks for sharing! Looking good so far 🙂
For the cooldown, you may want to use the “Timeout” decorator node. What it does is that it simply interrupts the child node or branch after a specific amount of time has come to pass. Looks like it’s exactly what you want here if I am not mistaken 🙂
Cheers!
Join us on Discord: https://discord.gg/97q2Rjh