import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; import netscape.javascript.*; import javax.comm.*; import javax.sound.midi.*; import javax.sound.midi.spi.*; import javax.sound.sampled.*; import javax.sound.sampled.spi.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.sax.*; import javax.xml.transform.stream.*; import org.xml.sax.*; import org.xml.sax.ext.*; import org.xml.sax.helpers.*; public class BIO_1A extends BApplet {//---------------BIO_1A--------------
//A structure and motion study for a complex cellular automata
//by Alessandro Capozzo -GHOSTAGENCY-
// 4th december 2003
//built with proce55ing alpha .67
//______________________________________________________________
//creature data, setting for 1 worm with 14 nodes
Structure [] list;
int num=14;
int countList=1;
void setup() {
  size(640,320);
  list=new Structure[countList];
  for(int index=0;index<countList;index++){
    int xx=3;
    int yy=7;
    list[index]=new Structure(index,num,xx,yy);
    list[index].startMe();
  }

}

void loop() {
  background(235,230,215);
   // perspective and grid design
  translate(20,-100,-450);
  push();
  rotateX(PI*.28f);
  stroke(180,165,130);
  for(int grx=0;grx<7;grx++){
    for(int gry=0;gry<7;gry++){
      line(grx*100-2,gry*100,grx*100+2,gry*100);
      line(grx*100,gry*100+2,grx*100,gry*100-2);
    }

  }
  //check structure objects
  for(int index=0;index<countList;index++){
    list[index].update();
  }
  pop();
}
//main object
class Structure{
  int id;
  int nBall;
  int xBall,yBall;
  public Ball [] cont;

  Structure (int me,int n,int stx,int sty){
    id=me;
    nBall=n;
    xBall=stx;
    yBall=sty;

  }
  void startMe(){
    cont=new Ball[nBall];
    for (int index = 0; index < nBall; index++) {
      int rx=(int)(random(500));
      int ry=(int)(random(500));
      cont[index]=new Ball(.04f*(index+2),ry,rx,15,index,xBall,yBall,id);
    }

  }
  void update(){
    for (int res = 0; res <nBall; res++) {
      cont[res].update();
    }
  }
  // nodes objects
  class Ball {
    int bx,by;
    int difX,difY;
    int dim;
    int me;
    int radius;
    //skin var
    int tarX,tarY;
    //----------
    float objX,objY;
    float beta,dist;
    float xSpeed,ySpeed,ndelay;
    float angx,angy,coef;
    int posx,posy;
    float dirX,dirY;
    Ball(float d,int initX,int initY,int magnitude, int iid,int _sx,int _sy,int _pid){
      ndelay=d;
      bx=initX;
      by=initY;
      difX=0;
      difY=0;
      xSpeed=0.00f;
      ySpeed=0.00f;
      dim=magnitude;
      me=iid;
      //head initialising
      if(me==0){
        posx=(int)(random(height));
        posy=(int)(random(width));
        xSpeed=_sx;
        ySpeed=_sy;
        dirX=xSpeed;
        dirY=ySpeed;
        coef=TWO_PI/40;

      }
    }
    void update (){
      if(me!=0){
      //body
        distance();
      } else{
      //head
        boolean checkX=false;
        boolean checkY=false;
        if((posx<50)&&(dirX<0)){
          dirX=5;
          checkX=true;
        }
        if((posx>550)&&(dirX>0)){
          dirX=-5;
          checkX=true;
        }
        if((posy<50)&&(dirY<0)){
          dirY=5;
          checkY=false;
        }
        if((posy>550)&&(dirY>0)){
          dirY=-5;
          checkY=false;
        }

        if(dirX!=xSpeed){
          xSpeed+=((dirX-xSpeed)*.12f);
        }
        if(dirY!=ySpeed){
          ySpeed+=((dirY-ySpeed)*.12f);
        }

        if(angx>=TWO_PI){
          angx=0.00f;
        }
        angx+=coef;
        if(angy>=TWO_PI){
          angy=0.00f;
        }
        angy+=coef;
        posx+=(int)(xSpeed+(xSpeed*sin(angx)));
        posy+=(int)(ySpeed+(ySpeed*sin(-angx)));
        bx=posx;
        by=posy;
        node();
      }
    }
    void distance(){

      objX=cont[me-1].bx-bx;
      objY=cont[me-1].by-by;
      dist=sqrt(sq(objX)+sq(objY));
      if(abs(dist)!=30){
        objY+=.01f;
        objX+=.01f;

        beta=(float)(Math.atan(objY/objX));

        if(cont[me-1].by>=by){
          radius=30;
        }else {
          radius=-30;
        }
        if(beta>0){

          bx=cont[me-1].bx-(int)((radius)*cos(beta));
          by=cont[me-1].by-(int)((radius)*sin(beta));

        }else {

          bx=cont[me-1].bx+(int)((radius)*cos(beta));
          by=cont[me-1].by+(int)((radius)*sin(beta));

        }
        tarX=cont[me-1].bx;
        tarY=cont[me-1].by;
        //render objects
        stroke(180,190,110);
        line(tarX,tarY,bx,by);
        node();
        if(me==1){
          //head
          skin(tarX,tarY,20,0);
          int lung=20;
          int alt=20;
          for (int hd=1; hd<5; hd++){
            lung= (int)(lung*.9f);
            alt=(int)(alt*.4f);
            skin(tarX,tarY,20-alt,lung);
          }
        }else if (me==(nBall-1)) {
          //tail
          skin(tarX,tarY,20,0);
          skin(bx,by,20,0);
          int lung=-20;
          int alt=20;
          for (int hd=1; hd<5; hd++){
            lung=(int)(lung*.9f);
            alt=(int)(alt*.4f);
            skin(bx,by,20-alt,lung);
          }
        } else  {
          skin(tarX,tarY,20,0);
        }

      }
    }
    void node(){
      stroke(210,220,130);
      fill(236,99,41);
      ellipseMode(CENTER_DIAMETER);
      ellipse(bx,by,10,10);
    }
    void skin(int skinX,int skinY,int diam,int sposta){
      push();
      for(int i=1;i<5;i++){
        push();
        translate(skinX,skinY);
        float nbeta = atan2(objY,objX);
        rotateZ(nbeta);
        push();
        int q=8;
        float d= 0.0f;
        while(d < TWO_PI) {
          rotateX(TWO_PI/q);
          push();
          for (int ic=0;ic<q;ic++){
            push();

            translate(sposta,diam,0);
            stroke(204, 102, 0);
            point(0,0);
            pop();
          }
          pop();
          d +=TWO_PI/q;

        }

        pop();
        pop();
      }
      pop();
    }

  }

}
}