Search Unity

[AI SCRIPTING] Panda BT: Behaviour Tree scripting

Discussion in 'Assets and Asset Store' started by ericbegue, Feb 26, 2016.

  1. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Now I get why you don't add such function : you want to keep it BT pure ... and it works!
     
  2. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Could we get enums parameters? strings are so prone to error...
     
    Martin_H likes this.
  3. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    @ericbegue this script freezes on that green Wait, it should go to Wander then repeat the root, no?
    EDIT: fallback stops on the first success (why?) so I replaced with not Wait(.1) and it goes to wander but still doesn't repeat the entire
    parallel
    fallback
    while IsHealthy...

    Code (CSharp):
    1. tree("Root")
    2.     parallel
    3.         fallback
    4.             while IsHealthy
    5.                 fallback
    6.                     while IsAttacked
    7.                         tree("Counter Attack")
    8.                     repeat
    9.                         random
    10.                             tree("find a mate")
    11.                             tree("Mate")
    12.                             tree("Wander")
    13.                             tree("Get Some Rest")
    14.             //need food, if not get food, if not wander
    15.             tree("Search For Food")
    16.             tree("Go Eat")
    17.             tree ("Search For Prey")
    18.             tree("Go Kill")
    19.             Wait(.1)
    20.             tree("Wander")
    21.          
    22.         repeat mute tree("Die")
    23.  
    24. tree("Go Eat")
    25.     while HasTargetFood
    26.         parallel
    27.             //update the target if needed
    28.             repeat
    29.                 sequence HasFoodMoved
    30.                     SetDestination_Food
    31.                     Wait(0.2)
    32.             //move until reach then eat
    33.             sequence
    34.                 MoveTo_Destination
    35.                 Eat
    36.  
    37. tree("Search For Food")
    38.     while not HasTargetFood
    39.         sequence
    40.             Acquire_Food
    41.             Wait(.5)
    42.  
    43. tree ("Search For Prey")
    44.     while
    45.         sequence
    46.             CanAttack
    47.             not HasTargetPrey
    48.         sequence
    49.             Acquire_Prey
    50.             Wait(0.5)
    51.  
    52. tree("Go Kill")
    53.     while
    54.         sequence
    55.             CanAttack
    56.             HasTargetPrey
    57.         parallel
    58.             //update the target if needed
    59.             repeat
    60.                 sequence HasPreyMoved
    61.                     SetDestination_Prey
    62.                     Wait(0.1)
    63.             //move until reach then attack
    64.             repeat
    65.                 sequence
    66.                     MoveTo_Destination_WithinAttackDistance
    67.                     Attack
    68.                     WaitAfterAttack
    69.  
    70. tree ("Get Some Rest")
    71.     sequence
    72.         SetDestination_Random_Vision
    73.         MoveTo_Destination
    74.         Wait(10)
    75.  
    76. tree ("Wander")
    77.     sequence
    78.         SetDestination_Random_Vision
    79.         MoveTo_Destination
    80.         Wait(0.5)
    81.  
    82.  
    83.  
    84. tree ("Counter Attack")
    85.     sequence
    86.         Acquire_Prey_Attackant
    87.         tree ("Go Kill")
    88.  
    89. tree ("Mutate")
    90.     sequence
    91.         ReadyForMutation
    92.         Wait(2.0)
    93.         DoMutate
    94.         Wait(2.0)
    95.  
    96. tree("Die")
    97.     sequence
    98.         IsHealthLessThan(0.1)
    99.         Explode
    100.  
    101. tree("Mate")
    102.     sequence
    103.         HasMate
    104.         IsOvulating
    105.         repeat
    106.             sequence
    107.                 SetDestination_Mate
    108.                 MoveTo_Destination
    109.                 Mate
    110.  
    111. tree("find a mate")
    112.     sequence
    113.         not HasMate
    114.         Acquire_Mate
    115.         Wait(0.5)
    Screen Shot 2016-11-13 at 5.43.03 PM.png
     
  4. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Enums support would be a great addition, particularly for the pro-edition for that it would allow selecting parameter values from a list the editor . That's on my todo list.
     
    Last edited: Nov 15, 2016
    laurentlavigne likes this.
  5. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    That's just how the fallback node works. It runs its children one after the other while they fail and it stops on the first child that succeeds. If you want to continue when either the children succeed or fails, that is you don't care whether they succeed or not, you could use a sequence with the mute node. The mute node always succeeds whatever the return status of its child is. For instance:
    Code (CSharp):
    1. sequence
    2.     mute task_a
    3.     mute task_b
    4.     mute task_c
    All 3 tasks will run whatever their return status would be.

    I know it can be confusing, but keep in mind that the "while" in BT does not work the same way as the "while" in c#; the while node in BT does not do repetition. The c# "while" has to be translated with a combination of the "while" node and the repeat "node":
    Code (CSharp):
    1. while IsSomeConditionTrue
    2.     repeat
    3.         SomeTaskToBeRepeated
     
    Last edited: Nov 15, 2016
    laurentlavigne likes this.
  6. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Should repeat root handle that ?
     
  7. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @laurentlavigne Ok. I think I've spotted what your problem is.
    The root tree does not repeat because:
    Code (CSharp):
    1. repeat mute tree("Die")
    never completes and will run forever ('repeat' will repeat until its child fails, however 'mute' never fails).

    Here is a summary of the problem:
    Code (CSharp):
    1. tree("Root")
    2.     parallel
    3.         fallback
    4.             /*completes and succeeds on Wait(.1)*/
    5.         repeat mute tree("Die") /*Runs forever!*/
    The 'repeat' node never completes, therefore the 'parallel' keeps running as well as the root.
     
    Last edited: Nov 16, 2016
  8. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Gotcha! But I can't remote that repeat because parallel fails only if both fail, and fallback will still be running some code while tree("die") only execute once, yeah?
     
  9. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @laurentlavigne
    The parallel fails if one of its child fails.
    The fallback is not running anymore; it has turned green which means it has completed successfully. The tree("die") is infinitely repeating because it has a mute in front of it, so the repeat node never fails, so it keeps repeating tree("die"). Maybe you don't need that mute?
     
  10. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Ok since parallel fails if any of its children fails, removing mute on die will mean the children of parallel will be repeated every tick, so the content of fallback won't get a chance to do anything.


    I tried it and yep that's what happens. It seems to me that the best way to write higher level logic in the root is to toggle off root repeat and do the looping by hand like this.

    Code (CSharp):
    1. tree("Root")
    2.     parallel
    3.         repeat
    4.             fallback
    5.                 while IsHealthy
    6.                     fallback
    7.                         while IsAttacked
    8.                             tree("Counter Attack")
    9.                         repeat
    10.                             random
    11.                                 tree("find a mate")
    12.                                 tree("Mate")
    13.                                 tree("Wander")
    14.                                 tree("Get Some Rest")
    15.                 //need food, if not get food, if not wander
    16.                 tree("Search For Food")
    17.                 tree("Go Eat")
    18.                 tree ("Search For Prey")
    19.                 tree("Go Kill")
    20.                 tree("Wander")
    21.                
    22.         repeat mute tree("Die")
     
  11. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    When repeat root is checked, the BT script is equivalent to:
    Code (CSharp):
    1. repeat
    2.     mute
    3.         tree("Root")
    4.             /*...*/
    So, when tree("Root") completes (either in success or failure) it gets automatically repeated, otherwise it just stops.

    Repeating the root or not, just depends on whether you want the root to be repeated or not.
    Beware that with the "repeat root" toggled off, the whole tree will stop after completion. For instance, if the fallback fails, the whole tree stops. But that might be what you want to do.

    BTW, why tree("Die") is not in the fallback?
     
    Last edited: Nov 18, 2016
  12. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Because if it is in the fallback it gets executed only once the rest is, die is a test condition of health so needs to be tested every tick.
     
  13. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @laurentlavigne
    I like to embed the conditions inside the trees themselves in order to make them self-contained. This way, it declutters the higher level nodes from testing conditions. For instance, with your BT script, I would embed "while Is Healthy" in every trees except for tree("die") which would have a "while not IsHealthy". Then you can just list the actions in a fallback without testing any condition. Something like:
    Code (CSharp):
    1. tree("Root")
    2.     fallback
    3.         tree("Counter Attack")
    4.         tree("Go Eat")
    5.         tree("Get Some Rest")
    6.         tree("Wander")
    7.         tree("Die")
    8.  
    9.  
    10. tree("Counter Attack")
    11.     while
    12.         sequence IsHealthy IsAttacked
    13.         /* do counter attack*/
    14.  
    15. tree("Go Eat")
    16.     while IsHealthy
    17.         /*go eat*/
    18.  
    19. tree("Get Some Rest")
    20.     while IsHealthy
    21.         /* get rest*/
    22.  
    23. tree("Wander")
    24.     while IsHealthy
    25.         /* wander */
    26.  
    27. tree("Die")
    28.     while not IsHealthy
    29.         /* die */
    So, as soon as the health reaches zero, all the tasks bail out and leave only the tree("Die") to be executed.

    This way of embedding the conditions inside the trees might look a bit unnatural because, we (programmers), are used to put the condition first, like: IF (1st)condition THEN (2nd)action. But with behaviour trees, it seems (1st)Action IF (2nd)condition works better.
     
    Last edited: Nov 19, 2016
    kk99 and laurentlavigne like this.
  14. ciberxtrem

    ciberxtrem

    Joined:
    Jul 24, 2012
    Posts:
    5
    Hello Eric, I've been playing a bit with your Behaviour Tree and I like it a lot! it is super easy to use and I like the way to do it with just plain text.

    I would need the BehavourTree to run also without any Unity dependenct. I think currently it only works with Unity.
    I'd like to ask you this feature. Another option would be to modify myself the code but what I have is the compiled version of the library so I would need to have the source code to be able to do it, am I right ?.

    What do you think ?
    Thanks you! :)
     
    Last edited: Nov 21, 2016
  15. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi @ciberxtrem,

    Great that you like Panda BT! It would be great if you leave a review on the Asset Store.

    The core is completely independent from Unity, so it would possible to run behaviour trees outside of Unity. Although, you won't be able to visualize the BT at runtime, since this part is implemented in the Unity Inspector, therefore depends on UnityEditor.dll and UnityEngine.dll.

    The Pro Edition comes with the complete source code.

    Although, it's possible to run the core of Panda BT independently from unity, I haven't published a ready to use package and this way of using the core is not documented. But it should be simple and I can assist about that. The only difference is in the way the source is compiled and bound to an object. So excepted that and the runtime visualization, everything else is the same.

    Could you tell a bit more why would you need to run BTs outside of Unity?
     
  16. ciberxtrem

    ciberxtrem

    Joined:
    Jul 24, 2012
    Posts:
    5
    Hi @ericbegue!, cool! I need it for a multiplayer game with an authoritative server that is going to run standalone without Unity and the clients are the ones that will run the game with Unity.

    So what I'd like is to have both runtimes, the current runtime for Unity to create the trees and debug them and then just export the texts to the server to run them in the standalone runtime version of your Behaviour Tree engine :)

    Cool, good to know that we have the full Source code in the Pro Edition!
    As you said one of the main changes is related to how to map the tree text to the class with the Tasks, now I guess the binding is done via GameObject.

    I'm currently looking for all available options and currently yours seems the best avaliable option to me! if you know any other behaviour tree engine with a cool editor and debugger that can run standalone tell me and I'll take a look.
     
    Last edited: Nov 21, 2016
  17. guillermo-b

    guillermo-b

    Joined:
    May 30, 2013
    Posts:
    10
    Hi,
    I tried using Panda BT on windows 10 and got the following errors. Will windows 10 be supported in the near future?

    Guillermo

    Error: method `System.Delegate System.Delegate::CreateDelegate(System.Type,System.Object,System.Reflection.MethodInfo)` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Boolean Panda.BTRuntimeBuilder::Bind(Panda.BTTask,Panda.TaskImplementation).
    Error: method `System.Delegate System.Delegate::CreateDelegate(System.Type,System.Object,System.Reflection.MethodInfo)` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Boolean Panda.BTRuntimeBuilder::Bind(Panda.BTTask,Panda.TaskImplementation).
    Error: method `System.Reflection.MemberInfo[] System.Type::GetMembers(System.Reflection.BindingFlags)` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at Panda.TaskImplementation[] Panda.TaskImplementation::Get(System.Object[]).
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at Panda.BTSourceString.
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.String Panda.BTSourceString::GetHash().
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.String Panda.BTSourceString::GetHash().
    Error: method `System.Void System.Security.Cryptography.SHA256Managed::.ctor()` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.String Panda.BTSourceString::GetHash().
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.String Panda.BTSourceString::GetHash().
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.String Panda.BTSourceString::GetHash().
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Byte[] Panda.BTLAssetManager::GetHash(System.String).
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Byte[] Panda.BTLAssetManager::GetHash(System.String).
    Error: method `System.Void System.Security.Cryptography.SHA256Managed::.ctor()` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Byte[] Panda.BTLAssetManager::GetHash(System.String).
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Byte[][] Panda.BTLAssetManager::GetHashes(Panda.BTSource[]).
    Error: type `System.Security.Cryptography.SHA256Managed` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.Byte[][] Panda.BTLAssetManager::GetHashes(Panda.BTSource[]).
    Error: method `System.Void System.Security.Cryptography.SHA256Managed::.ctor()` doesn't exist in target framework. It is referenced from PandaBehaviour.dll at System.<message truncated>
     
  18. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi @guillermo-b,

    Windows 10 (PC Mac & Linux Standalone) is supported. There are known issues on Windows Phone and Windows Store, so if you compile for Windows Store, you will get these errors. The other platforms are OK.

    Panda BT rely heavily on reflection, which is restricted on Windows Store. So, sorry, it is simply not possible to support this platform.
     
  19. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    I redid the trees like this and now iteverything works - it's like magic ;)

     
  20. XRA

    XRA

    Joined:
    Aug 26, 2010
    Posts:
    265
    hey @ericbegue really enjoying PandaBT thank you for making it available so freely. I'm new to Behavior Trees, still figuring out how to best use them, but I'm curious about one thing, mostly just wondering why it works out this way with some very minor GC allocation-

    if I have
    [Task]
    bool IsThingActive;

    "while IsThingActive" adds 9 bytes of GC Alloc per frame (not a big deal- seems like any while bool reachable in the current node adds 9bytes)

    But if I do

    bool IsThingActive;
    [Task]
    void ThingActive(){
    Task.current.Complete( IsThingActive );
    }

    "while ThingActive" is zero bytes of GC Alloc (great!)

    I have no problem making functions to poll the booleans, since my whole reason for trying PandaBT was to get rid of a lot of coroutines and GC allocations with a FSM I was using. Just the "why" is stuck in my head.
     
    ericbegue and laurentlavigne like this.
  21. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi @XRA,

    Great that you like Panda BT so far. I hope you will found good use of it, and I'm sure it will make things easier compared to coroutines or FSMs. If you have any question about using Behaviour Tree, don't hesitate to ask ;). Also, it would be nice if you leave a review on the Asset Store. That helps a lot to increase the visibility of this tool.

    I was not aware of that GC allocation issue. Good catch! I investigated it a bit and could isolate the source of the allocation. Unfortunately it's coming from the reflection system of Mono, so there is not much I could do to fix it. The following code is reproducing the problem:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Reflection;
    3.  
    4. public class FieldInfoGCLeak : MonoBehaviour
    5. {
    6.     public bool IsThingActive = false;
    7.  
    8.     FieldInfo fieldInfo;
    9.     public bool value;
    10.  
    11.     // Use this for initialization
    12.     void Start ()
    13.     {
    14.         fieldInfo = this.GetType().GetField("IsThingActive");
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void Update ()
    19.     {
    20.         value = (bool)fieldInfo.GetValue( this ); // Allocate 17 B GC! ... =(
    21.     }
    22. }
    23.  
    I send a bug report to Unity with the hope that they would find a fix for that. In the meanwhile I still looking for a workaround...

    So, if you are concerned about GC allocations, the best thing to do for now is to exclusively use methods to define your tasks. Sorry... but at least, you have your why-question answered =).

    Edit:
    There was a similar allocation issue in the past (see this post). For that one, I could find a workaround, so I didn't keep track of the bug. But it has actually been fixed! So, hopefully the Unity team would manage to fix this new bug too...
     
    Last edited: Dec 5, 2016
  22. XRA

    XRA

    Joined:
    Aug 26, 2010
    Posts:
    265
    thanks for the explanation! I will leave a review ;)

    a new question I have is about defining "exit" behavior for specific Tasks- I got very used to relying on this from the FSM, for example it has onEnterState and onExitState. I'd often use onExitState to revert/cleanup or hide some things that were used while in a specific state, as the state is exiting to a different one.

    Task.isStarting acts a bit as "EnterState" which lets me setup what I need for a Task, but I've not figured out a clean way to do something just once when I've completed the Task.
    Any simple approaches I think of involve using a boolean to track if a Task was active previously, but that could get messy.

    One thought is I could try an enum, and have currentAction & previousAction
    Then specific Tasks modify the currentAction so that a node in the behavior tree can check if the Action changed and performs some Exit/End behavior. But is that moving away from the concept of BTs?


     
  23. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @XRA
    Thanks a lot for leaving a review =). I appreciate it.

    Task.current.isStarting is indeed used for doing initialization. There is no equivalent mechanism for signaling when a task is ending (because you don't need it), since it's up to to you to decide when to complete a task. That is you are in control when to call Task.current.Fail|Succeed|Complete to indicate when the task is completed. So, if you have some clean up to do, you just have do it right before completing the task.

    Below is a boiler plate for implementing tasks with an indication of the FSM callback equivalents.
    Code (CSharp):
    1. using UnityEngine;
    2. using Panda;
    3.  
    4. public class SomeMonoBehaviour : MonoBehaviour
    5. {
    6.     [Task]
    7.     void DoSomeTask()
    8.     {
    9.         if (Task.current.isStarting)
    10.         {
    11.             //1. Do some initialization here.
    12.             // (FSM OnEnterState equivalent)
    13.             // ...
    14.         }
    15.  
    16.         //2. Do some work here on every tick.
    17.         // (FSM OnUpdateState equivalent)
    18.         // ...
    19.  
    20.         if ( /*Some ending condition */ )
    21.         {
    22.             //3. The task is completing.
    23.             // (FSM OnExitState Equivalent)
    24.             // Do some cleaning here.
    25.             // ...
    26.  
    27.             Task.current.Complete( /*Either fail (false) or succeed (true)*/ );
    28.         }
    29.     }
    30. }
    Also, coming from FSM, you know that writing/maintaining transitions is a big part of your job. The good news is, with Behaviour Tree, you don't have to worry about transitioning and connecting states anymore. The transitions in BT are implicit, so you don't specify them. Practically, this means that when you write a task, you design it completely independently from any other task. That is, a task is an atomic action that can be used at anytime and anywhere in the tree. So, when it comes to modify a BT, you can insert/delete/move a task without worrying about its transitions, it will just work. In contrast with FSM, where any single modification implies fiddling with the transitions. Compared to FSM, maintaining a BT is a breeze.

    To come back to your question, you could as well handle the initialization and cleaning as tasks directly in the tree. For instance, initializing, doing some work then cleaning up could be implemented as:
    Code (CSharp):
    1. sequence
    2.     Initialize
    3.     DoSomeWork
    4.     CleanUp
    You could even handle errors directly in the BT. Let's say, something could go wrong with DoSomeWork and it fails. Therefore the sequence will also fail and CleanUp will not be executed, which is not very neat. To avoid this situation and handle the error properly, you can wrap the sequence into a fallback:
    Code (CSharp):
    1. fallback
    2.     sequence
    3.         Initialize
    4.         DoSomeWork
    5.         CleanUp
    6.     sequence // Will be executed if the first sequence fails.
    7.         CleanUp
    8.         DebugLogError("Something went wrong.")
    I'm not sure whether I'm still answering your question or I'm drifting. But I hope this gives some ideas about the flexibility of Behaviour Tree.
     
    Last edited: Dec 5, 2016
  24. reubengann

    reubengann

    Joined:
    Jun 1, 2016
    Posts:
    7
    I'm getting up to speed on this, but I'm having a problem right up front. All my characters are made at run-time, so I'm using the run-time compile function
    Code (CSharp):
    1. PandaBehaviour AI = Jean.go.AddComponent<PandaBehaviour>();
    2. TextAsset ta = Resources.Load("Behavior/jean110alby.BT") as TextAsset;
    3. AI.Compile(ta.text);
    I believe this works, because if I set breakpoints on the functions called by the behavior tree, they do stop execution. But unlike if I add the script/tree at design time, I cannot see the tree in the inspector while it's running. That's making it challenging to debug. Is this normal behavior?
     
  25. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @reubengann Thank you for reporting this problem.
    I reproduced your setup on my side. The BT is not displayed in the Inspector, but it is indeed running as expected. I will fix this, since it useful to have the BT displayed in the Inspector to check whether a generated BT script or runtime-loaded one is running properly.
     
    Last edited: Dec 17, 2016
    reubengann likes this.
  26. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @reubengann and @all,

    The BT scripts not being displayed in the Inspector after calling 'PandaBehaviour.compile(...)' has been fixed. Also, the same problem occurred when assigning the TextAsset's to 'PandaBehaviour.scripts' in code (side note: that requires PandaBehaviour.Apply()).

    Both problems will be fixed in version 1.4.1.

    As usual, if you don't want to wait until the package becomes available on the Asset Store, pm me and I'll send it to you directly.
     
  27. reubengann

    reubengann

    Joined:
    Jun 1, 2016
    Posts:
    7
    Great, thank you. I'll send you PM.

    I wonder if there's any way to implement the params feature of C#. If I define a
    Code (CSharp):
    1. SetConversation(params string[] names)
    2. {
    3. foreach(string name in names)
    4.         {
    5. //stuff
    6.         }
    7. }
    Panda thinks there's no method assigned for SetConversation("string1", "string2"), though it's valid in the language. If there's no way to do this I will simply overload the function for as many args as I need.
     
  28. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @reubengann

    Methods with 'params' are not supported in Panda. Though, it should not be hard to implement it. I try to keep the system as simple as possible, but I'll see what I can do.

    In the meanwhile, having the overloaded functions is a work-around solution.

    You could also have a AddToConversation task implemented as follow:
    Code (CSharp):
    1.  
    2. List<string> participants = new List<string>();
    3. [Task]
    4. void AddToConversation(string name)
    5. {
    6.     participants.Add(name);
    7.     Task.current.Succeed();
    8. }
    9.  
    Then you could add as many conversation participants as you want just as follow:
    Code (CSharp):
    1. sequence
    2.     AddToConversation("Jean")
    3.     AddToConversation("Jimmy")
    4.     AddToConversation("Suzanne")
    5.     // ... or more ...
    6.     StartConversation
    7.    
     
    Last edited: Dec 18, 2016
    reubengann likes this.
  29. Welemco

    Welemco

    Joined:
    Dec 18, 2016
    Posts:
    2
    Hi there, I really like panda and I'm using it in a school project.
    I just want to ask if there is a way to let the while action run even if the condition fails mid run.
    My code is like this
    Code (CSharp):
    1. while
    2.       In_Range
    3.       sequence
    4.           stop_moving
    5.           attack
    6.           return_moving
    If the target exits from range my character stops moving until the target comes back in range

    Not an usual english speaker so I'm sorry if there is any error.
     
    Last edited: Dec 18, 2016
  30. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @Welemco
    Great that you like Panda BT. Maybe you could leave a review on the Asset Store. I hope it will help you for your school project.

    So, you want your character to continue the attack even if the target goes out of range?
    If this is the case, you don't need the 'while' node, just place the 'In_Range' condition at the beginning of the 'sequence', like this:

    Code (CSharp):
    1. sequence
    2.     In_Range
    3.     stop_moving
    4.     attack
    5.     return_moving
    This way, the attack starts only when the target is in range but it won't stop once started.
     
    Last edited: Dec 18, 2016
    Welemco likes this.
  31. Welemco

    Welemco

    Joined:
    Dec 18, 2016
    Posts:
    2
    Thanks it works like a charm!
     
  32. reubengann

    reubengann

    Joined:
    Jun 1, 2016
    Posts:
    7
    I have what is probably a stupid question. The while node has the following description "The while node has two children: the first one is the condition and the second one is the action. It repeats the condition and runs the action unless the condition fails. The action is started after the first success of the condition. It succeeds if the action succeeds and it fails when any child fails." This is confusing, because if the node succeeds then clearly it's not continuing to repeat the action, right? When it succeeds it kicks success up the tree. So I have a sequence

    Code (CSharp):
    1. tree("BeforeMetEgo")
    2.     sequence
    3.         while
    4.             IsNounVerbCount("FRONT_DESK", "WALK", 0)
    5.             sequence
    6.                 Wait(0.2f)
    7.                 DebugLog("It's zero")      
    8.         StartConversationWithEgo()
    9.         tree("InitialGreeting")
    10.         tree("Dialog")
    As soon as IsNounVerbCount returns true, the sequence is run once and then the line StartConversationWithEgo() runs, which is not what I expect. It sounds like the sequence under the while should repeat until the condition is not true. What am I missing?
     
  33. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @reubengann
    I know it's confusing but the 'while' node in Panda, contrary to the 'while' loop in C#, does not repeat the action. It repeats only the condition. The 'while' node is used to run (not to repeat) an action under a guarding condition. For, instance:
    Code (CSharp):
    1. tree("DriveHome")
    2.        while HasGas
    3.              sequence
    4.                  StartEngine
    5.                  MoveToLocation("Home")
    6.                  StopEngine
    The sequence will execute only once; when we reach home, we are done. So when we reach home, we are not turning the engine on and off until the tank is empty, no. However, if, while we are driving home, we run out of gas, the tree("DriveHome") fails, and we would have to reach home on foot...

    If you want to do repetition while a condition is true, you need to combine the 'while' node with the 'repeat' node:
    Code (CSharp):
    1. while IsDirty
    2.     repeat
    3.         sequence
    4.             Wash
    5.             Rince
    So, we keep repeating wash & rince while it is dirty.

    I hope that helps to clarify how the 'while' node works.
     
    Last edited: Dec 19, 2016
  34. reubengann

    reubengann

    Joined:
    Jun 1, 2016
    Posts:
    7
    Ok, I think it makes sense. So when does IsDirty get re-evaluated if the repeat is working? Is it every iteration of the sequence? If I had a fallback node there, would IsDirty be re-evaluated after the first success of the fallback's children?
     
  35. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @reubengann
    IsDirty is always evaluated independently of the type of node the second child is. The second child could be a single task, a repeat, a sequence, fallback or another tree, it does not matter, the first node of the while node (the condition) is always ticked.

    I'm not sure what the IsNounVerbCount task does, but it seems you want to wait until it fails to continue with the rest of the sequence. If that's right, your tree should be:

    Code (CSharp):
    1. tree("BeforeMetEgo")
    2.     sequence
    3.         mute
    4.             while
    5.                 IsNounVerbCount("FRONT_DESK", "WALK", 0)
    6.                 repeat
    7.                     Wait(0.2)
    8.         StartConversationWithEgo()
    9.         tree("InitialGreeting")
    10.         tree("Dialog")
    Here we keep repeating to wait 0.2 second while IsNounVerbCount succeeds. The 'mute' node is here to ignore the failure of the 'while' node and guaranties that the 'sequence' will continue, otherwise the failure of the 'while' node will cause the failure of the 'sequence' node and would interrupt it.

    But to make your tree simpler to read, I'd suggest to make a new task WaitWhileIsNounVerbCount that keeps running while the condition is true and succeeds when the condition is false. So your tree would be:
    Code (CSharp):
    1. tree("BeforeMetEgo")
    2.     sequence
    3.         WaitWhileIsNounVerbCount("FRONT_DESK", "WALK", 0)
    4.         StartConversationWithEgo()
    5.         tree("InitialGreeting")
    6.         tree("Dialog")
    7.  
    Is this what you want to do?
     
    Last edited: Dec 20, 2016
  36. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    I'm happy to announce that Panda BT 1.4.0 (Free & Pro) are now available on the Asset Store. It comes with enum support and a new feature for the Pro edition: you can now save and restore the execution state of a BT. It's possible to serialize and deserialize the state if you need to.

    Here is the change log details:

    Core:
    • Added PandaBehaviour.snapshot: The BT execution state can be stored and restored via this serializable property (Pro only).
    • Added support for Enum type in BT scripts.
    • Made enum value selectable from a combo-box in the in-Inspector Editor (Pro only).

    Fixes:
    • Fixed GC allocations in PandaBehaviour.Wait(...) due to boxing into Task.current.item.

    The price of the Pro Edition has dropped from $80 to $30. Happy Christmas!
     
    Last edited: Dec 20, 2016
  37. reubengann

    reubengann

    Joined:
    Jun 1, 2016
    Posts:
    7
    Yes. I had it working with something similar to the first option, but you're right that it makes sense to just define whatever tasks make the tree readable. Thanks
     
  38. cephalo2

    cephalo2

    Joined:
    Feb 25, 2016
    Posts:
    263
    Thanks so much for making a free version so I can decide if I'm worthy before spending money! I've only read the docs so far but it looks straightforward. Looks great!

    I have a question though. My game is a little like chess, and I foretell that some of the tasks that the AI might want to do could take a long time. Is there a way I can insert myself back into a tree where I left off as I calculate little chunks, instead of just hanging the app entirely while the AI thinks?

    I assume the Wait tasks are coroutines. Can I put coroutines in the tree? Does a yield return suspend the tree while unity does other stuff?
     
    Last edited: Jan 19, 2017
  39. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @cephalo2 Thank you. I hope it this tool will help for your project.

    I'm not sure what you want to do here. But a behaviour tree won't hang the app, it's running continuously as the game is running.

    The Wait task (and any other task) is not a coroutine, though it behaves has a coroutine, in the sens that it does not block the execution of the program, but runs over several frames.

    If you want to use a coroutine as a task, it's possible to wrap it in a [Task] method, but it would be more straightforward to write it has a task to begin with. But maybe you already have plenty of coroutines and you would like to reuse them to build behaviour tree? Is this your issue?
     
  40. cephalo2

    cephalo2

    Joined:
    Feb 25, 2016
    Posts:
    263
    For example, lets say I have a routine that has to analyze all the choke points on a world map. It's a beastly calculation. I want to process the task in little chunks so the app doesn't just hang. Then when its all done, I want to do something.

    I guess I could make the subprocessing it's own little tree, like so:

    Code (CSharp):
    1. tree "BeefyProcess"
    2.      while chunksNotFinished
    3.           repeat
    4.                processNextChunk
    then say:
    Code (CSharp):
    1. tree "DoSomethingAfterBeefyProcess"
    2.      fallback
    3.           tree "BeefyProcess"
    4.           doSomething
    EDIT: Now that I think about it, the DoSomethingAfterBeefyProcess tree would have to be ticked on a regular bases. So if I tick manually on the root tree, I would have to keep ticking.
     
    Last edited: Jan 20, 2017
  41. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @cephalo2
    If your concern is about handling heavy computations without blocking the application, the behaviour tree you've defined could help to distribute the load over several frames (or ticks). But that won't be the optimal solution. Such computation is best done by a worker thread, though you would need to process your own data structures since the Unity API is not thread-safe.
     
  42. Bluie

    Bluie

    Joined:
    Nov 14, 2012
    Posts:
    8
    I was trying out Panda BT AI and I was just getting started when i got a error:
    void SetColor(float p1,float p2,float p3) is not defined
    Whatever i did, it didn't matter it was not working.

    I tried to make copies of the files in ChangeColor but something is wrong, On the Panda behavior it says: Status Error, and the colors is not right. Root and sequence is grayed out and SetColor(1.0, 0.0, 0.0) is red.

    Unity 5.5.0 0f3 on Mac/El Cap

    Uppdate:
    It is working now, but I don't know what I did more than restart my computer so a glitch maybe...
     
    Last edited: Jan 26, 2017
    laurentlavigne likes this.
  43. a_horned_goat

    a_horned_goat

    Joined:
    Oct 27, 2016
    Posts:
    1
    I created a WaitRandom extension to the built in Wait task. I thought about using random with multiple Wait() statements, but that would only work for discrete random points, whereas this gives a continuous range. Sharing here for what it is worth.

    Usage:
    Code (JavaScript):
    1. tree("Root")
    2.     sequence
    3.         WaitRandom(0.1, 10.0)
    Source:
    Code (CSharp):
    1.   public class WaitRandomFloatInfo
    2.     {
    3.         public float elapsedTime;
    4.         public float duration;
    5.     }
    6.     /// <summary>
    7.     /// Pick a number in the specified range, wait that number of seconds then succeed.
    8.     /// </summary>
    9.     /// <param name="message"></param>
    10.     [Task]
    11.     public void WaitRandom(float min, float max)
    12.     {
    13.         var task = Task.current;
    14.         var info = task.item != null ? (WaitRandomFloatInfo)task.item : (WaitRandomFloatInfo)(task.item = new WaitRandomFloatInfo());
    15.  
    16.         if (task.isStarting)
    17.         {
    18.             info.duration = Random.Range(min, max);
    19.             info.elapsedTime = -Time.deltaTime;
    20.         }
    21.  
    22.         var duration = info.duration;
    23.  
    24.         info.elapsedTime += Time.deltaTime;
    25.  
    26.         if (Task.isInspected)
    27.         {
    28.             float tta = Mathf.Clamp(duration - info.elapsedTime, 0.0f, float.PositiveInfinity);
    29.             task.debugInfo = string.Format("t-{0:0.000}", tta);
    30.         }
    31.  
    32.         if (info.elapsedTime >= duration)
    33.         {
    34.             task.debugInfo = "t-0.000";
    35.             task.Succeed();
    36.         }
    37.     }
     
  44. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @a_horned_goat
    Thank you! This is an excellent idea and neater than using several discrete Wait tasks with the random node. This WaitRandom task is going to be integrated in the next release.
     
    laurentlavigne, a_horned_goat and ZJP like this.
  45. cephalo2

    cephalo2

    Joined:
    Feb 25, 2016
    Posts:
    263
    I have a quick question. Why is it, when Panda is included in my project, that it takes like 7 minutes to switch to the Android platform? Switching from Android to PC is fast, but PC to android takes forever. Any idea why?
     
  46. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi @cephalo2,
    I've done a test with a project containing only Panda BT free, and it takes ~30 seconds to switch from PC to Android and ~3 seconds to switch from Android to PC. That's seems quiet acceptable. I did the test on an Intel Core I7 @2.4GHz.

    Unity re-imports the assets to adapt them to the targeted platform. Are you sure is not the conversion of your assets that are taking time?

    Here is a tip. When working on several platforms (and with a version control system), duplicate your project directory for each platform. This way you won't need to switch from platform to platform and re-import all the assets each time.
     
  47. devstudent14

    devstudent14

    Joined:
    Feb 18, 2014
    Posts:
    133
    Hello Eric! I started a YouTube channel a couple of weeks ago. I'm making a 'Simple RTS' series and I want to start making videos about AI. I like your asset a lot, and the fact that there is a free version is even better for my viewers (all 18 of them haha). Here's my channel: https://www.youtube.com/channel/UCGs9giq_hL9cTGmuw4EgOvg

    Can you please help me understand something:

    I share my entire project every time I make a tutorial. I started out making viewers type the code they saw on the screen. Then I supplied the scripts but made them copy what I did to set the scene up. Now I just supply everything and talk them through the logic it of it all. Since Panda BT is free, can I share that in my tutorial project, or would you prefer that I show them how to download it? I'll direct them to your Asset Store page anyway of course. I've got a feeling that they should download it themselves, but I just want to hear it from the horse's (lama's?) mouth :)
     
  48. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi @mattockman,

    Great that you're going to use Panda BT in your tutorials! I'm curious to watch them. I'm your 20th subscriber.

    I think it would be best to not include the package within your projects and invite your viewers to download the package from the Asset Store instead. It's mentioned in the Unity's EULA , unless that you've obtain a permission from Unity, that you should not make any asset on the Asset Store available from somewhere else. Also, it would be better for me to keep track of the stats.

    Keep these great videos coming!

    Cheers,

    (from the lamb's mouth)
     
    devstudent14 likes this.
  49. devstudent14

    devstudent14

    Joined:
    Feb 18, 2014
    Posts:
    133
    Thanks a lot Eric! That's what I thought. I feel slightly silly for asking but I just wanted to be sure. When in doubt, ask the Lamb :)

    Thanks a lot for subscribing! I know my programming videos won't be much use to you, but I plan on making quite a few AI videos with your system. I still have a lot to learn, so I'll be posting here for some critical feedback every time I make a new behaviour. I hope I don't become too annoying :)

    I posted a while back about a woodcutter behaviour. I'm going to resurrect that BT and make it my first Panda BT AI tutorial. I'll share the project here before I make/publish the video to be sure that I'm on the right track. It should be ready in two days latest.
     
  50. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @mattockman,

    Sounds great!

    Please do post your behaviours here, that's not annoying at all, I'll be very glad to give you feedbacks.
     
    devstudent14 likes this.