Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[AI SCRIPTING] Panda BT: Behaviour Tree scripting

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

  1. FNDEBOER

    FNDEBOER

    Joined:
    Jan 4, 2017
    Posts:
    2

    I have this exact same problem. Still in PandaBehaviour as of 2022. You can't assign scripts at runtime without things breaking. I tried calling Compile(), I tried calling Reset(), I tried deactivating and activating the parent GameObject which only works in the Editor and not in a build....

    Can you assign scripts at runtime at all? It looks like you can't.
     
  2. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Most of the new features are implemented and there is some polishing left to be done. The beta testing will start this month. I can't make promises; it will be ready when it's ready. But I think a release could be possible by the end of this fall (northern hemisphere).
     
  3. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    At runtime, you don't assign script but use the compile method on the PandaBehaviour component. This method take a string (not a TextAsset). But you can get a string from a TextAsset. For instance:


    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using Panda;
    4. public class RuntimeCompile : MonoBehaviour
    5. {
    6.     public TextAsset script;
    7.  
    8.     private void Start()
    9.     {
    10.         var bt = GetComponent<PandaBehaviour>();
    11.         bt.Compile(script.text);
    12.     }
    13. }
     
    FNDEBOER likes this.
  4. FNDEBOER

    FNDEBOER

    Joined:
    Jan 4, 2017
    Posts:
    2
    Thanks. I thought the Compile() without a parameter would take what is currently in the script variable. This works.
     
  5. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @FNDEBOER
    Actually, it is also possible to assign TextAssets at runtime. In that case you need to call the Apply() method to signal that there is a change after assigning the scripts. For instance:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using Panda;
    4. public class RuntimeAssign : MonoBehaviour
    5. {
    6.     public TextAsset script;
    7.  
    8.     private void Start()
    9.     {
    10.         var bt = GetComponent<PandaBehaviour>();
    11.         bt.scripts = new TextAsset[] { script };
    12.         bt.Apply();
    13.     }
    14. }

    Edit:

    In version 2, the scripts are no more stored as TextAssets, but have their own asset type (PandaBTScript) with the *.pbt extension. This has the advantage to have the BT scripts compiled at import time instead of at runtime. Which dramatically improves the PandBehaviour initialization at runtime. The BT scripts will be also come as compiled if they are stored into asset bundles. However it will be still possible to compile bt scripts at runtime if that's required, for instance if the bt script source is generated at runtime:

    Code (CSharp):
    1. using UnityEngine;
    2. using Panda2;
    3.  
    4. public class RunTimeCompile : MonoBehaviour
    5. {
    6.     public TextAsset script;
    7.  
    8.     void Start()
    9.     {
    10.         string source = script.text; // bt source generated at runtime.
    11.         var btscript = PandaBTScript.Compile(source);
    12.  
    13.         var bt = GetComponent<PandaBehaviour>();
    14.         bt.scripts = new PandaBTScript[] { btscript };
    15.         bt.Apply();
    16.     }
    17.   }
    This also gives the possibility to compile a script once and re-used on multiple PandaBehaviours, avoiding re-compiling the same script multiple times saving both cpu and memory.
     
    Last edited: Sep 10, 2022
  6. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    100
    I'm really enjoying PandaBT, I love how clean, simple and intuitive it is. Having access to the tick rate is an essential feature.

    I changed the structural node "while" to "if" as I couldn't get used to it, I hope I'll still be able to do that in v2.
    Is there a reason that I'm missing for this decision?

    I'm using this vscode extension to get syntax highlighting in vscode and changed the keyword in there also.
    https://github.com/Aldlevine/panda-language

    Thanks for your work on PandaBT :) and looking forward to v2!
     
    mike6502 likes this.
  7. ericbegue

    ericbegue

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

    Great that you like Panda BT and I hope you'll like version 2 too.

    The "while" node is not to be confused with the while loop in C#, since the "while" node does not repeat the action node. It runs the action node while the condition node succeeds, it does not repeat the action node and when the action node is completed the while node completes as well. That is, the action node is run only once. In Panda BT it has the same meaning as the word "while" in english in sentences like:
    - Dance while there is music. (Stop dancing when the music stops)
    - Drink while you're thirsty. (Stop drinking when you're are no more thirsty).

    However, in order to have the same meaning as the C# while loop, the "while" node is to be combined with the "repeat" node:

    Code (CSharp):
    1. while condition
    2.     repeat
    3.         action
    Why the while node is named this way? While choosing the word for this keep-running-the-action-until-completion-while-the-condition-succeeds-and-interrupt-the-action-as-soon-as-the-condition-fails node, I was aware that it might cause confusions if I choose the word "while". But I couldn't come up with any better word that expresses the same concept; the best candidate was the word "while". Another candidate was the word "until" but it requires to write the condition in a negative form. I've also consider the word "if" too, but it does not really convey this time-passing idea. The word "if" is used to check a condition at a particular point in time, whereas the word "while" is about an on-going action which spans a period of time.

    It's unfortunate that you've choose to rename it "if" because there will be a new node named "if" in version 2. This new node can be used to run an action if the condition succeeds, but it won't fail if the the condition fails. It can be used to run something optional:
    Code (CSharp):
    1. if condition action
    It is the equivalent of the following:
    Code (CSharp):
    1. fallback
    2.    not condition
    3.    action
    and of course there will be a if-else node too:
    Code (CSharp):
    1. ifelse condition thenAction elseAction
    which is the equivalent of:
    Code (CSharp):
    1. sequence
    2.     fallback
    3.         not condition
    4.         thenAction
    5.     fallback
    6.         condition
    7.         elseAction
    (if you have difficulties to read that last one, you understand why the "ifelse" node is required).
     
    Last edited: Oct 1, 2022
    haywirephoenix likes this.
  8. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    As a sneak peak, here is what the AI script from the PlayTag demo looks like in version 2:
    upload_2022-10-1_12-44-57.png

    A few things to notice:
    • Trees can be written using #. For instance instead of `tree "Playtag"` you just write `#PlayTag`. This syntax makes the tree node more distinguishable and makes the whole script lighter on the eyes to read.
    • You can stack nodes on the same line to make the scripts more readable and save some vertical space and indentations.
    • Variables! They are the blue words prefixed with @. They are defined in C# and can be of any type.
    • Expressions. For instance "(!isIt & !IsPlayer)". This allows to write complex conditions in a more compact way.
     

    Attached Files:

    Last edited: Oct 1, 2022
    haywirephoenix and ratking like this.
  9. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    100
    I understand your logic here. I guess it depends on context and how many Ticks the sequence is running for but BT2's "if" and "if/else" totally clears it up.

    This is perfect as the sequence failing was also throwing me and as the BT grows it was starting to look like your example of fallbacks.



    This looks great, so much cleaner; all of those features will be welcome. Feel free to drop me a link if you're looking for testers.
     
  10. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Hi everyone,

    The beta testing of Panda BT 2 has started! If you want to join and have a look at version 2 before the official release, please drop a message on this discord channel.

    https://discord.gg/B698egvUNf

    (You can also PM me on this forum if you don't use discord.)
     
  11. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    This is a nice project! Syntax highlighting does help a lot when editing BT scripts. I've forked the project here:
    https://github.com/ericbeg/panda-language

    and added support for version 2 new features.

    You can download the Visual Studio Code extension here:
    https://github.com/ericbeg/panda-language/releases/download/v0.0.3/panda-language-0.0.3.vsix
     
    haywirephoenix and mike6502 like this.
  12. w34edrtfg

    w34edrtfg

    Joined:
    Nov 23, 2014
    Posts:
    72
  13. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @w34edrtfg
    Thank you for reporting this typo, it's fixed. Details are important ;)
     
  14. shadiradio

    shadiradio

    Joined:
    Jun 22, 2013
    Posts:
    83
    @ericbegue I have used Panda BT free in a previous project, and I really enjoyed its design - both the c# attribute [Task] syntax and the simple text-based scripting.

    I am actually wondering how tightly coupled the core is with Unity? I'm considering purchasing the Pro version for full access to the source because I'd like to use it in another non-Unity, c# project. I realize I won't have the benefits of all the monobehaviour realtime functionality, but I'm wondering if the core behavior tree and text parsing is self contained. Thanks for your time!
     
  15. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @shadiradio The core of Panda BT has no dependency with the Unity API. Though, I've never used it from another environment than Unity. But I'm quiet confident it would work independently of Unity with little effort. I've started the core project from pure C# .Net project and kept a separation layer from Unity. This makes it easier, from a software engineering perspective, to keep the code base maintainable.

    Internally the PandaBehaviour component is a wrapper around the BTProgram class, which is responsible for handling an executable BT Tree and this class has no dependency with Unity. The parser and compiler are also standalone.

    As you already mentioned, all the runtime visualization is done through the Unity Inspector and the IMGUI api. So this part is obviously dependent on Unity.

    You can PM me (on this forum or on discord) if you need more details.
     
    Last edited: Nov 2, 2022
    shadiradio likes this.
  16. ryanrich90

    ryanrich90

    Joined:
    Feb 11, 2018
    Posts:
    4
    @ericbegue I wonder how hard it would be to add support for something like this to Rider - might investigate :)
     
  17. shadiradio

    shadiradio

    Joined:
    Jun 22, 2013
    Posts:
    83
    Thanks for all the details, much appreciated @ericbegue! I actually started working on my own BT, and while it was working, I may actually start the project over in Unity and just pick up Panda Pro. Thanks again for all your hard work.
     
  18. ryanrich90

    ryanrich90

    Joined:
    Feb 11, 2018
    Posts:
    4
    Hello,

    I've read through this forum and my question looks asked a couple of times now but didn't see any solution yet.

    How can the weights for the random node be dynamically set? Perhaps using Panda BT v2 you could use variables for this? Any ideas how it can be done for v1? I was thinking of creating a custom task for this, but I cannot call structural nodes from C# code, unless I'm mistaken.

    @laurentlavigne I see you answered this type of question a while ago, but I don't understand this solution https://forum.unity.com/threads/ai-...our-tree-scripting.388429/page-9#post-3361748
     
  19. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Yes, in Panda BT v2, it is possible to use variables to set dynamic weights for the random node.
    Variables are prefixed with the `@` character from the BT Script:

    Code (CSharp):
    1. random @Weight_1 @Weight_2 @Weight_3
    2.     Task_1
    3.     Task_2
    4.     Task_3
    and defined from C# using the [PandaVariable] attribute:
    Code (CSharp):
    1. using UnityEngine;
    2. using PandaBT;
    3.  
    4. public class DynamicWeights : MonoBehaviour
    5. {
    6.     [PandaVariable] public float Weight_1 = 0.1f;
    7.     [PandaVariable] public float Weight_2 = 0.2f;
    8.     [PandaVariable] public float Weight_3 = 0.7f;
    9. }
    10.  
    Of course, these variables can be modified at any time.

    It's not possible to write custom control node. However, it is possible to write a task that decides which tree or trees to run (and how to run them). You can retrieve a tree by name from the `PandaBehaviour` component by using the `GetTree` method. Then, you can run one or more trees using a custom algorithm:

    Code (CSharp):
    1. using UnityEngine;
    2. using PandaBT;
    3. public class TreeSelector : MonoBehaviour
    4. {
    5.     public PandaBehaviour bt;
    6.     [PandaTask]
    7.     void RunSelectedTree()
    8.     {
    9.         string treeName = null;
    10.         // decide which tree to tick
    11.         // treeName = ?
    12.         // ...
    13.         PandaTree tree = bt.GetTree(treeName);
    14.         tree.Tick();
    15.         var status = tree.status;
    16.         // Handle the returned status of the selected tree
    17.         // ...
    18.     }
    19. }
    20.  
    That would be very similar to custom control node. I've used this mechanism to experiment with GOAP: a task was responsible to execute a plan (a dynamic sequence of actions, where each action is implemented as a tree).

    Version 2 is currently in beta-testing (check this discord channel). Let me know if you want to give it a try.
     
    Last edited: Nov 7, 2022
    laurentlavigne likes this.
  20. ryanrich90

    ryanrich90

    Joined:
    Feb 11, 2018
    Posts:
    4
    @ericbegue I appreciate the response. I suppose GetTree could work, but then that means needing to create a custom task which decides which tree to tick through code, which I guess obscures the readability of the BT a little. It also forces each child node to have to be a tree instead of just being a custom task or node.

    Perhaps using V2 will just be easier! I'll reach out.
     
  21. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,994
    This is cool. Love the facile syntax and attributes.
    It seems that, now with variables, you can add Utility selector.
     
  22. ryanrich90

    ryanrich90

    Joined:
    Feb 11, 2018
    Posts:
    4
    For those using Rider, I investigated a little and while the plugin process is quite complex with a feature-rich SDK, I got most of what I was looking for by using a custom File Type. Here's how I set it up:

    Preferences -> Editor -> File Type -> Add new File Type

    panda-bt-file-type-rider.png

    For the file name pattern, use *.BT.txt or any suffix that differentiates from regular .txt files
    For those using the V2 beta, can use *.pbt

    It's pretty nice as you can add all the structural nodes to the Keywords list and any custom PandaTasks you have and it'll give you syntax highlighting and autocompletion!

    For more information about this see https://www.jetbrains.com/help/rider/Creating_and_Registering_File_Types.html#create-new-file-type
     
    Ruufer, ericbegue and laurentlavigne like this.
  23. Ruufer

    Ruufer

    Joined:
    Jul 28, 2016
    Posts:
    17

    thanks for this!
     
  24. ko-de

    ko-de

    Joined:
    Apr 15, 2019
    Posts:
    7
    Love PandaBP but migrated to godot 4 and wont look back. Any chance to get Panda for godot? Sry but there was no other contact on the website than this…
     
  25. ILVI_

    ILVI_

    Joined:
    Sep 2, 2021
    Posts:
    1
    Hello,

    Love Panda BT, but recently ran into big performance issues. In my game, when I spawn a single enemy, the panda script takes 51 ms to compile in just one frame... Not to mention that I need to spawn dozens of enemies, and this happens on every instantiation. The script itself isn't incredibly large and contains only 9 BT.txt files.

    Here is a screenshot of a deep-profiled game build:
    Screenshot_1.png

    All of those peaks are the enemy instantiations. Needless to say, this makes the game hardly playable :(

    Any suggestions on how to fix it in Panda version 1? Or at least to make some workaround, like compiling the script once and copying it (tried, didn't work)?
     
  26. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,994
    Yeah it's awful. try beta 2, it's on his discord. I think it fixed that.
    Also in some cases you can precompile and cache scripts, don't recall how, it's in the doc.
     
    ILVI_ likes this.