The next step after the lobotomy was to begin work on the Behaviour Tree system. I needed a first-attempt tree that would give me a chance to set up and test the basic functions: I went for this one.
This is a nice simple tree, and great for starting up. It’s hardly ancient, occult code transmitted from the blackest depths of humanities soul, but everyone has to start somewhere. It’s like the first gun you get in an RPG. Later, when I’m killing skyscraper-sized programming with a gun that shoots lightning, I’ll look back on this moment and be like “heh”.
What it does should be fairly self explanatory, but I’ll go through it step by step. This might not be necessary for *this* tree, but things’ll get more and more complex in the future, and if I tell you all about it now, the future posts will be somewhat easier to follow.
Repeats. This ensures that every time the creature finishes its task (in this case, the sequence below it), it starts a new one. Simple!
One of the foundational concepts of behaviour trees. A sequence works by starting up the first routine in it’s list (Wander) and waiting for it to succeed. When it does succeed, the sequence will continue to the next item in the list, and then the next, and then the next. Only after all items in the list Succeed will the Sequence itself succeed and return control to the parent (which in this case, given that the parent is a Repeat, will cause the sequence to start over).
If any routine fails (say Wander fails because there’s a fence between the creature and the wander location), the entire Sequence will fail. If Wander fails, the creature will NOT idle for 1 second: it will immediately go up to Repeat and search for a new location to wander to.
The practical upshot of this is that Sequences are great for things that need to be done in order. Hunting, for example: a hunter needs to [find food, catch food, kill food, eat food]. If any one of these operations fails; say the hunter has poor senses, or the prey escapes, or the hunter spontaneously decides to become a vegetarian; then the entire Hunt() sequence fails.
This is really just a wrapper for the MoveTo method. All it does is reset the target location, then call MoveTo(), which does all the actual work of moving the creature.
That said, this is also a method ripe for improvement. The previous Wander method, hidden away somewhere in the Finite State Machine code, simply picked a random (x,y) location in a square around the creature. The new method picks a location in a 180 degree arc in *front* of the creature, meaning they backtrack less and maximise the ground they cover.
In the long term, this won’t be the only upgrade to this method: it will also have code to disincentivise (shut up spellcheck, I know that one’s a word) them from wandering into inhospitable biomes like lava, deserts and oceans. Rather than just hard-coding a list of ‘inhospitable biomes’, I plan to implement this as an aspect of the “Discomfort” emotion: they will avoiding wandering in directions that make them less comfortable, such as area’s too hot/cold or dry/wet for them.
I don’t want to completely eliminate attempts to cross the desert/ocean, though, so Wander may have to become even more complex than that to facilitate migration behaviors.
This actually moves the creature to a target, Succeeding when the creature reaches the target, and Failing in a variety of other situations (such as an obstacle, like a fence or a homicidal rover).
This is another task that, while simplistic, is ripe for extension. “Move” could mean a lot of things: Walk, Run, Stalk, Pounce, Fly, Swim: it’s entirely possible we’ll end up doing away with the “MoveTo” leaf node entirely, replacing it with a sub-tree that chooses between all of those variations depending on circumstance.
For now though, it serves its purpose.
A simple node that causes the creature to wait around for a set period of time. Nothing complex about it: it just prevents the creature from immediately re-wandering.
So, in totality…
… this tree has a creature walk in a random direction, then wait for a second, and repeat.
Wow. I murdered a lot words for that. Oh well, words are cheap and delicious.
This tree might not be particularly impressive, but it’s a foundation for something a lot more complex. It’s existence means we have a Routine base class, with leaf (MoveTo and Idle), decorator (Wander and Repeat) and composite (Sequence) nodes. And importantly, it’s a way to test and debug each of these individual types of nodes before we start putting together something more interesting.
With this working, we can move on to more complex behavior, and finally begin unlocking the Strange Occult Power of Behavior Tree’s. In the name of SCIENCE. I have it on good authority that strange occult powers are very scientific.
NEXT TIME on BoringTechnicalCrapNobodyCaresAbout: FindClosestEdibleTree();
Are you excited? I’m excited.