vsTASKER #5 – Using Events : Flock of birds

This tutorial deals with a simulation of a flock of 3000 birds, sharing the same simple Logic.
The behavior of each bird is given by the Logic according to 3 rules:

  • The first one is to get attracted by one of the blue birds, without going too far;
  • The second rule is to avoid getting close to one of the red birds;
  • The last rule is to go back to the initial position when there is nothing in sight.

Some code is provided below the video to help you build this demo in vsTASKER.
The database can also be downloaded.


 
Flock Logic:

Avoid Group: Avoid Task Runtime

if (L:threat) {
     if (E:pos.distanceTo(L:threat->pos) > L:threshold) {
        E:setSpeed(10);
        return DONE;
     }
     else {
        float hdg = E:pos.azimuthTo(L:threat->pos);
        hdg += DEG2RAD(180 + RANDOM(-20,20));
        E:setHeading(hdg);
        E:setSpeed(L:threat->getSpeed()*2);
     }
     return AGAIN;
  }

Avoid Group: Return Task Runtime

    E:dyn->setHeading(L:init_pos);
    E:dyn->setSpeed(20);

    if (E:pos.distanceTo(L:init_pos) < 50) {
       E:setSpeed(0);
       return DONE;
    }

Follow Group: Return Home Check

if (L:leader->pos.distanceTo(L:init_pos) > L:threshold * 2)
     return YES;
else return NO;

Follow Group: Follow Task Runtime

  if (L:leader) {
     if (E:pos.distanceTo(L:init_pos) > L:threshold * 2) {
        return DONE;
     }
     else {
        float hdg = E:pos.azimuthTo(L:leader->pos);
        hdg += DEG2RAD(frand(-disp,disp));
        disp += RANDOM(1,10);
        if (disp > 90) disp = 0;
        E:setHeading(hdg);
        E:setSpeed(RANDOM(30,50));
     }
  }

Eyes Task Declaration

private:
    Array threats;
    Array leaders;

Eyes Task Initialization

  case RESET: {
      for (int i=0; igetStatus()->isForce(_Red)) threats.addElem(e, UNIQ);
      }
      for (int i=0; igetStatus()->isForce(_Blue)) leaders.addElem(e, UNIQ);
      }
  } break;

Eyes Task Runtime

    float closest = L:threshold;
    Vt_Entity* threat = NULL;

    for (int i=0; ipos) < closest) {
          closest = E:pos.distanceTo(e->pos);
          threat = e;
       }
    }
    if (threat) {
       L:leader = NULL;
       L:threat = threat;
       L:raiseEvent("Detect!");
       return AGAIN;
    }

    closest = L:threshold;
    Vt_Entity* leader = NULL;

    for (int i=0; ipos) < closest) {
          closest = E:pos.distanceTo(e->pos);
          leader = e;
       }
    }
    if (leader) {
       L:threat = NULL;
       if (L:leader != leader) {
          L:leader = leader;
          L:raiseEvent("Follow!");
       }
    }

 
Pulser Task:

Declaration

private:
    Vt_Entity* e;
    int wait, cpt, threat;

Initialization

  case RESET: {
      for (int i=0; igetStatus()->isForce(_Blue)) break;
      }
      cpt = 0;
      wait = 0;
      threat = 0;
  } break;

Runtime

    if (++cpt > wait) {
       if (!threat) {
          threat = true;
          e->setColor(clRed);
          wait = RANDOM(1,5);
       }
       else {
          threat = false;
          e->setColor(clBlue);
          wait = RANDOM(20,40);
       }
       cpt = 0;
    }
    if (threat) S:raiseEvent("Detect!", T_Entity, e);
    else S:raiseEvent("Follow!", T_Entity, e);

 
Download the database (vsTASKER v6):

Download the zip database.
Unzip it in Data/Db/OpenGL
Load it with vsTASKER GUI v6 or newer