Here is a example of my code back when I was still prototyping it. Here I was using rule sets and combining them to find the effect I liked.
//Avoid others
Vector3 RuleTwo(GameObject[] InZombieHord, GameObject InZombieBoid){
Vector3 Avoid = new Vector3 (0f, 0f, 0f);
foreach (GameObject Zombie in InZombieHord) {
Vector3 Diffirence = Zombie.transform.position -InZombieBoid.transform.position;
if (Diffirence.magnitude != 0 && Diffirence.magnitude < ViewDistance) {
Avoid -= Diffirence;
Avoid = Avoid * Time.deltaTime;
}
}
return Avoid;
}
So this made the boid check all other boids and then if they where in view distance it would move away from them. This is how it was used:
void UpdateAllBoids(GameObject[] InZombieHord){
foreach (GameObject Zombie in InZombieHord) {
Vector3 NewPosition = new Vector3 (0f, 0f, 0f);
NewPosition += RuleOne (InZombieHord, Zombie); //This has a loop inside
NewPosition += RuleTwo (InZombieHord, Zombie); //So does this
NewPosition += ThreeTwo (InZombieHord, Zombie); //etc.
NewPosition += FourTwo (InZombieHord, Zombie);
Zombie.transform.position += NewPosition;
WrapAround (Zombie);
}
}
My new code still follows this but the rules have all been worked into one:
[I decided to remove the main rule it is to bloated for the forum.]
foreach (GameObject Zombie in InPack) {
TheFourZombieRules(Zombie); //This has a single loop inside that does all 4 rules I want, it's also a void now.
}
The whole point of this loop is so that the new rules is done once for every zombie to compare it'self to the others.
A rule like this is also done by the pack leader but it moves to a goal instead of the perceived average.
This sketch shows a bit in more depth how it works.
First pass all pack leaders are compared with all pack leaders, this is done using Broad Phase, so most of the time even if there is a 1000 pack leaders I get around 96 loops per update cycle (10-15 min) for the pack leaders.
In the second pass the zombie pack is calculated and if the zombie pack leaders are in the same zone they share there lists of zombies.
If the total zombies in a pack or combined pack is more than 24 a relative Broad Phase is used instead of just brute force loops. Leaders are also added to the Broad Phase loops because with so many zombies in such a small place they often try to overlap.
When off screen only the Pack leaders update and only there positions.
My math is also as optimal as I can get it, for example instead of calculating the perceived avrrage, the leader is the average position. So PerceivedAvrrage = Leader.transform.position - ( self.transform.position / PackList.length);