Following the direction of this site, I set about making a set of flocking behaviour for a group AI known as Boids.
Boids follow three sets of very simple behaviour, that when combined creates an emergent behaviour that resembles a group of birds moving as a flock.

The behaviours are described above, Cohesion, alignment and separation. The way I set about implementing the boids functionality is to first set up how they would interact with the world.

First the boid spawner and controller has an area that the boids can spawn in. This is also the containment area for the boids, and will move to the other side of the box if they leave one side. This spawner also keeps track of every boid that is spawned, so that there is a record of how many game objects there are and where.
Next we start on the boid code. Each boid is parented to the spawner, and so can access the list of every game other boid. Next, we give the boids a random starting movement direction, and get them moving in that direction. Each boid will have a direction vector they will follow, meaning we can influence that vector to change its direction easily.
cameraParent = GetComponentInParent();//get spawner component
Vector3 tempDir = new Vector3(Random.Range(-cameraParent.spawnX, cameraParent.spawnX), Random.Range(-cameraParent.spawnY, cameraParent.spawnY)); //random location in the spawn area
Vector3 newDir = Vector3.RotateTowards(transform.forward, tempDir – transform.position, 9999, 0.0f);//get the vector to look at that direction. will snap to it
transform.localRotation = Quaternion.LookRotation(newDir);//actually look at that vectordir = transform.forward;//the movement direction is where the boid is looking
We then get the boids to ignore their own colliders, as they move easier that way
Physics2D.IgnoreLayerCollision(8, 8, true);
Now that the boids can access the spawner data, we can check how close they are to each other. While this code is quite inefficient (as each boid is checking the distance of every other boid, an o^n in terms of performance) we can use square magnitude to increase the speed of checking the distance. As we’re only ever using this to check if another boid is close enough, then we can use sqrmagnitude.
foreach (GameObject go in cameraParent.boidList)
{
Vector3 offset = go.transform.position – transform.position;
float sqrDist = offset.sqrMagnitude;if (sqrDist < (boidRange * boidRange) && go != gameObject)//checking if a boid is not the current boid as well as the square distance
{
nearby.Add(go);
Debug.DrawLine(go.transform.position, transform.position);
}
}
Now each boid knows which other boids are close by. Now we can start implementing the three behaviours as described above. I chose to have each function return a direction that is added to the boids current movement. This will mean that the boids will move to their objective over time.
Vector3 dirTemp = dir;
//add the direcitons
dirTemp += Cohesion();
dirTemp += Seperation();
dirTemp += Alignment();dir = dirTemp;//make the direction equal the temp
dir.Normalize();//normalise itrb.AddForce(dirTemp * speed * Time.deltaTime);//move in that direction
Now we get into what each function does. Starting with Cohesion:
public Vector3 Cohesion()
{
if (cameraParent.cohesion)//if the bool is ticked
{
if (nearby.Count != 0)//if there is boids nearby
{
Vector3 temp = Vector3.zero;foreach (GameObject go in nearby)
{
temp += go.transform.position;//add each other boids position into a variable
}temp /= nearby.Count;//average the postion
Vector3 diff = temp – transform.position;//get to direction to that average position
diff.Normalize();//normalise it and return itreturn diff;
}
}
return Vector3.zero;//otherwise don’t affect the outcome
}
This makes all boids clump together like weird ants.

Next, separation. My original though was to get the average of the boids, and then inverse the directional vector. However, this doesn’t work out very well, as if you have both cohesion and separation on, they simply both cancel out. What separation needed was the distance between each OTHER boid and the boid being checked, and normalising that. (Thanks Greg for that advice)



By normalising each of those other points that are facing away from the “parent” boid, we can a directional vector that faces away from all the other ones.
foreach (GameObject go in nearby)
{
temp += transform.position – go.transform.position;
}
temp.Normalize();
return temp;
Alignment was a much more simpler. As each boid is moving using Unity’s physics system, we can just check what their velocity is, and make our current velocity more like everyone elses.
foreach (GameObject go in nearby)
{
temp += go.GetComponent().velocity;
}temp /= nearby.Count;
temp.Normalize();return temp;
However, the directions that are begin returned aren’t that strong, so if we multiply them we can get some of the effects we want.
dirTemp += Cohesion() * 2.45f;
dirTemp += Seperation() * 2.5f;
dirTemp += Alignment() * 2;
While the boids can now move in relation to each other, they don’t move away from objects. We can make a primitive wall force push that makes the boids avoid the walls by adding directly to the boids directional vector when they get near.

I also implemented an “influencer boid” which simply moves throughout the scene while not acting as a boid. As a result, the other boids will be affected by it while being a consistent change in the scene. It would also be relatively easy to give an overall objective for a swarm, pushing them to a location.