/* * SwarmApplet.java * * (C) 2005, Alex S. */ import java.awt.*; import java.util.Vector; class MovingObject { public double x,y; public double direction; public double speed; public MovingObject(double x,double y,double direction,double speed){ this.x = x; this.y = y; this.direction = direction; this.speed = speed; } public void move(int w,int h){ double sin = Math.sin(direction); double cos = Math.cos(direction); double nx = x + cos * speed; double ny = y + sin * speed; if(nx > w-1){ nx -= w-1; //cos = -cos; //speed += 0.5*(Math.random()-0.5); } if(nx < 0){ nx += w-1; //cos = -cos; //speed += 0.5*(Math.random()-0.5); } if(ny > h-1){ ny -= h-1; //sin = -sin; //speed += 0.5*(Math.random()-0.5); } if(ny < 0){ ny += h-1; //sin = -sin; //speed += 0.5*(Math.random()-0.5); } if(speed < 0.1) speed = 0.1; if(speed > 10) speed = 10; //direction = Math.atan2(sin,cos); x = nx; y = ny; } } /** * BufferedCanvas */ class BufferedCanvas extends Canvas { private boolean damage = true; // you can force a render private Image image = null; private Graphics buffer = null; private Thread t; private Rectangle r = new Rectangle(0, 0, 0, 0); private final static int NUM_OBJS = 200; private final static int GWIDTH = 40; private final static int GHEIGHT = 40; private final static int RADIUS = 5; private final static double EPSILON = 0.001; private int width,height; private int[] queue = new int[GWIDTH * GHEIGHT]; private int[] queuelast = new int[GWIDTH * GHEIGHT]; private int[] next = new int[NUM_OBJS]; private int[] objx = new int[NUM_OBJS]; private int[] objy = new int[NUM_OBJS]; private MovingObject[] objects = new MovingObject[NUM_OBJS]; // weights that control overall swarm behavior // Separation: steer to avoid crowding local flockmates private float separation = 0; // Alignment: steer towards the average heading of local flockmates private float alignment = 0; // Cohesion: steer to move toward the average position of local flockmat private float cohesion = 0; public void setSeparationAlignmentCohesion(float s,float a,float c){ separation = s; alignment = a; cohesion = c; // normalize float len = (float)Math.sqrt( separation * separation + alignment * alignment + cohesion * cohesion ); if(len > 0){ separation /= len; alignment /= len; cohesion /= len; } //System.out.println("alignment: "+alignment+"; cohesion: "+cohesion+"; separation: "+separation); } /** * initialize things */ public void init(){ for(int i=0;i 0){ dx /= len; dy /= len; cos = (1-xcenterpull)*cos + xcenterpull*dx; sin = (1-ycenterpull)*sin + ycenterpull*dy; sin += 0.03; // downward bias. objects[i].direction = Math.atan2(sin,cos); objects[i].speed = len > RADIUS/2 ? RADIUS/2:len; } } */ int bx = objx[i]; int by = objy[i]; int Ux = bx - 1 < 0 ? 0:bx-1; int Uy = by - 1 < 0 ? 0:by-1; int Lx = bx + 1 > GWIDTH-1 ? GWIDTH-1:bx+1; int Ly = by + 1 > GHEIGHT-1 ? GHEIGHT-1:by+1; //System.out.println("current bucket: "+bx+","+by+" RANGE: ("+Ux+","+Uy+")->("+Lx+","+Ly+")"); // direction stats. double _avgsin = 0; double _avgcos = 0; double _avgx = 0; double _avgy = 0; double _avgspeed = 0; int _numobjects = 0; for(int cy=Uy;cy<=Ly;cy++){ for(int cx=Ux;cx<=Lx;cx++){ //System.out.println("examining: "+cx+", "+cy); int bucket = cy * GWIDTH + cx; for(int j = queue[bucket];j != -1; j = next[j]){ if(i != j){ double ox = objects[j].x; double oy = objects[j].y; double dx = ox - x; double dy = oy - y; double dd = dx * dx + dy * dy; //System.out.print("comparing: "+i+" to "+j+" dd:"+dd+" distsqrt: "+distsquared); if(dd < distsquared){ double dist = Math.sqrt(dd) - EPSILON; double disp = ((diam - dist)/2)/dist; //System.out.print(" dist: "+dist); objects[i].x -= dx * disp; objects[i].y -= dy * disp; objects[j].x += dx * disp; objects[j].y += dy * disp; //objects[i].direction = Math.atan2(-dy,-dx); //objects[j].direction = Math.atan2(dy,dx); //double speed = objects[i].speed; //objects[i].speed = objects[j].speed; //objects[j].speed = speed; } } _avgsin += Math.sin(objects[j].direction); _avgcos += Math.cos(objects[j].direction); _avgspeed += objects[j].speed; _avgx += objects[j].x; _avgy += objects[j].y; _numobjects++; } } } // adjust current object according to averages. _avgsin /= _numobjects; _avgcos /= _numobjects; _avgx /= _numobjects; _avgy /= _numobjects; _avgspeed /= _numobjects; // add some noise into the motion _avgsin += 0.2*(Math.random()-0.5); _avgcos += 0.2*(Math.random()-0.5); objects[i].speed += 0.2*(Math.random()-0.5); // find heading into center of local group. double _dx = _avgx - objects[i].x ; double _dy = _avgy - objects[i].y ; // normalize. double _ddist = Math.sqrt(_dx * _dx + _dy * _dy); // find heading into center of -global- group. double _dxall = avgx - objects[i].x; double _dyall = avgy - objects[i].y; double _ddistall = Math.sqrt(_dxall * _dxall + _dyall * _dyall); if(_ddistall == 0) _ddistall = EPSILON; _dxall /= _ddistall; _dyall /= _ddistall; if(_ddist > 0){ _dx /= _ddist; _dy /= _ddist; } /* * Separation: steer to avoid crowding local flockmates * Alignment: steer towards the average heading of local flockmates * Cohesion: steer to move toward the average position of local flockmat */ // separation alignment cohesion float sep = (float)Math.cos(separation * Math.PI); objects[i].direction = Math.atan2( _avgsin*alignment + sep*_dy*cohesion, _avgcos*alignment + sep*_dx*cohesion ); objects[i].speed += 0.05*(_avgspeed - objects[i].speed); } //System.out.println("alignment: "+alignment+"; cohesion: "+cohesion+"; separation: "+separation); if (true || damage) { g.setColor(Color.white); g.fillRect(0, 0, bounds().width, bounds().height); /* // draw grid. g.setColor(Color.gray); for(int i=0;i