xxxxxxxxxx
int nt=500;
int np=250,min=1,max=10;
ArrayList<termite> t ;
ArrayList<pile> p ;
float maxspeed=5;
void setup(){
//size(700,700);
fullScreen();
background(255);
ellipseMode(RADIUS);
textAlign(CENTER,CENTER);
t = new ArrayList();
p = new ArrayList();
int i=0;
while(i<np){
int x=int(random(max,width-max));
int y=int(random(max,height-max));
int r=int(random(min,max));
boolean valid=true;
for(int a=0;a<p.size();a++){
float d=dist(p.get(a).pos.x,p.get(a).pos.y,x,y);
if(d-1<(max*2)){
valid=false;
break;
}
}
if(valid){
p.add(new pile(x,y,r));
i++;
}
}
i=0;
while(i<nt){
int x=int(random(max,width-max));
int y=int(random(max,height-max));
int r=5;
boolean valid=true;
for(int a=0;a<p.size();a++){
float d=dist(p.get(a).pos.x,p.get(a).pos.y,x,y);
if(d-1<(r+p.get(a).size)){
valid=false;
break;
}
}
if(valid){
t.add(new termite(x,y));
i++;
}
}
}
void draw(){
background(255);
for(int j = 0 ; j < p.size() ; j++){
p.get(j).show(j);
}
for(int j = 0 ; j < t.size() ; j++){
t.get(j).move();
t.get(j).display();
}
}
class termite{
/* Rules
1. move forward one then turn random direction
2. if you bump into a pile & are carrying a chip, drop chip in pile
3. if you bump into a pile & not carrying a chip, take chip & turn random direction
*/
PVector pos=new PVector();
PVector vel;
PVector acc;
boolean carry;
float maxforce;
float wandertheta;
float size=4;
termite(int x,int y){
wandertheta = 0.0;
pos=new PVector(x,y);
acc = new PVector(0, 0);
float angle = random(TAU);
vel = new PVector(cos(angle), sin(angle));
maxforce = .25;
carry=false;
}
void move(){
checkinside();
if(pos.x <= 0 || pos.x >= width){
vel.x*=-1;
}
if(pos.y <= 0 || pos.y >= height){
vel.y*=-1;
}
acc.add(wander());
acc.limit(maxforce);
vel.add(acc);
vel.limit(maxspeed);
pos.add(vel);
for(int a=0;a<p.size();a++){
float d=dist(p.get(a).pos.x,p.get(a).pos.y,pos.x,pos.y);
if(d<(size+p.get(a).size)){
if(carry){
ringCollision(this,p.get(a).pos,++p.get(a).size);
//vel.mult(-1);
pos.add(vel);
//p.get(a).size++;
carry=false;
}else if(carry==false && p.size()>1){
//vel.mult(-1);
ringCollision(this,p.get(a).pos,--p.get(a).size);
pos.add(vel);
//p.get(a).size--;
if(p.get(a).size<=0){
p.remove(a);
maxspeed=map(p.size(),np,0,5,10);
}
carry=true;
}
}
}
pos.add(vel);
/*
if (pos.x < 0) pos.x = width;
if (pos.y < 0) pos.y = height;
if (pos.x > width) pos.x = 0;
if (pos.y > height) pos.y = 0;
*/
acc.mult(0);
}
void lineCollision(termite te, PVector lp, float la, float lw){
PVector lineStart = new PVector(lp.x-cos(la)*lw/2,lp.y-sin(la)*lw/2);
PVector lineEnd = new PVector(lp.x+cos(la)*lw/2,lp.y+sin(la)*lw/2);
PVector start2ball = new PVector(te.pos.x - lineStart.x, te.pos.y - lineStart.y);
//find normal to line and set it to unit length
PVector normalToLine = new PVector(-(lineStart.y - lineEnd.y), lineStart.x - lineEnd.x);
normalToLine.normalize();
//to resolve overlap of ball and line
//find vector representing the line
PVector theLine = new PVector(lineStart.x - lineEnd.x, lineStart.y - lineEnd.y);
//first: find dist from lineStart to ball along the line
//project start2ball onto the line
//need dot products
float ballDOTline = start2ball.dot(theLine);
float lineDOTline = theLine.dot(theLine);
PVector ballProjectedOntoLine = PVector.mult(theLine, ballDOTline/lineDOTline);
PVector projectionAddedToStart = PVector.add(lineStart, ballProjectedOntoLine);
//second: find offset needed to negate overlap
//to find out which side of the line the ball is
//find dot product of start2ball and the normalised normal
//it'll be negative or positive (one side of the line or the other)
float ballDOTnormal = start2ball.dot(normalToLine);
//normalised normalToLine multiplied by ballDOTnormal and normalised again
PVector offsetFromLine = PVector.mult(normalToLine, ballDOTnormal);
offsetFromLine.normalize();
//normalised offsetFromLine multiplied by the radius
offsetFromLine.mult(size + .5);
//set the ball's position to the distance from start plus the offset
te.pos = PVector.add(projectionAddedToStart, offsetFromLine);
PVector incidence = new PVector(-te.vel.x, -te.vel.y);
//find dot product of incident vector and line normal
float incidenceDOTline = incidence.dot(normalToLine);
//calculate reflection (assuming coefficient of restitution = 1)
//reflection = (1 + coefficient of restitution) * normalToLine
// * (normalToLine DOT incidence) - incidence
PVector temp = PVector.mult(normalToLine, (2*incidenceDOTline));
te.vel = PVector.sub(temp, incidence);
te.vel.limit(maxspeed);
}
void ringCollision(termite te, PVector cp, float cr){
float dx = cp.x - te.pos.x;
float dy = cp.y - te.pos.y;
float distance = sqrt(dx*dx + dy*dy);
if((cr < distance + size) && (distance < cr + size)){
float angle = atan2(dy, dx);
float xbit = cp.x - cr * cos(angle);
float ybit = cp.y - cr * sin(angle);
PVector tangentPosition = new PVector(xbit, ybit);
lineCollision(te,tangentPosition,angle+HALF_PI,10);
}
}
void checkinside(){
for(int i=0;i<p.size();i++){
if(pos.dist(p.get(i).pos)<p.get(i).size){
boolean b=false;
float x=random(width),y=random(height);
while(b==false){
if(dist(x,y,p.get(i).pos.x,p.get(i).pos.y)<p.get(i).size){
x=random(width);
y=random(height);
}else{
b=true;
}
}
pos=new PVector(x,y);
}
}
}
PVector seek(PVector target) {
PVector desired = PVector.sub(target, pos);
desired.normalize();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired, vel);
steer.limit(maxforce);
return steer;
}
PVector wander() {
float wanderR = 16.0;
float wanderD = 50.0;
float change = 0.5;
wandertheta += random(-change,change);
PVector circlepos = vel.get();
circlepos.normalize();
circlepos.mult(wanderD);
circlepos.add(pos);
PVector circleOffSet = new PVector(wanderR*cos(wandertheta),wanderR*sin(wandertheta));
PVector target = PVector.add(circlepos,circleOffSet);
return (seek(target));
}
void display(){
stroke(0);
strokeWeight(1.5);
fill(0);
pushMatrix();
translate(pos.x,pos.y);
rotate(vel.heading());
rect(0,0,-7,0);
//line(pos.x,pos.y,pos.x+ex,pos.y+ey);
if(carry){
noStroke();
fill(170,40,15);
ellipse(2.5,0,2.5,2.5);
}
popMatrix();
}
}
class pile{
int size;
PVector pos=new PVector();
pile(int x,int y,int i){
size=i;
pos=new PVector(x,y);
}
void show(int i){
checkinside(i);
fill(250,200,100);
strokeWeight(.75);
stroke(0);
ellipse(pos.x,pos.y,size,size);
if(size>=5){
fill(0);
textSize(10);
text(size,pos.x,pos.y-1);
}
}
void checkinside(int a){
for(int i=0;i<p.size();i++){
if(a!=i && pos.dist(p.get(i).pos)<size+p.get(i).size){
if(p.get(i).size>size){
pos=new PVector(random(width),random(height));
}else{
p.get(i).pos=new PVector(random(width),random(height));
}
}
}
}
}