Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

[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:
    2,060
    Code (CSharp):
    1. tree("ChasePlayer")
    2.     //Chase the player while we are "it".
    3.     //Use the current player position as destination,
    4.     //Then move straight to that destination.
    5.     while IsIt
    6.         parallel
    7.             repeat
    8.                 SetDestination_Player
    9.             repeat
    10.                 MoveToDestination
    notice the two repeats inside parallel, that's how you do it
     
  2. TheRealAlakeram

    TheRealAlakeram

    Joined:
    Dec 12, 2017
    Posts:
    6
    Thank you for your response sir, I was able to get it to work but had to scrap it because the behaviour tree system is way too resource intense, with it I could only get 20 AI on screen and then it started using way too much processing power, when I switched the exact code and removed the behaviour tree I was able to get about 500 units on screen doing the same thing just hardcoded instead of using the BT so I think this is off the table unless someone knows a way to cut back the processes required
     
  3. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,060
    Show me the Panda code and the hardcode conversion.
    There shouldn't be much overhead, negligible compared to raycast and pathing.
     
  4. TheRealAlakeram

    TheRealAlakeram

    Joined:
    Dec 12, 2017
    Posts:
    6
    I deleted the pandatree and don't have the trees that i made, but during testing i couldn't find a way to make the tree trigger the follow function at a set interval like i can with my hardcoded follow, with it hard coded I just set a invokerepeat to constantly check every 1 to 2 seconds to make sure the AI was in range of the target.

    When i tried the same theory with pandatree he would follow the target but then for some reason have a long delay between rerunning the behaviour.

    or if he was within range and the target moved he would just stop running that part of the tree all together

    and when i tried the repeating function on the tree it would be extremely resource intense and unable to run more then 20 AI at the same time. I'm not sure if it was my own fault for not knowing how to use it, or if its a type of leak with pandatree that just eats resources on repeat

    Could have also been because I'm making a multiplayer game and I had the AI constantly checking for players, which i had that issue with the hardcoded version but i just moved the searchfortags function to a one time trigger for all players and then as the players die off i ran a for loop to remove them from the list of active players
     
  5. BitsAtPlayDev

    BitsAtPlayDev

    Joined:
    May 5, 2013
    Posts:
    11
    Testing out PandaBT and also ran into the issue of "isStarting" always being true.

    Any clarification on this? Is this a bug or me not understanding something?

    Thanks
     
  6. Crouching-Tuna

    Crouching-Tuna

    Joined:
    Apr 4, 2014
    Posts:
    36
    Hi all. My Panda's inspector LiveView is not updating every 2nd play. I have to restart Unity to make it work again each time.
    Anyone know the cause?

    Also, I'm making a 2D platformer, on which I'm recreating my hardcoded movement steering to Panda. Slowly working on it. Pathfinding is using A* Waypoints, each node connection got a context like "Walk", "JumpSide" etc. I need to handle the small details in movement such as jump has to be done from the origin node to properly jump on top of the obstacle.

    My Panda BT is really broken into many small trees, often because I have to convert some parts to tree to be able to mute them ( Can't mute while or mute sequence)

    Code (CSharp):
    1. tree("MoveToDestination")
    2.     sequence
    3.         MoveTo_Destination
    4.         parallel
    5.             sequence
    6.                 GetCurPathDists
    7.                 mute ReachedCheckPoint
    8.             fallback
    9.                 while HasPath
    10.                     fallback
    11.                         tree("Walk")
    12.                         tree("JumpSide")
    13.                         //tree("JumpUp")
    14.                         //tree("JumpDown")
    15.  
    16.                 tree("LastWalk")
    17.                 Succeed
    18.    
    19.  
    20. tree("Walk")
    21.     while IsNextWaypointWalk
    22.         tree("WalkToNext")
    23.  
    24.  
    25. tree("JumpSide")
    26.     while
    27.         IsNextWaypointJumpSide
    28.    
    29.         parallel
    30.             mute tree("GetToJumpSpot")
    31.             mute tree("AirWalk")
    32.             mute tree("JumpFromSpot")
    33.             tree("MissedJump")
    34.  
    35. tree("GetToJumpSpot")
    36.     while
    37.         sequence
    38.             NearOriginX
    39.             IsCanJump
    40.         tree("WalkToOrigin")
    41.  
    42. tree("AirWalk")
    43.     while
    44.         sequence
    45.             not IsCanJump
    46.             not IsGrounded
    47.         tree("WalkToNext")
    48.  
    49. tree("JumpFromSpot")
    50.     while CloseToOrigin
    51.         tree("JumpAction")  
    52.  
    53.  
    54. tree("JumpAction")
    55.     while
    56.         sequence
    57.             IsGrounded
    58.             IsCanJump
    59.             NearOriginX              
    60.         JumpUpAction
    61.  
    62.  
    63. tree("MissedJump")
    64.     fallback
    65.         while
    66.             sequence
    67.                 not IsGrounded
    68.                 not AboveTarget
    69.                 IsFalling
    70.             Fail
    71.         Succeed
    72.  
    73. tree("JumpUp")
    74.     Succeed
    75.  
    76. tree("JumpDown")
    77.     Succeed
    78.  
    79. tree("WalkToNext")
    80.     fallback
    81.         while IsNextLeft
    82.             WASD(-1,0)
    83.         while IsNextRight
    84.             WASD(1,0)
    85.  
    86. tree("WalkToOrigin")
    87.     fallback
    88.         while IsOriginLeft
    89.             WASD(-1,0)
    90.         while IsOriginRight
    91.             WASD(1,0)
    92.  
    93.  
    94. tree("LastWalk")
    95.     fallback
    96.         while not ReachedDestination
    97.             sequence
    98.                 AdjustSpeed
    99.                 tree("WalkToNext")
    100.         sequence
    101.             ClearLeftRight
    102.             Succeed
    103.  
    104.  
    I hope I'm approaching this right.. JumpUp / Down is not done yet
    My old hardcoded is much detailed than this, but it's just very hard to follow that I decided to rework it in BT..

    Cheers

    edit:
    Sometimes I need to mute while.
    In pseudo-code it'd be like:

    Code (CSharp):
    1. DoWalk();
    2. if(haveDashSkill)
    3.      DoDash();
    4. DoOtherStuff
    A while node would cancel the sequence with a fail. If I want to mute while, I'll have to make a new tree and mute that tree.
    Can't I just mute the while? The only workaround is to use fallback for each
    Code (CSharp):
    1.  
    2. sequence
    3.      fallback
    4.           while haveDashSkill
    5.                    DoDash
    6.           Succeed
    7.      DoOtherStuff
     
    Last edited: Sep 20, 2018
  7. delgelato

    delgelato

    Joined:
    Jan 12, 2017
    Posts:
    1
    Hello,

    I just cloned my project to another PC, and I'm getting this error in the editor (not playing):
    Error parsing script. See console for details

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. Panda.BTNode.get_parameterTypes () (at <674062e0bb4c4af8a588c898a06dd65b>:0)
    3. Panda.TaskImplementation.IsMatch (Panda.BTTask task) (at <674062e0bb4c4af8a588c898a06dd65b>:0)
    4. Panda.BTRuntimeBuilder.Bind (Panda.BTProgram program, System.Object[] implementers) (at <674062e0bb4c4af8a588c898a06dd65b>:0)
    5. Panda.BTProgram.Bind (System.Object[] objects) (at <674062e0bb4c4af8a588c898a06dd65b>:0)
    6. Panda.BehaviourTree.CreateProgramAndBind () (at <674062e0bb4c4af8a588c898a06dd65b>:0)
    7. UnityEngine.Debug:LogException(Exception, Object)
    8. Panda.BehaviourTree:CreateProgramAndBind()
    9. Panda.BehaviourTree:Compile()
    10. Panda.BehaviourTreeEditor:OnInspectorGUI()
    11. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    It tells me nothing more..
    If only assigned 1 text file, it shows the content (with the error of not able to find "Root" or so), but if I assign all dependant behavior text files, they don't show its content in the inspector and all of the text file shows the error message under them
    In my first computer it works fine. Double clicking in the console also does nothing.
    I wonder what's wrong?

    Edit:
    Taking the example works fine in the new PC but every timer related task is 10x longer ( Wait(0.2) is 2 seconds, Wait(2.0) is 20 seconds )
    I'm not sure if this is related.
    I checked Time in project settings and it's 1..
    I think it's related to text formatting?
    In this computer it's not detecting any period (.) in float parameters anywhere. So 0.105 just means 105.
    Also removed any (.4) without preceding 0 (this was causing the error before). But still, why is it not detecting any period ?
     
    Last edited: Oct 11, 2018
  8. brad-bit

    brad-bit

    Joined:
    Mar 26, 2015
    Posts:
    5
    Hi! I got 1.4.2 and there seems to be a particularly nasty bug... float numbers don't parse in some locales.

    "Wait 2.0" gives the errors:
    The task `void Wait( )` is not defined
    The task `void 2.0( )` is not defined


    This is very likely because Panda's number parsing code uses a non-invariant culture, which is inappropriate for code. I'm in a Finnish locale, where a comma is used as the decimal separator instead of a dot. You need to specify invariant culture or 2.0 would not be recognized by e.g. float.Parse here. To make things worse it's not possible to use the local format either, because "Wait 2,0" is interpreted to be a two-parameter call:

    The task `void Wait( int p0, int p1 )` is not defined


    The fix should be simple, replace all float.Parses etc. with float.Parse(s, CultureInfo.InvariantCulture).
     
  9. giotta

    giotta

    Joined:
    May 31, 2015
    Posts:
    39
    PandaScriptException: Tree node has too many children. Only one is expected in file 'Troll.BT': line 1

    why do I keep getting this error?
    What may be the causes?
     
  10. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,060
    Check your formatting, some times I edit the BT script and break the tab format.
    More that that, copy paste your BT code here so someone can fix it.
     
  11. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    @brad-bit

    Most programming languages are based on english and use the dot character as decimal separator. As you have mentioned, it would make the parsing ambiguous by supporting the local. Are do you handle decimal while coding in C#? You also use the dot character there, right?
     
  12. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    @giotta

    Are you sure you are not placing several children under the tree node? Because that would trigger this error: the tree node accepts only one child.

    If that's not the problem, it must be a indentation issue. I suggest enabling the non printable characters (spaces and tabs) in your text editor to make it easier to check whether the indention is correct.
     
    Last edited: Nov 17, 2018
  13. mblissmer

    mblissmer

    Joined:
    Aug 18, 2015
    Posts:
    1
    @ericbegue hey there! Just testing out this asset, and really its my first time using behavior trees in general, so I apologize if this is a dumb question.

    I have a little character that I want to stand around for a few seconds before getting bored and running/walking to a random spot.

    What's weird is, this script works fine, it waits for x seconds (2, in this case), and then randomly chooses the running or walking sequence. But then RandomDestination and IldeMove *immediately* succeed, and it cycles back to Waiting.

    RandomDestination will stay as the active one running if I remove the call to my PointToPoint script that calls for a new move (ptp.MakeNewMove()). I have no idea why calling this would make the task succeed. the PTP script doesn't interact with tasks in any way. Also, even if that was somehow getting past that, IdleMove is empty. Shouldn't it just sit on IdleMove?

    I'm completely lost and I assume I'm doing something wrong. I can provide more info if needed. I really appreciate any help.

    Code (CSharp):
    1. tree "Root"
    2.     fallback
    3.         tree "Eating"
    4.         tree "Petting"
    5.         tree "Playing"
    6.         tree "Bored"
    7. tree "Bored"
    8.     sequence
    9.         Waiting
    10.         random
    11.             sequence
    12.                 RandomDestination 0 // running
    13.                 IdleMove
    14.             sequence
    15.                 RandomDestination 1 // walking
    16.                 IdleMove
    17.             // sequence
    18.             //    TakeNap
    19.             //    Napping
    20. tree "Eating"
    21.     Fail
    22. tree "Petting"
    23.     Fail
    24. tree "Playing"
    25.     Fail
    Code (CSharp):
    1.  
    2.     [Task]
    3.     void Waiting() {
    4.         if (Task.current.isStarting) boredTimer = 0;
    5.         if (boredTimer < boredMaxTime) {
    6.             boredTimer += Time.deltaTime;
    7.         }
    8.         else Task.current.Succeed();
    9.     }
    10.  
    11.     [Task]
    12.     void RandomDestination(int speed) {
    13.         if (Task.current.isStarting) {
    14.             if (speed == 0) ptp.UseAltSpeed();
    15.             else ptp.UseFullSpeed();
    16.             ptp.MakeNewMove();
    17.         }
    18.         if (ptp.moving) Task.current.Succeed();
    19.     }
    20.  
    21.     [Task]
    22.     void IdleMove() { }
    23.  
     
  14. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13

    In first, you can to use a built-in task Wait(float time) instead your own Waiting() .
    In second, I think, you should to change your IdleMove task. It should return a Succeed when the player is near the destination point.
    Something, like below:


    Vector3 characterPosition;
    Vector3 destionationPoint;
    [Task]
    void IdleMove()
    {
    if (Vector3.Distance(characterPosition, destionationPoint) <= 5.0f)
    {
    Task.current.Succeed();
    }
    }

     
  15. psm1782

    psm1782

    Joined:
    Nov 18, 2018
    Posts:
    1
    Hi Eric,
    I'll consist My Project with your Panda BT, but I have a question.
    Can I assign [Task] property to virtual Method? And so, can I use inherited class to Panda BT?

    This is not a big question, but nobody said about it. Please let me know this information.

    Thanks.
     
  16. Ald_levine

    Ald_levine

    Joined:
    Jan 6, 2014
    Posts:
    1
    Hi all,

    I've just started using Panda BT for my game and so far it's great! However, the lack of editor support makes writing/reading the code a bit difficult, so I created an extension for VSCode that supports basic syntax highlighting. I will see if I can implement IntelliSense sometime in the future, but that may be a long ways off.

    I would have created the extension for Visual Studio, but it's a lot more involved and I wanted to get something I could work with done quickly.

    I figured it might be useful to others, so I made the extensions avilable here: https://github.com/Aldlevine/panda-language. It's not currently on the VS Marketplace (MS doesn't exactly make that part easy...), but the readme provides simple instructions for manual installation both from source and from the prebuilt VSIX file.

    If anyone has questions/issues regrading the extension, please submit issues on Github.
     
  17. mdookie4

    mdookie4

    Joined:
    Jun 15, 2017
    Posts:
    8
    Hi Eric,
    I 've being looking around for a compatible Behavior Tree solution that is able to work with the following components;
    1) Unity 2D top down using Physics2D
    2) Aronberg A* pathfinding
    Do you foresee any issues with PandaBT in terms of movement interactivity with the above items?
    Thanks!
     
  18. Sharlatan

    Sharlatan

    Joined:
    Jul 23, 2013
    Posts:
    111
    Hello Eric

    This looks like a great extension!
    One question: The description sounds like I could seamlessly replace the pro version with the free version; it just has less convenience features, right?

    I'm asking because the pro version will certainly be more convenient for development but I'm currently working on a project that I might make open source in the future and so it wouldn't only be usable by people that buy the pro version, it would be great, if I could develop with the pro version but it could seamlessly be replaced with the free version for open source distribution.

    Thanks and have a nice day
     
  19. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    I think, you are right. I didn't noticed something not compatipbe with the free version of the Panda BT. I use the Pro version. It has functions important for debugging.
     
    Sharlatan likes this.
  20. Sharlatan

    Sharlatan

    Joined:
    Jul 23, 2013
    Posts:
    111
    Thank you very much, that's useful to know!
     
  21. TPEUnity

    TPEUnity

    Joined:
    Jan 17, 2018
    Posts:
    18
    Hi. While inspecting Panda Behavior in the inspector im experiencing massive slowdown. I checked with profiler and it seems to be caused by InspectorWindow.DrawEditors(). If i inspect anything without Panda attached to it or remove the script everything runs just fine. Normally EditorOverhead stays around 30% but while inspecting Panda script its 80%. Anyone else experienced this or knows what could fix it?
    Im using 2018.2.13f1 version of unity. I've attached picture of the editor profiler if it makes more sense to someone.
     

    Attached Files:

  22. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    Hmm... I don't see the issue at all.. I don't see the row "InspectorWindow.DrawEditors()" in the profiler too. Mayby, it's a characteristic feature of your panda script...
     
  23. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    Yes, you can substitute the pro version with the free version and expect your game to work the same.
     
  24. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    Eric,is any possibility to get a new version of your Panda Behaviour ? The latest version has few bugs:(
     
  25. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    @Zinev
    The next version will include the following fixes:

    - Fixed BT not initialized when PandaBehaviour component is attached at runtime
    - Fix debugging breakpoints not pausing when bt is ticked on FixedUpdate or LateUpdate

    Do you have other bugs to report?
     
  26. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    @ericbegue
    The most disappointing bug for me was described below:

     
  27. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    I could reproduce this bug on my side. This is due to the C# float parse method using the local culture.That will be fixed in the next release.
     
  28. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    I'm happy to announce that Panda BT 1.4.3 is now published on the Asset Store.

    Here is the change log:

    Core:
    • Renamed "Tree" to "PandaTree" to avoid name collission witn Unity built-in class.
    Fixes:
    • Fixed BT not initialized when PandaBehaviour component is attached at runtime.
    • Fix debugging breakpoints not pausing when bt is ticked on FixedUpdate or LateUpdate.
    • Fix PandaBehaviour.GetTree generating GC Allocs.
    • Fixed float parser using local culture and causing errors.
     
  29. Crouching-Tuna

    Crouching-Tuna

    Joined:
    Apr 4, 2014
    Posts:
    36
    Sorry this is quite a bump but was really interested in Utility and this didn't get replied.
    Have you tried:

    Code (CSharp):
    1.  
    2. while TickChosenTree
    3.     sequence
    4.         UpdateStats
    5.         UpdateBT
    6.         Wait(1.0)
    Also, thanks for update! Really needed that float.parse bug fix

    edit:
    Nvm this would .isStarting TickChosenTree every frame, exactly your problem on the next post...
     
  30. MastermindInteractive

    MastermindInteractive

    Joined:
    Jun 13, 2014
    Posts:
    86
    I'm having a hard time understanding this implementation of behavior trees. My confusion is mostly around the while and repeat nodes.

    What are best practices for using While and Repeat?
    Should I only use repeat for things I want to happen more than once in a while condition?
    Should I bypass using while if I only want the agent to perform the actions once?
    What's better - using a while and repeat to do something multiple times or bypass them completely and just allow the whole tree run over and over again? For instance, couldn't you make an agent shoot repeatedly without using while and repeat and just having it fail so that the whole tree repeats itself?

    Sorry if these are redundant questions but these are my main sticking points with getting up and running.

    Am I on the right track with the the tree below or am I overusing the while node?

    Code (CSharp):
    1. tree("Root")
    2.     fallback
    3.         // Die
    4.         while
    5.             not Alive
    6.             Succeed
    7.         // Alert - Fallback
    8.         while
    9.             fallback
    10.                 HealthLow
    11.                 // NoAmmoInInventory
    12.             fallback
    13.                 Succeed
    14.         // Alert - Attack
    15.         while
    16.             sequence
    17.                 CanSeeTarget
    18.                 not HealthLow
    19.                 // not NoAmmoInInventory
    20.             fallback
    21.                 Succeed
    22.         // Search
    23.         while
    24.             sequence
    25.                 not CanSeeTarget
    26.                 not CanHearTarget
    27.                 not HealthLow
    28.                 // not NoAmmoInInventory
    29.             fallback
    30.                 Succeed
    31.         // Guard
    32.         while
    33.             sequence
    34.                 not CanSeeTarget
    35.                 not CanHearTarget
    36.                 not HealthLow
    37.             fallback
    38.                 Succeed
     
  31. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    For first, While in the Panda BT has not the same sense than While has in C#. While in the Panda BT doesn't parform task. It's obviously, when uncheck the "Repeat root". Thus, While and Repeat are not opposite tools.

    For second, in your example above, using While keyword is redundant. Use the Sequence or Fallback
    You can use something like next code instead of your one:

    Code (CSharp):
    1. parallel
    2.    
    3.  
    4. tree("Root")
    5.     fallback
    6.         // Die
    7.         Sequence
    8.             not Alive
    9.             Succeed
    10.         // Alert - Fallback      
    11.             fallback
    12.                 HealthLow
    13.                 // NoAmmoInInventory
    14.           // Alert - Attack
    15.            sequence
    16.                 CanSeeTarget
    17.                 not HealthLow
    18.                 // not NoAmmoInInventory
    19.            
    20.         // Search      
    21.             sequence
    22.                 not CanSeeTarget
    23.                 not CanHearTarget
    24.                 not HealthLow
    25.                 // not NoAmmoInInventory          
    26.  
    27.  


    For third. I want to tall about my experience in using While and Repeat.

    If you want simply do something multiple times you should to verify only is the "Repeat root" checked.
    Repeat repeats executing of tasks when the "Repeat root" is uncheked. Or when you want to repeat branches independently each from other. Something like below:
    ...
    Code (CSharp):
    1. parallel
    2.      repeat tree("First")
    3.      repeat tree("Second")
    ....

    And about while.
    My pattern of using While in the next ( The "Repeat root" is unchecked, by the way).

    Code (CSharp):
    1. fallback
    2.      fallback
    3.             repeat
    4.                 while Condition
    5.                     tree("First tree")
    6.             repeat
    7.                 sequence
    8.                     not Condition
    9.                     tree("Next tree")
    What the example above does?
    Suppose, the tree("First tree") do something during a long time. For example 10 seconds.
    The While allows to stop an executing of tree("First tree") when the Condition is false immediately and go to the next task or tree (tree("Next tree") in our example).

    If we would use something like:

    Code (CSharp):
    1. repeat
    2.          sequence
    3.                    Condition
    4.                     tree("First tree")
    The Panda BT :
    • checks the Condition
    • if the Condition is true it goes to the tree("First tree"). If the Condition is false it goest to tree("Next tree")
    • executes the tree("First tree") during the 10 second
    • returns to the Condition again.
    In other words, The Panda BT waits when the tree("First tree") will be full completed and only after checks the Condition again in the example above.

    Sorry for my poor English.
     
    Last edited: Apr 3, 2019
    MastermindInteractive likes this.
  32. devstudents

    devstudents

    Joined:
    Feb 18, 2014
    Posts:
    132
    Hello,

    I've got an issue with my panda behaviour tree. One of my tasks is a simple counter which goes from 5 to zero -= Time.DeltaTime. For some reason, the children are firing even though the countdown timer has not reached 0. The children are in a sequence node. The counter timer does not succeed until the counter is <= 0. A debug.log statement in the next child is firing even though the counter is still greater than 0. What have I missed?
     
  33. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    Please, share your Panda BT script and the counter task. It will help to solve the issue.
     
  34. Yukken

    Yukken

    Joined:
    Jul 12, 2015
    Posts:
    46
    Been playing with for a few days. Definitely like it so far. A few questions:

    1. Any way to have variables(such as floats) that are exposed in the panda behaviour component? I don't want to hardcode the wait duration for a particular behaviour tree asset.

    2. From what I understand, sequence and fallback can double as && and || in conditions. But I'd still appreciate it if there was a way to allow both to create complex conditions.

    3. Is there any restriction that the method referenceed in a panda behaviour component needs to be on the same gameobject?

    4. Similarly, is there any way to specifically mention which gameobject it will use?
     
  35. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    1. You can use simple a public C# variable for it in your file that contains behaviour tasks.
    2. Sorry, but I don't understand your question. What do you mean?
    3. Yes, there is the restriction. As I know, you should add the script with tasks to the same Panda component that uses the tasks.
    4. Sorry again, I don't get clear question. Can you write your question with addition details?
     
  36. Yukken

    Yukken

    Joined:
    Jul 12, 2015
    Posts:
    46
    Ques 2: Basically, I'm saying that in c# you do this:

    Code (CSharp):
    1. if(condition1 && condition2 || condition2)
    2.      doSomehting()
    In panda bt you can replicate that conditional by using sequence nodes instead of && and fallback instead of || which is awkward.
    Ques 4(Rephrased): Is there any way for the panda component to link a function call to a gameobject I specify(or set in the inspector)? But based on your answer it's probably not possible.
     
  37. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13

    Ques 2.
    Yes, you can.
    Code (CSharp):
    1. tree("Root")
    2.     sequence
    3.         fallback
    4.             sequence
    5.                 condition1
    6.                 condition2
    7.             condition2
    8.         doSomehting
    9.  
    Quest 4.
    Yes, you can do it too
    Here is a short example.
    The C# script
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using Panda;
    4.  
    5. public class netTask : MonoBehaviour
    6. {
    7.  
    8.     public GameObject targetGameObj;
    9.    public  float speed=1.0f;
    10.  
    11.     [Task]
    12.     void MoveTargetObj()
    13.     {
    14.         targetGameObj.transform.Translate(Vector3.right * speed * Time.deltaTime);
    15.     }
    16.  
    17.  
    18. }
    19.  
    The appropriate BT script

    Code (CSharp):
    1. tree("Root")
    2.     sequence
    3.         fallback
    4.             sequence
    5.                 condition1
    6.                 condition2
    7.             condition2
    8.         doSomehting
    Attach the C# script and the BT script to an empty game object. After, set other game object for the targetGameObj field. You can specify the speed too.
     
  38. unity_PJQFq87ckSe_qA

    unity_PJQFq87ckSe_qA

    Joined:
    Dec 22, 2017
    Posts:
    4
    Hi, I've just started to use the free version of Panda BT and it's been great so far but I do have a question on how to prevent a tree from running while a task is incomplete. The only thing I'd compare my desired result to is an ienumerator with a:
    Code (CSharp):
    1. yield return new WaitUntil(() => condition);
    So far I have:
    Code (CSharp):
    1. tree("Root")
    2.     FallBack
    3.         while SeeInteractable
    4.             sequence
    5.                 MoveToTarget
    6.                 OpenChest
    7.         while not SeeInteractable
    8.             sequence
    9.                 PickNextWaypoint
    10.                 MoveToWaypoints
    I'd like to pause the tree in order to allow the player to perform an action in "OpenChest". How is this possible?
     
  39. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    Here are few ways to do it. One of them - use a flag. When the flag will be set true you should run the Task.current.Succeed() .
    In the short example below the task OpenChest will be paused the tree until the key T will be pressed.


    Code (CSharp):
    1. using UnityEngine;
    2. using Panda;
    3.  
    4. public class Tasks : MonoBehaviour
    5. {
    6.     [Task]
    7.     void FirstTask()
    8.     {
    9.         //do something
    10.         Debug.Log("First task");
    11.         Task.current.Succeed();
    12.     }
    13.  
    14.     [Task]
    15.     void OpenChest()
    16.     {
    17.         if(Task.current.isStarting)
    18.             Debug.Log("OpenChest  OpenChest");
    19.  
    20.         Debug.Log("OpenChest  running");
    21.  
    22.         if (Input.GetKeyDown(KeyCode.T))
    23.         {
    24.             Debug.Log("OpenChest  completed");
    25.             Task.current.Succeed();
    26.         }
    27.     }
    28.     [Task]
    29.     void LastTask()
    30.     {
    31.         //do something
    32.         Debug.Log("Last task");
    33.         Task.current.Succeed();
    34.     }
    35. }
    The Panda BT script:

    Code (CSharp):
    1. tree("Root")
    2.     Sequence
    3.         FirstTask
    4.         OpenChest
    5.         LastTask
    6.  
     
    unity_PJQFq87ckSe_qA likes this.
  40. unity_PJQFq87ckSe_qA

    unity_PJQFq87ckSe_qA

    Joined:
    Dec 22, 2017
    Posts:
    4
    I would expect this to work but it doesn't, when the branch arrives at the last behavior in the "while SeeInteractable" tree it repeats the tree from root instead of waiting for a input. A lack of success or failure state also re-initiates the tree. What SeeInteractable does is spherecast around the player to check for any objects with an interactable layer are in range and the only interactable in the scene is a chest. My guess is fallback causes the tree to repeat. Your example works as it stops that task from finishing but the navmesh moves around looking for waypoints. I'd like to have it stand still while it waits for a condition.

    Edit: Sorry for populating this thread I found out what was wrong and corrected it. I made a mistake. This does work as expected, thanks for helping me solve the problem Zinev.
     
    Last edited: May 30, 2019
  41. MateoPeri

    MateoPeri

    Joined:
    Oct 19, 2017
    Posts:
    10
    Hi!
    I've been using this asset for a week or so, and I must say that it is very powerful and easy to use. So far I've tried to do a simple enemy AI using the shooting example scene as a guide, but I've run into problems with my Inspect tree (see script below).

    A quick guide of how these BTs work:
    If we haven't detected a player, we patrol (follow the next waypoint) and then inspect (look in 4 directions, 90 degs at a time). Calling inspect here works as intended.
    If we see and detect a player, we "Engage" (chase the player).
    If we have reached the last known position of the player and we don't see him, we Inspect.
    At this point is where the problem is. When calling inspect after engage, the tree runs up to a point (InspectNextAngle) and then resets. This causes the enemy to spin around infinitely.
    I would like my enemy to rotate just like in the gif.

    So far I've found that the problem is caused by Inspect getting called too many times (there is a DebugLog inside Inspect that gets called every frame when called from engage, and only once when called after patrol).
    But I don't know what causes it to call Inspect every frame.
    I still don't fully understand the difference between repeat and while. Maybe that's what's causing the problem.

    I would appreciate any help that you guys could give me. Thanks in advance.

    Inspect being called after patrol (works fine)
    inspect_patrol.gif

    Inspect being called after engage (tree resets every frame)
    inspect_engage.gif

    This is the base enemy script:
    Code (CSharp):
    1. tree("Root")
    2.     parallel
    3.         repeat mute tree("BeAlive")
    4.         repeat mute tree("Die")
    5.         repeat mute tree("Move") // This is another BT, for enemy movement
    6.  
    7. tree("Detect")
    8.     sequence
    9.         DebugLog("detecting sequence...") // This is called every frame
    10.         fallback
    11.             sequence
    12.                 IsPlayerDetected
    13.                 sequence
    14.                     not tree("Engage") // If Engage fails
    15.                     tree("Inspect") // Inspect
    16.             sequence
    17.                 IsVisible_Player // If not visible
    18.                 not IsPlayerDetected // And not detected yet
    19.                 Stop
    20.                 IncreaseDetection // Increase detection level
    21.             sequence
    22.                 not IsVisible_Player // If not visible
    23.                 not IsPlayerDetected // And detection is less than 1
    24.                 DecreaseDetection // Decrease detection level
    25.    
    26. tree("Inspect")
    27.     fallback
    28.         sequence
    29.             IsVisible_Player // If we see the player
    30.             Resume // We continue
    31.  
    32.         sequence
    33.             DebugLog("Inspect sequence") // Should only be called once
    34.             repeat(4)
    35.                 sequence
    36.                     Stop
    37.                     InspectNextAngle // we get the next angle (current + 90 deg)
    38.                     AimAt_Target // We look at it
    39.                     Wait(0.3)
    40.                     Resume
    41.                     not IsVisible_Player // If we see the player, fail
    42.             Clear_Player // If after 4
    43.  
    44. tree("Engage")
    45.     sequence
    46.         DebugLog("engaging sequence...") // Called every frame
    47.         IsPlayerDetected
    48.         SetDestination_PlayerLastSeenPosition
    49.         SetStoppingDistance(0)
    50.         fallback
    51.             sequence
    52.                 not IsVisible_Player // If not visible
    53.                 fallback
    54.                     sequence
    55.                         not HasReachedDestination // And we haven't arrived
    56.                         MoveTo_Destination // Move
    57.  
    58.                     Fail // If we have arrived we fail (calling inspect).
    59.                     // tree("Inspect") // This doesn't work either
    60.                
    61.             sequence
    62.                 IsVisible_Player // If visible
    63.                 sequence
    64.                     UpdatePlayerLastSeenPosition // Update position
    65.                     SetDestination_PlayerLastSeenPosition
    66.                     SetStoppingDistance(1)
    67.                     fallback
    68.                         sequence
    69.                             HasReachedDestination // If we arrived
    70.                             Stop
    71.                             Fire
    72.                         MoveTo_Destination // If not, keep moving
    73.  
    74. tree("Die")
    75.     sequence
    76.         IsHealthLessThan(0.1)
    77.         Explode

    This is the patroller script:
    Code (CSharp):
    1. tree("BeAlive")
    2.     parallel
    3.         tree("Detect")
    4.         while
    5.             sequence
    6.                 not IsVisible_Player
    7.                 not IsPlayerDetected
    8.  
    9.             sequence
    10.                 tree("Patrol")
    11.                 tree("Inspect")
    12.  
    13. tree("Patrol")
    14.     //While no enemy is spotted,
    15.     //follow the assigned waypoints.
    16.     sequence
    17.         SetDestination_Waypoint
    18.         //SetTarget_Destination
    19.         //AimAt_Target
    20.         MoveTo_Destination
    21.         WaitArrival
    22.         Wait(0.3)
    23.         NextWaypoint
    24.         //tree("Inspect")

    I can upload the csharp code if needed.

    Sorry for my bad English.
     
  42. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    Can you write the C# code for tasks: InspectNextAngle and AimAt_Target .
    It seems, your solution is not clear. For example, the tree("BeAlive") calls the tree("Detect") and the tree("Inspect").
    But, tree("Detect") calls the tree("Inspect") agail.... Maybe, it makes an error in your trees...
    You can read about difference between while and repeat in my recent post

     
  43. MateoPeri

    MateoPeri

    Joined:
    Oct 19, 2017
    Posts:
    10
    Code (CSharp):
    1.     [Task]
    2.     public void AimAt_Target()
    3.     {
    4.         var targetDelta = (target - this.transform.position);
    5.         var targetDir = targetDelta.normalized;
    6.  
    7.         if (targetDelta.magnitude > 0.1f)
    8.         {
    9.             Vector3 axis = Vector3.up * Mathf.Sign(Vector3.Cross(this.transform.forward, targetDir).y);
    10.  
    11.             var rot = Quaternion.AngleAxis(rotationSpeed * Time.deltaTime, axis);
    12.             transform.rotation = rot * this.transform.rotation;
    13.  
    14.             Vector3 newAxis = Vector3.up * Mathf.Sign(Vector3.Cross(this.transform.forward, targetDir).y);
    15.  
    16.             float dot = Vector3.Dot(axis, newAxis);
    17.  
    18.             if (dot < 0.01f)
    19.             {// We overshooted the target
    20.                 var snapRot = Quaternion.FromToRotation(this.transform.forward, targetDir);
    21.                 this.transform.rotation = snapRot * this.transform.rotation;
    22.                 Task.current.Succeed();
    23.             }
    24.  
    25.             var straighUp = Quaternion.FromToRotation(this.transform.up, Vector3.up);
    26.             this.transform.rotation = straighUp * this.transform.rotation;
    27.         }
    28.         else
    29.         {
    30.             Task.current.Succeed();
    31.         }
    32.  
    33.         if (Task.isInspected)
    34.             Task.current.debugInfo = string.Format("angle={0}", Vector3.Angle(targetDir, this.transform.forward));
    35.     }
    Code (CSharp):
    1.     int inspectAngleIndex = 0;
    2.     [Task]
    3.     public void InspectNextAngle()
    4.     {
    5.         if (inspectAngleIndex > 3)
    6.         {
    7.             inspectAngleIndex = 0;
    8.         }
    9.         var p = transform.position + Quaternion.AngleAxis(90f, Vector3.up) * transform.forward;
    10.         SetTarget(p);
    11.         Debug.Log("setting target to next angle " + inspectAngleIndex);
    12.         inspectAngleIndex++;
    13.         Task.current.Succeed();
    14.     }

    BeAlive only calls Inspect after Patrol (they are in sequence).
    And Detect makes sure to stop Patrol before calling Inspect (Patrol ends immediately if the player is detected).
    Also I've checked the code while running and they are not called simultaneously.
     
    Last edited: Jun 4, 2019
  44. Zinev

    Zinev

    Joined:
    Feb 8, 2017
    Posts:
    13
    What tree calls the tree ("Detect") in second case after the engage?
     
  45. kritoa

    kritoa

    Joined:
    Apr 21, 2017
    Posts:
    60
    When I use Wait (1.0) to wait 1 second, but use the manual tick method, and then tick once every quarter second or once every second in a coroutine, it takes a very, very long time for the Wait to complete (looks like the Wait only goes down by Time.DeltaTime perhaps?).

    Am I doing something wrong? This looks like a pretty obvious, basic use case so I would doubt it's a bug...
     
  46. jammarman

    jammarman

    Joined:
    Feb 15, 2017
    Posts:
    6
    Is it possible to set bool without creating a seperate task for each bool?
    e.g

    [Task]
    public void SetFalse(bool newBool)
    {
    newBool = false;
    Task.current.Succeed();
    }
     
  47. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,294
    Indeed, the Wait task uses Time.deltaTime, which explains why the Wait task it's slower when you tick manually.

    For your situation, you would need to write your own Wait task that would take into account the duration between each manual tick, or your own deltaTime.

    Here is another solution that uses the "real time" (from the user perspective):
    Code (CSharp):
    1.     [Task]
    2.     void WaitSec(float duration)
    3.     {
    4.         var task = Task.current;
    5.  
    6.         // Store the starting time on the first frame.
    7.         if (task.isStarting)
    8.         {
    9.             task.item = Time.realtimeSinceStartup;
    10.         }
    11.  
    12.         // Restore the start time and compute how long the task has been running.
    13.         float startTime = (float)task.item;
    14.         float elapsedTime = Time.realtimeSinceStartup - startTime;
    15.  
    16.         // Display time to completion in inspector.
    17.         if (Task.isInspected)
    18.         {
    19.             float tta = Mathf.Clamp(duration - elapsedTime, 0.0f, float.PositiveInfinity);
    20.             task.debugInfo = string.Format("t-{0:0.000}", tta);
    21.         }
    22.  
    23.         // Complete the task when the specified duration has been reached.
    24.         if (elapsedTime >= duration)
    25.         {
    26.             task.debugInfo = "t-0.000";
    27.             task.Succeed();
    28.         }
    29.     }
    30.  
    This implementation compute an absolute elapsed time, which might not be easy to debug. So I advice adapting this code to take into account you own deltaTime instead.
     
    kritoa likes this.
  48. kritoa

    kritoa

    Joined:
    Apr 21, 2017
    Posts:
    60
    That seems like a perfectly reasonable solution - I might copy that verbatim (divide by Time.timeScale in there perhaps).

    Thanks!
     
  49. NawarRajab

    NawarRajab

    Joined:
    Aug 23, 2017
    Posts:
    18
    Hi,
    I'm using Panda BT to do sequences as opposed to AI. My script looks like this:

    Code (CSharp):
    1. tree("Root")
    2.     fallback
    3.         tree "Step0"
    4.         tree "Step1"
    5.         tree "Step2"
    6.         tree "Step3"
    7.         tree "Step4"
    8.  
    9. tree("Step0")
    10.     while isStep("0")
    11.         sequence
    12.             StepStart()
    13.             StartActivity("cam_main_song")
    14.             LoadTransition()
    15.             Wait(0.5)
    16.             StartTransition()
    17.             Wait(4.0)
    18.             StepEnd()
    19.  
    20. tree("Step1")
    21.         while isStep("verse")
    22.             sequence
    23.                 StepStart()
    24.                 Play("AI-OM-TEMP-Song-Verse-1")
    25.                 PlayAnimation("PG_Verse_1")
    26.                 Wait(4.0)
    27.             //    StepEnd()
    I disabled Root repeat and I reset the tree on "step" change. However I noticed that tree("Step1") is triggered multiple times. I set a manual tick to debug this issues. Is seems that this sub-tree is traversed while pandabehaviour status is still showing ready. so for the first 2 ticks, the sub-tree is triggered twice and on the third tick the live view switches to "Running" and triggers the sub-tree for the third time.
     
  50. DesignerZero

    DesignerZero

    Joined:
    Sep 18, 2019
    Posts:
    1
    Hello.
    I am trying to make a tree in real time, how could I know with code if the tree is structurally correct?