There is often the need to procedurally instantiate a number of different agents using the same Behaviour Tree or FSM at runtime. Due to the way NodeCanvas decouples the Behaviour Tree data from the agent, this is very easy to do with a number of different options.
You have a game object prefab with a BehaviourTreeOwner. You also have a created BehaviourTree.
At runtime you can instantiate the BehaviourTreeOwner game object prefab and call StartBehaviour(Graph newGraph) on it, providing the BehaviourTree like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using UnityEngine; using NodeCanvas.BehaviourTrees; public class Example : MonoBehaviour { public int count; public BehaviourTreeOwner agent; public BehaviourTree bt; void Start(){ for (int i = 0; i < count; i++){ var newAgent = (BehaviourTreeOwner)Instantiate(agent); newAgent.StartBehaviour(bt); } } } |
You only have a BehaviourTree created and no BehaviourTreeOwner at all. You can add the BehaviourTreeOwner component at runtime and similarily to above, Start a new graph for them:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using UnityEngine; using NodeCanvas.BehaviourTrees; public class Example : MonoBehaviour { public int count; public BehaviourTree bt; void Start(){ for (int i = 0; i < count; i++){ var agent = new GameObject("Agent").AddComponent<BehaviourTreeOwner>(); agent.StartBehaviour(bt); } } } |
Of course in most cases you will also want to assign a blackboard for the BehaviourTreeOwner to use.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using UnityEngine; using NodeCanvas.Framework; using NodeCanvas.BehaviourTrees; public class Example : MonoBehaviour { public int count; public BehaviourTree bt; public Blackboard blackboard; void Start(){ for (int i = 0; i < count; i++){ var agent = new GameObject("Agent").AddComponent<BehaviourTreeOwner>(); agent.blackboard = blackboard; agent.StartBehaviour(bt); } } } |
Using the StartBehaviour(Graph) or SwitchBehaviour(Graph) you can go further and even switch BehaviourTrees at runtime. Here is an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
using UnityEngine; using NodeCanvas.BehaviourTrees; public class Example : MonoBehaviour { public BehaviourTree idleBehaviour; public BehaviourTree fleeBehaviour; public BehaviourTree attackBehaviour; private BehaviourTreeOwner agent; void Start(){ agent = new GameObject("Agent").AddComponent<BehaviourTreeOwner>(); agent.StartBehaviour(idleBehaviour); } void Update(){ if (Input.GetKeyDown(KeyCode.Alpha1)) agent.SwitchBehaviour(idleBehaviour); if (Input.GetKeyDown(KeyCode.Alpha2)) agent.SwitchBehaviour(fleeBehaviour); if (Input.GetKeyDown(KeyCode.Alpha3)) agent.SwithBehaviour(attackBehaviour); } } |
While this is quite possible, it is best design-wise, to have only one BehaviourTree and switch behaviours within using Sub Behaviour Trees.
All the above examples are also true for State Machines as well.
Sometimes you may want to Tick a BehaviourTree manually instead of relying on StartBehaviour, PauseBehaviour and StopBehaviour. Here is how you could do this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using UnityEngine; using System.Collections.Generic; using NodeCanvas.Framework; using NodeCanvas.BehaviourTrees; public class Example : MonoBehaviour { public int count; public BehaviourTree bt; public Blackboard blackboard; private List<BehaviourTreeOwner> agents = new List<BehaviourTreeOwner>(); void Start(){ for (int i = 0; i < count; i++){ var agent = new GameObject("Agent").AddComponent<BehaviourTreeOwner>(); agent.blackboard = blackboard; agent.StartBehaviour(bt, Graph.UpdateMode.Manual, null); agents.Add(agent); } } void Update(){ foreach (BehaviourTreeOwner agent in agents){ agent.Tick(); } } } |
Remember that the Tick method also returns the root node status in case you care about it. Alternatively, you can get the root node status with the rootStatus property on the BehaviourTreeOwner, which in essence returns the currently assigned Behaviour Tree’s root node status.
© Paradox Notion 2014-2024. All rights reserved.