Hi guys,
The built-in tasks (implemented on the PandaBehaviour component) are now documented:
Hi guys,
The built-in tasks (implemented on the PandaBehaviour component) are now documented:
Couple minor typos thereā¦ you have āposeā instead of āpauseā for DebugBreak, and for the last batch of Input entries it should be āindefinitelyā rather than āundefinitely.ā
Definitely some interesting Input options though. I think what Iām liking the most about all of this is the ease of chaining activities not tied to frame-based processing. (I realize that is no great insight!)
@MV10 , thank you for spotting the typos. Thatās fixed now.
If there is only one thing to say about this tool. This is it!
A serious problem constantly present while developing games is the lack of simply describing the game logic in a time independent way. Everything is fine until you start to write some code to handle long running activities, and it get worst when theses activities include some conditions and branching, even if theses activities are quiet easy to describe in plain english (or any human language). The usual approach to solve it, is to use some states to keep track of what the AI is currently doing, then changes the state on the go and use some coroutines, some time tracking variables or countersā¦ Then you look back at your code, and you canāt decipher the high-level logic anymore, itās diluted all over your code. I have reached the conclusion that C# or any similar programming languages does not provide an appropriate mechanism to describe this type of activities and that Behaviour Trees are just the perfect tool for that.
Letās say you want to do something simple as:
āI want my NPC to carry this precious object to some destination, but if there are some enemies on the way, secure the object and then eliminate the enemies. Once the threat is eliminated, go on with carrying the object to its destination.ā
This is a simple mission to understand.
Now, how would you implement that in C# only? It will take you days! I donāt even dare to sketch a solution for solving that.
But with a Behaviour Tree you can almost make a literal translation of this two sentences:
tree "root"
fallback
tree "DeliverPreciousObject"
tree "EliminateThreat"
tree "DeliverPreciousObject"
fallback
while not IsThereThreatOnTheWay
sequence
MoveTo_PreciousObjectLocation
PickUp_Object
MoveTo_PreciousObjectDeliveryLocation
tree "SecurePreciousObject"
tree "SecurePreciousObject"
sequence
MoveTo_PreciousObjectSafeLocation
Drop_Object
tree "EliminateThreat"
while IsThereThreatOnTheWay
sequence
SetTarget_NearestEnemy
Attack_Target
You have your high-level logic readable right there. And you know that the C# implementation of the tasks should be trivial.
Yeah my wife and I are knocking out a simple story-driven RPG in our spare time and this kind of abstraction is precisely how weāll be using this. I actually came to it trying to decide whether it was suited to dialogue trees (it isnāt really, and so Iām wrapping up a custom mini-language for that).
@MV10 , great that you are planning to use it for your game!
For a dialogue system, my first though was that BT was not appropriate and that you need more a Decision Tree for that. But after giving it some thoughts, it could come as handy if you define some proper tasks. Letās try out an example, letās say you want to design a dialogue for a shop in your RPG game:
tree "Dialogue"
sequence
Say "Welcome! What can I do for you?"
Option 1 "I'm fine... just looking around."
Option 2 "What are you selling?"
Option 3 "This is a hold-up! All your gold and fast!!"
WaitPlayerChoice
fallback
sequence Choice 1
Say "Ok, take your time. I'm here if you need me."
sequence Choice 2
tree "Shop"
sequence Choice 3
Say "Help! Guard! Heeelp!"
AddGold(100)
AlertNearestGuard
tree "Shop"
sequence
Say "Trinkets, odds and ends, that sort of thing."
Option 1 "Health potion: 10 G"
Option 2 "Mana potion: 5 G"
Option 3 "City map: 50 G"
WaitPlayerChoice
fallback
sequence Choice 1
RemoveGold(10) AddItem("HPotion")
sequence Choice 2
RemoveGold(5) AddItem("MPotion")
sequence Choice 3
RemoveGold(50) AddItem("CityMap")
sequence
Say "Sorry. You don't have enough gold!"
Fail
Say "Here you go. Thank you!"
The nice thing with that system is you can easily integrate the consequences of the dialogue choice quiet easily. Like the inventory management, or some triggers, like calling a guard.
Interesting. Iāll revisit this, thanks.
Hi guys,
There is a VS extension that would help to edit your BT scripts by displaying indentations guides:
https://visualstudiogallery.msdn.microsoft.com/e792686d-542b-474a-8c55-630980e72c30
This particularly helps if youāre are editing a deep tree.
Hi @ericbegue
Iām really liking your BT, but Iāve found a bug!
Sometimes deselecting a unit, and then reselecting that unit can cause Unity to pause for between 30secs and 2 mins, and cause this error:
This is with only this code:
public void BehaviourAction()
{
if (!isInitialised)
{
Initialise();
}
pandaBehavior.Tick();
}
[Task]
private bool HasTargets()
{
return controller.enemies.Count > 0 ? true : false;
}
[Task]
private bool CanWin()
{
return true;
}
[Task]
private void Attack()
{
Task.current.Succeed();
}
[Task]
private bool CanMove()
{
return true;
}
[Task]
private bool SafeDistance()
{
return false;
}
[Task]
private void Flee()
{
controller.transporter.Flee(controller.enemies[0].unitObject.transform.position, 500);
Task.current.Succeed();
}
tree "Root"
fallback
tree "Idle"
tree "Attack"
tree "Flee"
tree "Idle"
sequence
not HasTargets
tree "Attack"
while CanWin
sequence
Attack
tree "Flee"
sequence
CanMove
not SafeDistance
Flee
So very simplistic, but it still freezes Unity for an unnatural amount of time whenever I try to select the unit in the hierarchy. This is especially strange since Iām using a high end PC.
EDIT: Iāve found the culprit. When you have several components attached to a GameObject, and Panda Behavior is one of them, by selecting āMove Upā, or āMove Downā, it begins to slow down. Once youāve done this about 3 or 4 times (trying to move Panda Behaviour to the top), Unity really begins to chug. This chugging will then continue whenever you try to select that unit, sometimes throwing the StackOverFlow exception. Would you be able to take a look when you get a chance? Right now my only workaround is deleting every other component from a GameObject, adding Panda Behaviour, and then adding all the rest (as itās always best to have Panda Behaviour at the top so itās easy to click on and read whatās happening).
EDIT AGAIN: Iāve found that by minimising panda behavior before moving it up or down the component hierarchy, it doesnāt trigger the slowdown.
Thanks!
@Nigey , thanks for your bug report. Iāll take a look to see whatās exactly is going on there and try to fix it.
Side note: I also often need to reorganized components attached on a GameObject, Itās annoying to use the move up/down menu. It would be great if that was posible with a simple drag&drop. It seems a good candidate for a Unity feature request:).
Lol, I thought the exact same thing.
@Nigey , I could reproduce the bug youāve mentioned. It is indeed very annoying. The bug does occurs only with the current version (1.2.2) and does not occurred with the up coming version (1.2.3). I am suspecting it is related to the bug @Kiwasi discovered (see this post), this bug was making the BT being recompiled when an object is selected in the Hierarchy, and probably other undiscovered side effects. This will be fixed in the release of version 1.2.3.
I would like to somehow quickly distribute the fix to you guys, so you donāt have to wait for the fixed package being published on the Asset Store (the asset reviewing takes quiet some time). But I have to ensure first that I am not violating my agreements with Unity by doing so.
Thatās exactly what I thought the issue was too. It seemed like itād duplicate another version each time you moved the component. The delay got longer and longer each time you moved it. Iāve seen a few other assets on the asset store with the same issue of recompiling each time itās selected (A* Pathfinding, Iām looking at you).
I didnāt know about the asset reviewing phase. I suppose that does make sense. Well Iāve asked publishers for minor changes before via Email and theyāve sent it to me. So Iām guessing itās not a problem. In case you find itās okay to send the hotfix privately, my email is ānigel_clark_@outlook.comā. Thanks for fixing it quick :).
Oh! The BT scripts not appearing on the prefab seems to be caused by the same bug. So, this is a 1-stone-3-birds-fix (maybe more, who knows). Anyway, everything will better in the 1.2.3 release.
Nice work. Iām personally happy with simply waiting out the review process. Should be quicker for updates?
Either way none of this is time critical for me.
Iāve got an answer from Unity, itās fine I distribute the new package directly. So if you donāt want to wait for the Asset Store update, just PM me and Iāll send the hotfixed package to you.
Panda BT Pro is now available on the Asset Store!
This version contains the sources and break point debugging.
So far, Iām enjoying using Panda more than using the dialogue mini-language I wrote myself during the past week.
Disclaimer: I hate Python. This is minor, but from time to time I stumble over PBTās indent-based hierarchy. Looking at the language youāve created, I canāt see a reason itās important. I agree it looks nice, but I donāt understand why it must be enforced. Iām guessing it makes your parsing easier? Any chance this requirement could be dropped? Or am I missing some case where lack of indentation would introduce ambiguity? (My trees are still pretty simple at this pointā¦)
Another thought / suggestion / requestā¦
In using PBT for dialogue experiments, I found myself calling the same tasks over and over. To use the example you posted the other day, Say(text) would be an example of this. It is obvious those repeated calls belong in a separate class. I also separated the UI handling, so methods like Say() and Option() go into a generic Dialogue class that sits in between the dialogue script in the behavior tree and the UI.
It quickly begins to feel wasteful to sprinkle copies of this Dialogue class on every single GameObject that needs to say something. Normally I would to implement it as a static class (there is almost no state-data and only one dialogue would ever be active at a given time) but this doesnāt work because, by definition it isnāt on the same GameObject, and of course, a static class canāt be a MonoBehaviour.
Iām sure you see where Iām going with this. I can define [Task] attributes on static methods but PBT canāt find them. Is there some Unity-reason for this? As far as I know, .NETās GetCustomAttributes() should find [Task] anywhere in the project, right? As long as there are no naming ambiguities, would it be a problem to just call a named Task wherever it might be? I suppose this really only applies to static methods, but I tend to use them heavily for utility-style operations.
Yeah, I know what you mean about the Python indentation style. Sometimes I also have those āaargghhhh! ffffffā¦ā-moments when somehow I end up with a mixed of spaces and tabs indentation in the same script rendering the hierarchy as ambiguous. I went for this style of indentation because it requires less typing than using brackets as in C/C++ or derived languages including C#. Also I believe is more readable, though it is sometime frustrating to have such a strict indentation. But, maybe I could support both stylesā¦ I donāt know.
For example this BT script:
tree "DeliverPreciousObject"
fallback
while not IsThereThreatOnTheWay
sequence
MoveTo_PreciousObjectLocation
PickUp_Object
MoveTo_PreciousObjectDeliveryLocation
tree "SecurePreciousObject"
Would become in a bracket style indentation:
tree "DeliverPreciousObject"
{
fallback
{
while{ not{IsThereThreatOnTheWay} }
{
sequence
{
MoveTo_PreciousObjectLocation
PickUp_Object
MoveTo_PreciousObjectDeliveryLocation
}
}
tree "SecurePreciousObject"
}
}
Somehow, I prefer the python style. But maybe itās just a matter of taste. I would like to have more feedback on this. Or maybe there is another way to specify hierarchies (Disclaimer: I am definitely not going towards an xml style, donāt even suggest it, it would be a plain and definitive āNo!!!ā)?
Iāve made a small project trying to implement this Panda BT dialog system. And so far Iām pretty satisfied of the result. I have the intention to place this solution on the Asset Store as a Panda BT extension. But since you are the catalyst of this idea, I will send the project to you in PM. Basically, any character in you game that speaks, therefore could trigger a dialogue has to have a specific MonoBehaviour attached to it ( thereās no other way around this). However, that does not mean that this MonoBehaviour has to handle all the UI, this could be delegated to a unique object in the scene. So the āSayā task can have a āstatic smellā.
In fact, my first Panda implementations did not require the [Task] attribute. But I thought maybe itās a good idea to have a way to specify that you have the intention to use a method from a BT script, this would avoid some ambiguous situations where a method with the same name is already defined but has nothing to do with a BT script. Thatās why there is this [Task] attribute: you know that this method is to be used from a BT script.
Also, it is simple and straight forward that the task implementations should be implemented on the same GameObject the PandaBehaviour component is attached to. This also introduces some flexibility. For instance, you can have the same BT script attached to different GameObjects but with different different task implementations. Such that you have the same high level logic but different effective implementation, it is a mechanism somewhat similar to polymorphism in OOP.
I agree it is technically possible to not have the restriction of having the task implementation attached to a specific game object. But you would need to introduce some task implementation searching or priority, which would introduce more complications. I would like to keep Panda BT as simple and straight forward as possible. But I am not closed to suggestions and ideas that would come in handy in practice. Like having a way to specify a global-default-tasks. But again that would introduce extra configurations. Which are not necessary, since it so easy to create a new MonoBehaviours and attached to GameObjects.
Panda BT is a really young project and there is always place for improvements. Iām really glad to have such constructive critics and suggestions. Please keep them coming up!
Thanks, Iād be interested in checking out what you came up with.
In terms of Tasks which arenāt associated with a GameObject, I wasnāt hoping for anything complicated. If there is ambiguity, Iād be ok with it just throwing an error. With Unity serializing and deserializing things all over the place, no constructors on MonoBehaviours, etc, Iām just not a big fan of composing game elements and relationships through the editor, I prefer a more data- and code-driven approach.
After considerations and weightings, having an in-inspector BT editor would make the workflow much simpler and more streamlined than editing the BT script with an external text editor (though I will keep this as an option). An in-inspector editor would eliminate all the indention hassles ( @MV10 ) and it could open the option to have auto-completion and error checking directly within the Inspector.
The Unity scene Hierarchy tab could be a good model to start with, itās rather easy to organize a hierarchy using it (obviously). So I am going toward this approach to organize the node hierarchy of a behaviour tree.
@tatoforever I think this new feature would match pretty well what you are suggesting. (?)
Thought, this is not going to be implemented soon. I need to give it more thoughts. Also, I need to refactor the PandaBehaviour inspector a lot, since it was originality not build to be an editor.
This in-inspector editor is a good reason to increment the minor version number, so this is going to be a feature of Panda BT version 1.3.x!
Stay tuned!