home processing download documents tutorial python tutorial gallery source about
 チュートリアル (トピック一覧へ戻る)

物理シミュレーションとスウォーム・アルゴリズム例

     スウォーム・エージェント・アルゴリズム例

この例では、飛び回るスウォーム・エージェントを用いて、クラスター状の形態を生成するアルゴリズムを示します。

最初のコードではMyBoidクラスのエージェントが、移動方向に垂直な面に 五角形の線を生成していきます。

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray());
  }
  new Attractor(IG.v(0,0,0));
}

class MyBoid extends IBoid{
  int pointNum = 5;
  IVec[] points;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    double radius = 3;
    for(int i=0; i < pointNum; i++){
      IVec axis = vel().cross(IG.zaxis);
      axis.len(radius);
      axis.rot(vel(), 2*PI/pointNum*i);
      points[i] = pos().cp(axis);
    }

    for(int i=0; i < pointNum; i++){
      new ICurve(points[i], points[(i+1)%pointNum]).clr(clr());
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

次のコードではIG.time()sinを用いて 五角形の大きさをコントロールし、また各フレームごとに生成される線の間に 斜めの線をトラス状に追加生成しています。

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray());
  }
  new Attractor(IG.v(0,0,0));
}

class MyBoid extends IBoid{
  int pointNum = 5;
  IVec[] points, prevPoints;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    double radius = sin(IG.time()*0.1)*2 + 3; //changing radius by time
    for(int i=0; i < pointNum; i++){
      IVec axis = vel().cross(IG.zaxis);
      axis.len(radius);
      axis.rot(vel(), 2*PI/pointNum*i);
      points[i] = pos().cp(axis);
    }

    if(prevPoints!=null){
      for(int i=0; i < pointNum; i++){
        new ICurve(points[i], points[(i+1)%pointNum]).clr(clr());
        new ICurve(points[i], prevPoints[(i+1)%pointNum]).clr(clr());
        new ICurve(points[i], prevPoints[i]).clr(clr());
      }
    }
    else{
      prevPoints = new IVec[pointNum];
    }
    
    for(int i=0; i < pointNum; i++){
      prevPoints[i] = points[i];
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

次の例では変わってスウォーム・エージェントは五角形ではなく単純な軌跡を生成する だけに戻っていますが、 軌跡上にAnchorクラスのエージェントを生成して置いて行っています。 Anchorエージェントは、最初に置かれた位置から移動しませんが、 近くにスウォーム・エージェントが飛来した場合にそこへ向かって線を生成します。 結果として、近くのスウォーム・エージェントへ線を引くだけでなく、 近くにある過去にの軌跡に対しても線を引くような振る舞いとなります。 また、Anchorエージェントはそれを生成した親スウォームには線を引かず、 また短すぎる線が生成されないように、距離が近すぎるときも線を生成しません。

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  IG.bg(0);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).friction(0.001).clr(IRand.gray(48));
  }
  new Attractor(IG.v(0,0,0));
}

class Anchor extends IAgent{
  IVec pos;
  MyBoid parent;
  
  Anchor(MyBoid b){ 
    parent = b;
    pos = b.pos().cp();
  }
  
  void interact(IDynamics agent){
    if(agent instanceof MyBoid){
      MyBoid boid = (MyBoid)agent;
      double dist = boid.pos().dist(pos);
      if(boid!=parent && dist < 18 && dist > 8 ){
        new ICurve(boid.pos().cp(), pos).clr(parent.clr());
      }
    }
  }
}

class MyBoid extends IBoid{
  IVec prevPos;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
  }

  void update(){ //drawing line
    new Anchor(this); //leaving an anchor behind
    IVec curPos = pos().cp();
    if(prevPos!=null){
      new ICurve(prevPos, curPos).clr(clr());
    }
    prevPos = curPos;
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

最後に、以下のコードでは 多角形のトラス形状と、Anchorエージェントを組み合わせて、 クラスター状の形態を生成しています。 トラス形状はIG.meshSquareStick(pt1, pt2, size)メソッドを用いて 棒状のポリゴン・メッシュによって構成され、Anchorエージェントはトラスの 頂点に置かれて近傍他のトラス形状と接続します。

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  IG.bg(0);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray(48));
  }
  new Attractor(IG.v(0,0,0));
}

class Anchor extends IAgent{
  IVec pos;
  IVec[] points;
  MyBoid parent;
  
  Anchor(MyBoid b){ 
    parent = b;
    pos = b.pos().cp();
    points = new IVec[b.points.length];
    for(int i=0; i < points.length; i++){ points[i] = b.points[i]; }
  }
  
  void interact(IDynamics agent){
    if(agent instanceof MyBoid){
      MyBoid boid = (MyBoid)agent;
      double dist = boid.pos().dist(pos);
      if(boid!=parent && dist < 18 && dist > 8 ){
        double meshSize = 0.5;
        double r = sin(IG.time()*0.1)*0.1+0.3;
        double g = 0.2;
        double b = sin(IG.time()*0.1)*0.4+0.6;
        for(int i=0; i < points.length; i++){
          if(IRand.pct(40)){ //only 40%
            IG.meshSquareStick(boid.points[i],points[i],meshSize).clr(r,g,b);
          }
        }
      }
    }
  }
}

class MyBoid extends IBoid{
  int pointNum = 3;
  IVec[] points, prevPoints;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    if(time()%2==0){ //adjusting interval
      double radius = sin(IG.time()*0.1)*2 + 3; //changing radius by time
      for(int i=0; i < pointNum; i++){
        IVec axis = vel().cross(IG.zaxis);
        axis.len(radius);
        axis.rot(vel(), 2*PI/pointNum*i);
        points[i] = pos().cp(axis);
      }

      new Anchor(this); //leaving an anchor behind

      double meshSize = 0.5;
      double r = sin(IG.time()*0.1)*0.1+0.3;
      double g = 0.2;
      double b = sin(IG.time()*0.1)*0.4+0.6;
      if(prevPoints!=null){
        for(int i=0; i < pointNum; i++){
          IG.meshSquareStick(points[i], prevPoints[i], meshSize).clr(r,g,b);
          IG.meshSquareStick(points[i], prevPoints[(i+1)%pointNum], meshSize).clr(r,g,b);
          IG.meshSquareStick(points[i], points[(i+1)%pointNum], meshSize).clr(r,g,b);
        }
      }
      else{
        prevPoints = new IVec[pointNum];
      }
      
      for(int i=0; i < pointNum; i++){
        prevPoints[i] = points[i];
      }
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

以下の画像はレンダリングです。


(トピック一覧へ戻る)

HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java / Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT