Search Unity

Behavior Designer - Behavior Trees for Everyone

Discussion in 'Assets and Asset Store' started by opsive, Feb 10, 2014.

  1. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive Hi Justin, it's been a while I haven't dabbled with BehaviorDesigner but I was wondering how can you access a function within one task from another task? I think at some point it wasn't possible but I believe you said a while back that this was now possible.
     
  2. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Is it easy for you to find the post where I said that it was now possible? I want to see what I was referring to. You can directly select tasks within the editor so that means you can do something like:

    Code (csharp):
    1.  
    2. public class TaskA : Action
    3. {
    4.   public TaskB taskB;
    5.  
    6.    public override TaskStatus OnUpdate()
    7.    {
    8.      taskB.MyFunction();
    9.      return TaskStatus.Success;
    10.    }
    11. }
    12.  
    13. public class TaskB : Action
    14. {
    15.    public override TaskStatus OnUpdate()
    16.    {
    17.      return TaskStatus.Success;
    18.    }
    19.  
    20.   public void MyFunction()
    21.   {
    22.   Debug.Log("MyFunction");
    23.   }
    24. }
    25.  
    Then within the Behavior Designer editor you can select TaskB from TaskA:

    TaskReference.PNG

    You have been able to do this since the beginning though. Besides that, what you could do is use the built-in event system (example). This was added in Behavior Designer 1.5 so it might be what you are thinking of.
     
  3. Yebe

    Yebe

    Joined:
    Dec 23, 2014
    Posts:
    2
    Can Behavior Designer be used to make "AI manager" game like Prison Architect or Dwarf Fortress?

    For example: some AI saw some armored enemy that he can't kill with his current weapon, so he runs to a turret and use it to attack that enemy.
     
  4. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Yes, it definitely can. Here's a quick mockup of that example:

    BehaviorScreenshot.png

    The topmost branch uses conditional aborts (text) to react when the agent sees the armored enemy. If the agent cannot see the armored enemy then it will patrol. When the agent does see the armored enemy, it will first determine if it can kill the enemy with the current weapon. If it cannot, then it will move towards the turret and start attacking using the turret.
     
  5. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Sure, here's the post where we mentioned this: http://forum.unity3d.com/threads/be...rees-for-everyone.227497/page-15#post-1671642

    But I think this code is exactly what I need, in order to get rid of that pesky "MyComponent" temporary solution, so I'm going to test it... :) Thanks!
     
  6. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Ah - FindTask. Yes, that would work as well. I still suggest just referencing it directly within the tree though if you can because that will be quicker as there is no lookup required.
     
  7. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive Hi Justin, I'm getting this error when I activate/deactivate a group containing a character with the Behavior Designer component:



    Would you know how to fix this?
     
  8. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Are you using version 1.5.0.1? There was a fix related to enabling a paused behavior tree which could be related (though I wasn't getting that error). If you are running the latest, is it possible for you to tell me how to reproduce it or send me a repro scene?
     
  9. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    I wasn't! I updated to the latest version and it seems to have taken care of the issue. Thanks Justin! :)
     
    opsive likes this.
  10. cygnusprojects

    cygnusprojects

    Joined:
    Mar 13, 2011
    Posts:
    767
    Hi Justin,

    At last, back at behavior trees! I upgraded my project to Unity 5.1.0b4, Behavior Tree Designer 1.5.0.1, Movement Pack 1.4.1 and A* Pathfinding Pro 3.6.4

    I'm starting my behavior trees from scratch and while I was adding a new A* Pathfinding Patrol task to the tree I'm facing this error:
    Code (csharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. BehaviorDesigner.Runtime.Tasks.Movement.AstarPathfindingProject.RichAI.Patrol.OnDrawGizmos () (at Assets/Behavior Designer Movement/Third Party/AstarPathfindProject/RichAI/Tasks/Patrol.cs:88)
    3. BehaviorDesigner.Runtime.Tasks.ParentTask.OnDrawGizmos ()
    4. BehaviorDesigner.Runtime.Behavior.OnDrawGizmos (BehaviorDesigner.Runtime.Tasks.Task task)
    5. BehaviorDesigner.Runtime.Behavior.OnDrawGizmos ()
    6. UnityEditor.DockArea:OnGUI()
    This error also pops'up whenever I take focus of the Patrol task. I delved into the code and it looks like a check should be added to see if waypoints is a valid list:
    Code (CSharp):
    1. for (int i = 0; i < waypoints.Value.Count; ++i) {
     
  11. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Welcome back! :)

    Your null check is a good idea:

    Code (csharp):
    1.  
    2.   if (waypoints == null || waypoints.Value == null) {
    3.      return;
    4.   }
    I made the change on my and have updated the A* integration assets to the Movement Pack integrations page.
     
  12. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive Hi Justin, it looks like I may have stumbled upon a bug: coroutines called within a task only start executing in the next frame!

    I believe the part of the coroutine situated before the "yield return new WaitForSeconds(myNumberOfSeconds)" statement should execute right away (in the same frame it's called) and then the rest happens later of course. At least I think that's the way coroutines work in Unity...

    Edit: Just to be clear, I'm talking about a coroutine defined in a task and called from within that same task.
     
    Last edited: May 3, 2015
  13. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    @Seith -

    You are right - the part before the yield should be executed within the same frame. I just created a simple testcase but I'm not seeing the same thing as you are:

    Code (csharp):
    1.  
    2. public class CoroutineTest : Action
    3. {
    4.    public override void OnStart()
    5.    {
    6.     Debug.Log("Starting coroutine " + Time.time);
    7.     StartCoroutine(MyCoroutine());
    8.    }
    9.  
    10.    public override TaskStatus OnUpdate()
    11.    {
    12.     return TaskStatus.Running;
    13.    }
    14.  
    15.   public IEnumerator MyCoroutine()
    16.   {
    17.     Debug.Log("Within Coroutine start" + Time.time);
    18.  
    19.     yield return new WaitForSeconds(1.0f);
    20.  
    21.      Debug.Log("End " + Time.time);
    22.   }
    23. }
    24.  
    This outputs the following:

    So "Within Coroutine start" is being called within the same frame as the frame that starts the coroutine.
     
  14. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    I see. But did you start calling the coroutine directly from within the OnUpdate() method? That's the way I'm doing it and that's when it breaks down.

    (Of course I have flags that prevent the coroutine call to be spammed, so it's only called once until it finishes)
     
  15. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    I just tried it:
    Code (csharp):
    1.  
    2. public class CoroutineTest : Action
    3. {
    4.   private bool coroutineStarted = false;
    5.  
    6.    public override TaskStatus OnUpdate()
    7.    {
    8.     if (!coroutineStarted) {
    9.         Debug.Log("Starting coroutine " + Time.time);
    10.         StartCoroutine(MyCoroutine());
    11.         coroutineStarted = true;
    12.     }
    13.     return TaskStatus.Running;
    14.    }
    15.  
    16.   public IEnumerator MyCoroutine()
    17.   {
    18.     Debug.Log("Within Coroutine start " + Time.time);
    19.  
    20.     yield return new WaitForSeconds(1.0f);
    21.  
    22.     Debug.Log("End " + Time.time);
    23.   }
    24. }
    25.  
    This outputted:

    So the first part of the coroutine was executed the same frame as well. If send me a small repro scene I'd be happy to take a look at that.
     
    Last edited: May 3, 2015
  16. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Hah! That's embarrassing, it looks like I was calling the coroutine the wrong way. I was doing:

    StartCoroutine("MyCoroutine");

    And because of this the coroutine was actually called once in the frame, didn't do anything, and then once again in the following frame, which this time worked (?!!). So I'm sorry for the false alarm; I just needed to learn how to call coroutine properly... :)

    (And as always, thank you very much for your help!)
     
  17. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    @Seith -

    Ah, that was it! You were right - starting with the string version did have a one frame lag. There's no reason for that. I just fixed it - I can send you a new version or using the non-string version will work as well.
     
  18. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Thank you Justin, that's alright I'm fixing now all my coroutine calls to fit the non-string format. Anyway the advantage compared to using strings is that Unity tells you right away if the method name is undefined... :D
     
  19. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive Just another question: I have tasks under a sequence and the tasks are executed one after the other until the sequence starts again. Do the variables inside a task "remember" their previous values (the last time they were active)? Or are they reinitialized at every pass?
     
  20. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    The values aren't reset until you specifically reset them within a method such as OnEnd. Sort of related, in the next version I've added a feature that will automatically reset all of the values when the behavior tree restarts. This feature is useful if you have added the tree to an object that is within an object pool.
     
  21. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Sounds great! Thanks Justin!
     
  22. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive I'm encountering an error I hadn't seen before. I have a script to build an actor in my game and it used to work fine until I updated to the latest Behavior Designer version. All I do is assign the external behavior tree like this:

    Code (CSharp):
    1. myActor.GetComponent<BehaviorTree>().ExternalBehavior = AssetDatabase.LoadAssetAtPath("Assets/Scripts/AI/" + behaviorFile + "Behavior.asset", typeof(ExternalBehavior)) as ExternalBehavior;
    But now that line gives off an error like so:

    NullReferenceException: Object reference not set to an instance of an object
    BehaviorDesigner.Runtime.Behavior.EnableBehavior ()
    BehaviorDesigner.Runtime.Behavior.set_ExternalBehavior (BehaviorDesigner.Runtime.ExternalBehavior value)
    ActorBuilder.DoCreateCharacter (Boolean rebuild, UnityEngine.Transform sel) (at Assets/Editor/ActorBuilder.cs:833)


    (The line in my script is the one I copied above)

    And there's a weird new game object that popped up in the hierarchy called "Behavior Manager" which I'd never seen before... o_O

    Edit:
    Just to be clear: I'm looking to assign an existing external tree file to the BehaviorTree component of my actor through an editor-only script (not at game-time).
     
    Last edited: May 3, 2015
  23. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    That's an odd error to get. Do you have the behavior tree starting when it is enabled? If you import the runtime source code and send me the line number that it fails on that would help narrow the problem down.
    That has existed since Behavior Designer 1.0 :) The Behavior Manager does the actual execution of your behavior trees.
     
    Last edited: May 4, 2015
  24. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Ahh.. that would cause it. Don't worry about sending me the line number. When you assign the external behavior it assumes that the game is running. I'll send you a new runtime DLL.
     
  25. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    I got a request for Blox integration and I just wanted to let everybody know that the integration is complete. You can download the integration tasks and sample project from the samples page.
     
  26. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Hi, How can do I something an enemy character shot us at a specified distance?
    and second question I have a full animated character that works with animator and mecanim system. so can I use that character with its own animations as an enemy?

    Thanks
     
  27. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127

    Take a look at this help topic. If you scroll down about halfway through the page you'll see this image:

    This branch of the tree has the agent attacking as long as the player (named Doug) is within distance (and sight). The Use task will then do the actual attacking. What it means to attack is unique to each game so that's why the Use task is included with the Third Person Controller asset instead of being a task that is included with Behavior Designer. At a lower level you could instantiate a prefab for a bullet or do a raycast for the actual attack within your behavior tree.

    This post has a complete explanation of how you can do it. At the lowest level you can use the Animator tasks to set the Animator parameters within your behavior tree. At a higher layer you can write a component which will translate the root motion values into a velocity for your pathfinding implementation. This article gives a pretty good overview of how to accomplish that. This approach is similar to what we took for the Third Person Controller.
     
    ksam2 likes this.
  28. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Please look at this pic. if I place my character in sign of enemy at the first place (before I play the game) after playing game the animation will works. but it will not happens if I go in front of enemy inside of game.

    Tree doesn't get update?
     
    Last edited: May 9, 2015
  29. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    When your character goes in front of the enemy, is the tree active? In order to keep the tree active all of the time you'll need to either set the Repeater to "Repeat Forever" or on the behavior tree component set it to "Restart when Complete". A third option is to have an Action task that is always running (similar to the Third Person Controller tree in the previous link).

    Also, just looking at your tree, since you have a Repeater parented to your Sequence task the conditional aborts on the Sequence task aren't going to do anything. It definitely won't cause a problem but the Repeater is reevaluating the conditional task anyway.
     
    ksam2 likes this.
  30. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Thanks, sorry for noob questions but now I'm using "Wander" action but when It turns to right ' left or turn back it would be awful for a 3d person game. because of that I want to add animations for each Turns right or left or back in Wander mode!
    Can you please help me with that? or can you please add this options to wander move action?
    Thanks.
     
  31. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    No problem, I'm happy to help.

    This actually deals with the second part of your original question. With the Movement Pack tasks I stayed away from dealing with animations because that would make the tasks less generic and in this case the animations should probably be handled outside of the behavior tree anyway. Are you using Unity's Navmesh? If you take a look at the link to MecWarriors link you'll see their solution to syncing the animation with the NavMeshAgent.
     
    ksam2 likes this.
  32. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080

    Is this a bug? after wander action we can't continue Tree anymore! (This pic is just an example I tried lots of ways but no luck)

    Second I want to use look at target because I need when My character get in sign of enemy the enemy look at my character but it seems there is no action for this, How can I do that? I can't do that with "Look at or Set Look At Position"
     
    Last edited: May 10, 2015
  33. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Wander always returns a TaskStatus of running so the only way to get it to stop is to use conditional aborts or the interrupt task. Also, the Selector Evaluator is more of a specialized task so I would stick to just using the Selector or Sequence task while you are still getting the hang of it.

    Edit: take a look at this tree for an example of aborting a task while it is running. This example uses the Patrol task but the Wander task behaves in the same way.
    It sounds like the Movement Pack's Rotate Towards task should work for that situation.
     
    Last edited: May 10, 2015
    ksam2 likes this.
  34. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Really the best AI designer. When I'm working with this looks like I'm playing a game! so funy...
    I think the last problem I have with this is just "Can See Object" Task enemy can see me behind walls. I use mask layer but still can't hide behind something

    Can't see any pic of tree you mentioned there. :confused:
     
    Last edited: May 11, 2015
  35. teeebor

    teeebor

    Joined:
    Mar 7, 2013
    Posts:
    3
    Does WebGL supported by Behavior Designer?
     
  36. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Great to hear that things are going well! As long as your obstructing object isn't on the "Ignore Raycast" layer the Can See Object should return failure meaning the player is not within sight. If that isn't the case, can you modify the demo scene so I can reproduce it on my end? I just extended one of the barriers and the agent isn't finding the marker:
    can see.PNG

    Make sure you first login to view the attachments.

    Yes, it is.
     
    ksam2 likes this.
  37. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Thanks again. Can See action solved it was a problem of my target, but still have problem with using movement Tasks! it always stop tree. Sorry but with all your guidance I can't get movement tasks to work (For example tree always stop after Rotate Towards task )
     
  38. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    It sounds like you'll need to keep the tree active with one of the methods described in this post. Have you downloaded and played around with the CTF and RTS sample projects? There are videos that go along with them which describe how they work as well.

    In addition, the Third Person Controller sample project gives a great example of a complete behavior tree. The Third Person Controller behavior tree documentation goes into a ton of detail in how I designed the tree so it is helpful even if you don't have the Third Person Controller.

    There are also three stickied topics at the top of this board which gives mini-examples for how to design your tree. The "Patrol and Seek Behavior Tree" sounds very similar to what you are trying to accomplish so I would definitely take a look at that tree.
     
    ksam2 likes this.
  39. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    Hi again, I've created my tree and now my enemy looks really smart! thanks for this cool asset.
    The last thing I need to do is enable or disable a script that is placed on my enemy's gun model. Can you please help me with that? I think there is no task for this in behavior designer but can you please give me the code that can enable and disable a script that is placed on my gun model? I know it is an easy work to do but I'm totally away from programming.
     
    Last edited: May 14, 2015
  40. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Happy to hear that things are going well.

    In that situation you can use the Set Is Enabled task - just drag your gun component into the Object field and then you can enable/disable it.
     
    ksam2 likes this.
  41. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,080
    That doesn't enable a specified script on my gun model.
     
  42. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Instead of dragging the GameObject to the Object field, drag the actual component from the Unity inspector. This will then allow you to enable/disable a specific script.
     
  43. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    Version 1.5.1 of Behavior Designer has been submitted to the Asset Store and is available to those who purchased through opsive.com. This version includes a few new features and a lot of integration task updates. You can view the full release notes here. The highlights of this release include:

    Reset Values on Restart
    reset.png
    This feature is extremely useful to those who are using their behavior trees within an object pool. When the behavior tree is reset (either automatically through the Restart When Complete parameter or when it is disabled -> enabled), the SharedVariables and public task values will be reset back to their starting values.

    Improved Popover Navigation
    referenced.png
    As discussed in this post, a new popover has been added to the top toolbar which allows you to quickly navigate to behavior trees referenced within the active behavior tree.
     
    khan-amil and hopeful like this.
  44. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    @opsive Hi Justin, I noticed that any time the Behavior Designer editor window is open my framerate drops by at least a third, so I've taken the habit of keeping it closed 99% of the time. But I was wondering; is that something that could be optimized on your side or is it a Unity limitation that can't really be fixed?
     
  45. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    You know, you could have said something 24 hours ago before version 1.5.1 was released ;)

    Good catch. I was repainting the window one too many times so it was doing unnecessary work. I'll send you a PM with the new editor dll. Make sure you first update to 1.5.1. If anybody else wants this version let me know.

    To give some background, back in the Behavior Designer version 1.2 or 1.3 timeframe I got a few reports saying that the editor was laggy with a larger tree and the Behavior Designer window open. Since then I cached pretty much everything that I can within the editor and it fixed the problem back then. This repaint call has existed since version 1.0 though so I guess you really only notice it with larger trees.
     
  46. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    The Behavior Designer - Tactical Pack has been submitted to the Asset Store!

    Behavior Designer - Tactical Pack contains 14 different behavior tree tasks focused on tactical situations. Since attacking is unique to each game, the Tactical Pack uses interfaces so you can implement your own attack and damage logic that fits your game.

    You can see the web demo of the Tactical Pack here.

    Screenshot1.png
    Screenshot2.png
     
  47. IL4Mi3y

    IL4Mi3y

    Joined:
    Dec 29, 2014
    Posts:
    38
    Hi, I need some help.
    I set up a trigger but it won't work.

    I also added a script and printed out some text when OnTriggerEnter is called and it works fine.

    It does not work when I try it using behavior tree.
    Has anyone an idea how I can fix this?

    BehaviorScreenshot.png
     
  48. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    It doesn't look like your tree is reevaluating so the trigger isn't going to be called. This tree gives a small example of using the trigger task.
     
  49. IL4Mi3y

    IL4Mi3y

    Joined:
    Dec 29, 2014
    Posts:
    38
    @opsive
    I have seen this post already, but I can't find a tree there.
    Can you post the tree here in the forum, please?

    Edit: I got it. (See image)

    But I have a question to it.
    Does "until success" mean that it proves each frame wether the trigger is enter?
    I hope not. It only should work based on the OnTriggerEnter event.

    But great asset!

    Edit2: Excuse me, I have another question.
    I wrote a custom script to fade the light intensity up to a specific value.
    At the moment i set up the light as variable and get the intensity from my script.
    Is it possible to set the variable as float and then bind it to light->intensity?
    So access the intensity of a light?

    Code (CSharp):
    1. public override void OnStart()
    2. {
    3.     lLight = lightObject.Value.GetComponent<Light>();
    4.     StartCoroutine(fade());
    5. }
    6.  
    7. private IEnumerator fade()
    8. {
    9.     float current = from;
    10.     while (current < to)
    11.     {
    12.         lLight.intensity = current;
    13.         yield return new WaitForSeconds(wait);
    14.         current = current + step;
    15.     }
    16. }
    Then I have the possibility to use my script for other things.
    For example to fade the range of the light.

    Untitled.png
     

    Attached Files:

    Last edited: May 19, 2015
  50. opsive

    opsive

    Joined:
    Mar 15, 2010
    Posts:
    5,127
    When you login all of the attachments will be downloadable :)

    That's one way to do it, but your conditional aborts are basically doing repeat work because you have the Until Success task. That example tree has a better way of doing it involving just conditional aborts. To answer your question, yes, Until Success will evaluate its children every tick when the child does not return a status of running.
    Appreciate it!
    If you use the Variable Synchronizer component you can have it automatically sync SharedVariables with other types of variables. Behind the scenes this uses reflection so it will only work with properties (reflection with fields is slow). Since I think the Light component only has an intensity field and not a property, I think that the next best option is use the Get/Set Intensity task and have that task always run as a child of a parallel task. This will then sync the variable. Alternatively, have a specific task like you are currently doing will make your tree smaller.