AI: Flocking

Flocking should contain at least three steering behaviors that individually describes how an actor behaves base on its neighbors’ velocity and position.

Seperation: Actor should steer away from all neighbors. The closer a neighbor is, the harder the actor should steer away from it. Seperation describes the sum of all such steer away behavior.seperation

private Vector2 Separation(){
    Vector2 separation = Vector2.zero ;
    foreach (IActor actor in GetNeighborActors()) {
            Vector2 posDiff = actor.Position - _actor.Position;
            float T = 1.0f - (posDiff.magnitude / neighborDistance);
            separation += -posDiff * T * T;
        }
separation = (GetNeighborActors ().Count != 0) ? separation : Vector2.zero;
return separation;
        }

Alignment: Actor should steer towards the direction of the average speed of all neighbors.alignment

private Vector2 Alignment(){
    Vector2 alignment= Vector2.zero ;
    foreach (IActor actor in GetNeighborActors()) {
            alignment += actor.Velocity.normalized;
        }

        alignment = (GetNeighborActors ().Count !=0) ? alignment / GetNeighborActors ().Count - _actor.Velocity.normalized: Vector2.zero ;
    return alignment;
        }

Cohesion: Actor should steer towards the average position of all neighbors.cohesion

private Vector2 Cohesion(){
    Vector2 cohesion= Vector2.zero ;
    Vector2 avPos = Vector2.zero ;
    foreach (IActor actor in GetNeighborActors()) {
            avPos += actor.Position;
    }
    avPos = avPos / GetNeighborActors ().Count;
    cohesion = (GetNeighborActors ().Count !=0) ? avPos - _actor.Position : Vector2 .zero;
    return cohesion;
}

Flocking is simply the combination of the three.

flocking = Separation() * separationWeight + Alignment()* alignmentWeight + Cohesion()* cohesionWeight;
            
_actor.SetInput( flocking.x, flocking.y );

To define all neighbors, it is better to leave out the ones at the back of the actors. In real life, flocking birds can’t really see those behind them. Thus we can use a neighbor distance and an angle to define the area of neighbors.

private List<IActor> GetNeighborActors(){
    List<IActor> neighbor = new List<IActor>() ;
    foreach (IActor actor in Flocking.allActors) {
            if ((actor.Position  - _actor.Position).magnitude < neighborDistance) {
                neighbor.Add(actor);
            }
            if ((new Vector2 (actor.Position.x,actor.Position.y)  - _actor.Position).magnitude > neighborDistance) {
                neighbor.Remove(actor);
            }
            if (Vector2.Angle ((actor.Position - _actor.Position), _actor.Velocity) > NEIGHBORANGLE && Mathf.PI * 2.0f - NEIGHBORANGLE > Vector2.Angle ((actor.Position - _actor.Position), _actor.Velocity)) {
                neighbor.Remove (actor);
            }
            if (neighbor.Contains(_actor)){
                neighbor.Remove(_actor);
            }
    }
    return neighbor;
}

I added a button to toggle the flocking behavior, and used a few line renderer to show the neighbor area. I also have three sliders to control the weights of the three component of flocking.flocking

Finally, I added a pursuer that chases anything nearby, and the flocking actors also evades from the pursuer while flocking. It looks like this:flocking-evade

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s