Animal Farm

About

Animal Farm is a simulation that uses AI steering behaviors model to imitate the farm animals' movements.

Project Info

Role: AI Programmer

Type: Simulation

Engine: Unity (C#)

Introduction

This project was a fun and challenging project for me where I had the opportunity to put into practice what I learned about Autonomous Agents in games and animation, focusing on math and physics (mainly Vectors) and how to apply their principles to model and simulate complex behaviors through programming.

I had decided to make a simple farm simulation with low poly assets, where the player character is a farmer and the AI agents are animals. Through this simple world I could focus on giving the animals agents the ability to navigate around their world in a life-like and improvisational manner.

Check Project Repository

World Settings

The simulation world consists of grass, barn, the Sun, water troughs, mud puddle, fence and seeds.
The player character is a farmer that can be controlled by arrow keys to move around.
AI agents are the animals : cows, sheep, pigs and chickens all of which use NavMesh Agent component attached to them.

After setting up the scene and characters, I started by adding colliders to props, player character and AI agents. Then I added a navigation map to the grass game object and baked it to the scene as it'd be the surface the agents will navigate on. I decided to add Navmesh obstacle component to the game objects shown in image below ( barn, water troughs, mud puddle, fence, seeds). Navmesh obstacle is usually used for moving objects, but I wanted to experiment using it for static objects to observe the difference between using colliders alone verses using colliders with Navmesh obstacle.

navmesh map
NavMesh map - Scene view
navmesh obstacles
Navmesh obstacles - Scene view

Animation

The animation for the player was a simple system, where the character moves based on the player's vertical and horizontal axes input.
The four legged animals agents were not animated using unity animation system, but rather using vectors. Each leg is treated as a separate game object and is then rotated halfway through using Lerp function during the walk animation.
All the four legged agents call the Animate script which has two states: walking or not walking, based on which state the agent is in, the script either animate the animal or not.
The chickens agents, similarly to other animals agents in the farm, were animated using vectors only. The only difference is chickens has only two legs. The chickens also had second animation which is peck food from the ground, which was implemented using an enumerator that swings between two euler angles for the x axis.

Cows Agents

There are two cows agents in the environment, each has two states : wander and seek.

Wander is the idle state in which the cow agent moves around the farm (navmesh map) with no definite goal location.
Wander behavior was implemented here by constraining the cow agent to the surface of a sphere located slightly ahead of it. The sphere has a target location positioned on its circumference that moves back and forth around the sphere within a random range. As it moves the cow agent update its goal location, this random displacement makes the cow agent behavior look realistic without it looking twitchy and produces sustained turns.

Seek is the state in which the cow seeks the large water trough.
Seek behavior is simply the pursue of a static target, it was implemented using navmesh agent set destination method with a stopping distance to prevent the cow from continuously arriving to the target,stepping back and then approach it again.
I made the seek behavior evoke randomly if the cow is within a certain distance from the water trough to make the cow agent looks like its going to water trough only if its thirsty.

cows wander
Cows wander behavior
cows seek
Cows seek behavior

Sheep Agents

There are four sheep agents (one of them is a lamb) in the environment, each has two states : wander and pursue.

Wander is the idle state in which the sheep agent moves around the farm (navmesh map) with no definite goal location.
Wander behavior was implemented here in the same way as other animals in farm, only with slightly different sphere radius, distance and jitter to make the sheep agent wander behavior looks different than the other animals.

Pursue is the state in which the sheep follow the player character around.
Pursue behavior is similar to seek except that target is a moving character and the agent should predict the target's future position. It was implemented here by using an estimator that gets reevaluated each frame. The estimator was obtained by taking into account the relative headings of sheep agent and the player character, and whether the agent is generally ahead of, behind, or to the side of player. Steering for pursuit is then achieved by applying the seek function to the predicted target location.
I made the pursue behavior evoke randomly if the sheep agent is within a certain distance from the player to give the sheep more realistic behavior pattern.

sheep wander
Sheep wander behavior
sheep pursue
Sheep pursue behavior

Pigs Agents

There are three pigs agents (one of them is a piglet) in the environment, each has two states : wander and hide.

Wander is the idle state in which the pig agent moves around the farm (navmesh map) with no definite goal location.
Wander behavior was implemented here in the same way as other animals in farm, only with slightly different sphere radius, distance and jitter to make the agent wander behavior looks different than the other animals.

Hide is the state in which the pig agent hides from the player behind the barn.
Hide was implemented by first setting up the hiding location on the scene, and then using singleton to store that location and access it from the pig agent script. I used the singleton design pattern to ensure that the location has only one instance but could still be accessed by agents easily.
Two methods where used to determine when the pigs should hide, the first method checks if the agent can see the target, the second method check if the target can see the agent. These two methods where achieved by casting a ray from or to the target and then calculate the angle between where the ray cast hit the target or the pig.
I made the pigs hide if the two methods return true, meaning the pigs hide only if they see the player and the player is facing them.

pigs wander
Pigs transition from wander to hide behavior
pigs hide
Pigs hiding spot

Chickens Agents

There are three chickens agents in the environment, each has two states : seek and evade

Seek is the idle state in which the chicken agent seek and peck the food on the ground
Seek behavior was implemented here in the same way cows agents, the only difference is the stopping distance and that the chicken once it reaches the target start the peck animation rather than stop moving.

Evade is the state in which the chicken agent runaway from the player.
Evade behavior is opposite of pursuit, where the agent goes away from predicted future position of the target. To implement evade behavior, I first wrote a flee method.
Flee behavior is simply the inverse of seek, it was implemented using navmesh agent set destination method with a stopping distance to prevent jittery behavior.
Then in Evade method an estimator is used to predicts what direction should the agent to steer the character so that its velocity is radially aligned away from the target. Steering for evasion is then achieved by applying the flee function to the predicted target location.

chickens seek
Chickens seek behavior
chickens evade
Chickens evade behavior

What I Learned

The final scene has all the animal agents present on the scene, which made me notice how the size of the animals affect the way the programmed behavior work. For example, the piglet move and react faster than other pigs, same case for the lamb in comparison with the other sheep.
This difference was also noticeable between different kind of animals agents, which is why I adjusted the values of speed, wander behavior variables and stopping distance, the result not only made the animals movements look more life-like but also gave each group of agents their own unique behavior pattern.

This project helped me learn more about vector mathematics, as it is an essential part of AI programming. I also gained deeper understanding of steering behavior model, and how complex behavior, which is combining more than one steering behavior to a single character, can be challenging and rewarding, without it the character looked more robotic and less real.
I also learned a lot about optimization and programming design patterns to make the simulation more flexible and abstract, in case I want to add more features or agents in the future.

final
Final game view with states on
final
Final game view