チュートリアル | (トピック一覧へ戻る) |
最初のコードでは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); } } } }
以下の画像はレンダリングです。