GSoC Week 1 and 2: Wild Animals Behavior System Written on May 8, 2017





The start to GSoC has been smooth. Currently as I write this wrap up post for week one and two, my work has already crossed the week 3 mark according to my proposal.

What have I been up to?

I’ve been adding new features to the WildAnimals module. The module only had a deer that idly moved around and did nothing else. When hit it would lose health and ultimately just disappear as a glitch when it’s health reached 0.

A lot has happened since and at this point there are 4 variants of the deer that exhibit very different behaviors- deer , insensitiveDeer , aggressiveDeer and hostileDeer .

Before we get into details of how these were built, let’s have a look at a few preview videos:





Importing an animal in game

First an animal model is made in blender. After an artist finishes up a model, gets it rigged, UV Mapped and adds animations, it is pushed to the Meta repository that holds all the blender files for creature models. There is a comprehensive guide on how to add creatures in game here that I’ve written. Also there is one written by flo, here. Thanks to quaternius, I’ve been getting some help with animal models.

Working with the animal in game

Each animal has a prefab file located here that details the characterstics of the animal as components. To know more about components and the Entity system architecture, go here. Once an animal prefab is made, it can be spawned in game by typing spawnPrefab prefabName in the console.

Event driven Behavior System

The four different deer I mentioned really have the same animal model, animations and texture. They only vary in behavior. This behavior handling forms the crux of the WildAnimals module. Let’s dive into a little more detail.

The Behavior System built in the engine allows something known as behavior trees, to define a certain behavior.

+ What is a behavior tree?

This A behavior tree is used to define conditional or sequential behavior for an entity. A behavior tree essentially has a set of nodes, each node executes some logic and has a condition set for when it would return a status of FAILURE, SUCCESS or simply keep RUNNING. An involved behavior tree can switch among different nodes based on the previous or child node's status.This forum post and youtube video would really give you a feel for behavior trees.

These behavior trees are central to the event driven behavior system. Each behavior tree defines a particular type of behavior that can be applied to an entity, for eg-

A “ stray ” behavior can have a deer idly roam around, walk and stand for a while.

” behavior can have a deer idly roam around, walk and stand for a while. A “ flee ” behavior can have the deer run away from the player until it’s at a safe (defined minimum) distance.

” behavior can have the deer run away from the player until it’s at a safe (defined minimum) distance. A “hostile” behavior can have the deer close in on the player and then inflict damage.

The “stray” behavior tree that exists in the Pathfinding module module looks like this:

Each of these behavior trees can be applied to the entity by simply defining it in the entity’s prefab under the BehaviorComponent. But what’s needed for the animals, is a behavior system that controls what behavior the animal has at any point in time. A system that controls when the behavior needs to switch, what should trigger such a switch and which behavior takes a higher precedence. Enter Event Driven Behavior System.

+ What is an event?

This An event is an action that propagates through all systems in the game to trigger a change or execute some logic. An event is sent to exactly one entity. An event can be received by event handlers, which can add filters for selecting only entities having a certain set of components. Different event handlers can receive the same event in an order of precedence, by specifying a priority.This wiki page describes in detail how events work.

The WildAnimals module has different packages for different behaviors like “FleeOnHit”, “AttackOnHit”, “AttackInProximity”, “StrayIfIdle”, etc. Each of these packages consists of a system and a component. If such a component is attached to an entity, the respective system takes care of handling the behavior changes associated with that package.

+ How does it work?



Let's take the example of the "FleeOnHit" and "StrayIfIdle" package, the first such packages.

The FleeOnHit package has a FleeOnHitComponent, which when attached to any wild animal entity would let it exhibit the "flee" behavior when it is hit.



The StrayIfIdle package has a StrayIfIdleComponent, which when attached to any wild animal entity would let it exhibit the stray behavior when it is idle and has no other behavior that could get triggered.



For the deer, by default it has a behavior of "stray" defined in it's prefab.



The FleeOnHitSystem watches for the OnDamageEvent to happen to an entity which has the WildAnimalComponent and FleeOnHitComponent. It saves the event instigator (damage inflictor) to the FleeOnHitComponent and then sends an UpdateBehaviorEvent to the entity to trigger a change if it's needed.

The UpdateBehaviorEvent is received by the FleeOnHitSystem. It checks for the instigator inside "FleeOnHit" to be non-null, triggers the behavior switch to "flee" and consumes the UpdateBehaviorEvent.



The StrayIfIdleSystem also receives the UpdateBehaviorSystem, but with a lower priority.

When the deer reaches a safe (defined minimum) distance from the player, the instigator in the FleeOnHitComponent is set to null and another UpdateBehaviorEvent is fired from the CheckFleeStopNode (a part of the "flee" Behavior Tree).



This event is not consumed by the FleeOnHitSystem event handler as the instigator in FleeOnHitComponent is null. It then is received by the StrayIfIdleSystem event handler, which triggers a behavior switch to "stray" and consumes the event.

The behavior switches simply happen based on the different priorities the event handlers in the different packages have. The component from the package whose behavior is to be implemented in an entity, is added to the entity's prefab. Whenever an action/event happens in the game that could trigger a change in the behavior of an entity, an UpdateBehaviorEvent (a consumable event) is sent to the entity. This event is received by event handlers present in any such package's system. These event handlers receive the event based on a priority and trigger the behavior switch by changing the entity's behavior tree inside it's BehaviorComponent.Let's take the example of the "FleeOnHit" and "StrayIfIdle" package, the first such packages.The behavior switches simply happen based on the different priorities the event handlers in the different packages have.

Advantages of the Event Driven Behavior System

There are quite a few advantages of using this approach for dealing with complex and multiple behaviors.

Easily Extendable and Reusable : A package consisting of a particular conditional behavior can be used for multiple animals/entities. For eg- the “FleeOnHit” package made for the deer can easily be added to other animals like cows, dogs etc. Adding a behavior is as simple as attaching a component.

: A package consisting of a particular conditional behavior can be used for multiple animals/entities. For eg- the “FleeOnHit” package made for the deer can easily be added to other animals like cows, dogs etc. Adding a behavior is as simple as attaching a component. Efficient : There are no constant checks and running loops. The behavior switch is instant.

: There are no constant checks and running loops. The behavior switch is instant. Simple Behavior Trees : The behavior trees remain bare-bones and minimal, as they have to deal with only one behavior and not worry about switching behavior.

: The behavior trees remain bare-bones and minimal, as they have to deal with only one behavior and not worry about switching behavior. Neat Prefabs : The prefab for the animal now gives a good picture of what all behaviors it exhibits. A simple deer’s prefab would just have the “FleeOnHit” and “StrayIfIdle” components. A deer’s prefab could look like this: "FleesOnHit": { "minDistance": 15.0 }, "EatsFromBlockIfHungry": { "block": "grass", "maxWalkDistance": 4 }, "AttractedByHoldItems": { "items": ["apple", "nut"] }

: The prefab for the animal now gives a good picture of what all behaviors it exhibits. A simple deer’s prefab would just have the “FleeOnHit” and “StrayIfIdle” components. A deer’s prefab could look like this: Clear order of precedence : Different behaviors can be given different weights as per priority. A hungry deer when hurt would run for it’s life instead of looking for food. A priority list of behaviors could look like this: ensure safety (flee if recently damaged) ensure not hungry ensure not thirsty ensure not tired ensure not curious (has not watched player / player action / player item recently)

: Different behaviors can be given different weights as per priority. A hungry deer when hurt would run for it’s life instead of looking for food. A priority list of behaviors could look like this: Easy development: With this system, someone who’s making the “EatIfHungry” package does not have to worry about what will happen if the animal is hit when it’s hungry. All he has to do is assign the event handler for the “EatIfHungry” package a lesser priority than the “FleeOnHit” package’s event handler.

The post went longer than I had expected it to. The next post would contain details of the deer that have been implemented and maybe new creatures! Most deer at this point are just placeholders for other animals whose models aren’t ready yet. Thanks to flo for all his help lately. The whole event driven behavior system idea was born out of a discussion with him. He’s been really helpful in getting my PRs reviewed and merged too.

In other news, I was away for 3 days (10th to 12th May) for the Microsoft code.fun.do SHOWCASE event that was held in Hyderabad. The trip was fun with sponsored flight trips and hotel stay. Have to catch up with lost time on GSoC though.

Please enable JavaScript to view the comments powered by Disqus.