During my girlfriend's prom, I found it interesting how quickly everyone in a crowd of people could align to all face the same direction when a certain song came on where everyone danced in unison (like the Macerena). I figured each individual had some field of view in front of them and they were turning toward the average vector of all of the people in front of them, so I tried modeling it. My code gets some alignment, but then some strange wave pattern sweeps through the crowd and I'm not sure why.

read more

dancer.java

			
import java.awt.Polygon;
import java.awt.Rectangle;
import java.lang.reflect.Array;


public class dancer  {

	double orientation;
	int xposition; 
	int yposition;
	int xBounds; 
	int yBounds;
	int size;
	 Polygon fieldOfView;
	 
	
	
	public dancer(int i, int j, double orientation,int size,int xBounds, int yBounds){
		this.xposition=i;
		this.yposition=j;
		this.orientation=orientation;
		this.yBounds=yBounds;
		this.xBounds=xBounds;
		this.fieldOfView = new Polygon();
		this.updateFieldOfView();
		this.size = size;
		
		
	//if statements that find points for polygon	
	}

	public void updateFieldOfView(){
		if(this.orientation>=2*Math.PI){
			this.orientation-=2*Math.PI;
		}
		
		double leftSideAngle = this.orientation+Math.PI/2;
		double rightSideAngle = this.orientation-Math.PI/2;
		double maxAdd = 1.5*Math.sqrt((this.xBounds*this.xBounds)+(this.yBounds*this.yBounds));
		 
		 int xpoints[] = new int[3];
		 int ypoints[] = new int[3];
		//Rectangle boundsOfBox = new Rectangle(0,0,xBounds,yBounds);
		
			double leftxPoint = this.xposition +(int)this.size/2 + maxAdd*Math.cos(leftSideAngle);
			double leftyPoint = this.yposition + (int)this.size/2 +maxAdd*Math.sin(leftSideAngle);
	
			double rightxPoint = this.xposition +(int)this.size/2 + maxAdd*Math.cos(rightSideAngle);
			double rightyPoint = this.yposition +(int)this.size/2 + maxAdd*Math.sin(rightSideAngle);
			
	
			double vertexx = this.xposition +(int)this.size/2 + maxAdd*Math.cos(this.orientation);
			double vertexy = this.yposition +(int)this.size/2 + maxAdd*Math.sin(this.orientation);
			
			xpoints[0]=(int)leftxPoint;
			xpoints[1]=(int)rightxPoint;
			xpoints[2]=(int)vertexx;
			ypoints[0]=(int)leftyPoint;
			ypoints[1]=(int)rightyPoint;
			ypoints[2]=(int)vertexy;
			
			
			
			this.fieldOfView=new Polygon(xpoints,ypoints,3);
			
	}
	
	public double getOrientation() {
		return orientation;
	}

	public void setOrientation(double orientation) {
		this.orientation = orientation;
	}


	public int getXposition() {
		return xposition;
	}


	public void setXposition(int xposition) {
		this.xposition = xposition;
	}


	public int getYposition() {
		return yposition;
	}

	public void setYposition(int yposition) {
		this.yposition = yposition;
	}		
}

dancers.java

			
import java.util.Random;

//Perhaps a proximity factor could be introduced. Weight of p1's orientation on p2's orientation is inversely proportional to the distance between them. 
//Or inverse square 

public class dancers {
	boolean drawn = false;
	int numberOfDancers;
	int size;
	int xBounds; 
	int yBounds;
	int speedOfTurn = 5; //higher is slower
	dancer dancers[];
	Random ran = new Random();
	public dancers(int numberOfDancers, int size, int xBounds, int yBounds) {

		this.numberOfDancers = numberOfDancers;
		this.size = size;
		this.dancers = new dancer[numberOfDancers];
		this.xBounds = xBounds;
		this.yBounds= yBounds; 
		
		for (int i = 0; i < numberOfDancers; i++) {
			int xPosition = ran.nextInt(xBounds);
			int yPosition = ran.nextInt(yBounds);
			double orientation = 2*Math.PI*ran.nextDouble();
			dancers[i] = new dancer(xPosition,yPosition,orientation,size,xBounds,yBounds);	
		}

	}
	public void spin(){
		for (int i = 0; i < numberOfDancers; i++) {
			dancers[i].orientation+=.1;
			if(dancers[i].orientation>2*Math.PI){
				dancers[i].orientation-=2*Math.PI;
			}
			//dancers[i].updateFieldOfView();
			//System.out.println(dancers);
		}
	}
	
	public void updateFieldOfView(){
		for (int i = 0; i < numberOfDancers; i++) {
			dancers[i].updateFieldOfView();
		}
	}
	
	public void tryToAlignIncorrectButCool(){
		
		for (int i = 0; i < numberOfDancers; i++) {
			
			double sumOfAngles=0;
			int numberOfPeopleSeen = 0;
			for (int j = 0; j < numberOfDancers; j++) {
				if(dancers[i].fieldOfView.contains(dancers[j].xposition, dancers[j].yposition)){
					sumOfAngles+=dancers[j].orientation;
					numberOfPeopleSeen++;	
				}
			}
			double angleToTendTo=(sumOfAngles)/(numberOfPeopleSeen);
			
			if(angleToTendTo>dancers[i].orientation){
				double distanceNeededToGo=angleToTendTo-dancers[i].orientation;
				dancers[i].orientation+=(distanceNeededToGo/this.speedOfTurn);
			}
			if(angleToTendTo<dancers[i].orientation){
				double distanceNeededToGo=dancers[i].orientation-angleToTendTo;
				dancers[i].orientation+=(distanceNeededToGo/this.speedOfTurn);
			}
			
			
			
		}
	}

	public void tryToAlign() {
		
		double orientationToChangeTo[] = new double [dancers.length];
		
		for (int i = 0; i < numberOfDancers; i++) {

			double sumOfAngles = 0;
			int numberOfPeopleSeen = 0;
			for (int j = 0; j < numberOfDancers; j++) {
				if (dancers[i].fieldOfView.contains(dancers[j].xposition,
						dancers[j].yposition)) {
					sumOfAngles += dancers[j].orientation;
					numberOfPeopleSeen++;
				}
			}
			double angleToTendTo = (sumOfAngles) / (numberOfPeopleSeen);

			if (angleToTendTo > dancers[i].orientation) {
				double distanceNeededToGo = angleToTendTo- dancers[i].orientation;
				orientationToChangeTo[i] = dancers[i].orientation + (distanceNeededToGo / this.speedOfTurn);
			}
			if (angleToTendTo < dancers[i].orientation) {
				double distanceNeededToGo = dancers[i].orientation - angleToTendTo;
				orientationToChangeTo[i] = dancers[i].orientation + (distanceNeededToGo / this.speedOfTurn);
			}

		}
		
		for (int i = 0; i < numberOfDancers; i++) {
			dancers[i].orientation=orientationToChangeTo[i];
		}
	}
	
	
	

	
}

player.java

			
import java.awt.Color;
import java.awt.Graphics;

public class player extends java.applet.Applet implements Runnable {

	int frame;
	int delay;
	int wait=100;
	int increment = 1;
	int displacement = 20;
	int arrowLength = 13;
	int halfOfArrowWidth=5;
	dancers dancers = new dancers(500,10, 1000,1000);
	
	Thread animator;

	/**
	 * Initialize the applet and compute the delay between frames.
	 */
	public void init() {
	
		String str = getParameter("fps");
		int fps = (str != null) ? Integer.parseInt(str) : 100;
		delay = (fps > 0) ? (1000 / fps) : 100;
		if (!dancers.drawn) {
			
			dancers.drawn = true;
			this.setSize(dancers.xBounds,dancers.yBounds);
			
			 }
	}

	/**
	 * This method is called when the applet becomes visible on the screen.
	 * Create a thread and start it.
	 */
	public void start() {
		animator = new Thread(this);
		animator.start();
		
	}

	/**
	 * This method is called by the thread that was created in the start method.
	 * It does the main animation.
	 */
	public void run() {

		while (Thread.currentThread() == animator) {
			// Display the next frame of animation.
			

			// Delay for a while
			 try {
					Thread.sleep(wait);
				    } catch (InterruptedException e) {
					break;
				    }

			// Advance the frame
				    increment++;
					repaint();
			frame++;
			
		}
	}

	/**
	 * This method is called when the applet is no longer visible. Set the
	 * animator variable to null so that the thread will exit before displaying
	 * the next frame.
	 */
	public void stop() {
		animator = null;
	}

	/**
	 * Paint a frame of animation.
	 */
	
	
	int constantincrementor = 0;
	
	public void paint(Graphics g) {
		
		
		
		
		try {
		 Thread.sleep(100);
		 } catch (InterruptedException e) {
		// TODO Auto-generated catch block
		 e.printStackTrace();
		 }
		
		 
		//dancers.spin();
			dancers.updateFieldOfView();
			dancers.tryToAlign();
			//dancers.tryToAlignIncorrectButCool();
			
			
			//g.drawPolygon(dancers.dancers[4].fieldOfView);
			//g.setColor(Color.yellow);
			//g.drawString("Here", dancers.dancers[4].xposition, dancers.dancers[4].yposition);
			
		 
		 if(dancers.drawn){
		
		int a = 1; 
		int b = 1; 
		int c = 1; 
		int d = 1; 
		
		for (int i = 0; i < dancers.numberOfDancers; i++) {
			g.fillOval(dancers.dancers[i].xposition, dancers.dancers[i].yposition, dancers.size, dancers.size);
			
			if(dancers.dancers[i].orientation<=Math.PI/2&&dancers.dancers[i].orientation>=0){
				a=-1;
				b=1;
				c=-1;
				d=1;
			}
				if((dancers.dancers[i].orientation>=Math.PI/2&&dancers.dancers[i].orientation<=Math.PI)){
					a=-1;
					b=1;
					c=-1;
					d=1;
				}
				if((dancers.dancers[i].orientation>=Math.PI&&dancers.dancers[i].orientation<=(3*Math.PI)/2)){
					a=1;
					b=-1;
					c=1;
					d=-1;
				}
				if((dancers.dancers[i].orientation>=(3*Math.PI/2)&&dancers.dancers[i].orientation<=2*Math.PI)){
					a=1;
					b=-1;
					c=1;
					d=-1;
				}
			
			int[] xPoints = {(int)dancers.size/2+dancers.dancers[i].xposition+(int)(arrowLength*Math.cos(dancers.dancers[i].orientation))+(a)*(int)(halfOfArrowWidth*Math.cos(dancers.dancers[i].orientation+(Math.PI/2))),(int)dancers.size/2+dancers.dancers[i].xposition+(int)(arrowLength*Math.cos(dancers.dancers[i].orientation))+(b)*(int)(halfOfArrowWidth*Math.cos(dancers.dancers[i].orientation+(Math.PI/2))),(int)dancers.size/2+dancers.dancers[i].xposition+(int)(arrowLength*Math.cos(dancers.dancers[i].orientation))+(int)(halfOfArrowWidth*Math.cos(dancers.dancers[i].orientation))};
			int[] yPoints = {(int)dancers.size/2+dancers.dancers[i].yposition+(int)(arrowLength*Math.sin(dancers.dancers[i].orientation))+(c)*(int)(halfOfArrowWidth*Math.sin(dancers.dancers[i].orientation+(Math.PI/2))),(int)dancers.size/2+dancers.dancers[i].yposition+(int)(arrowLength*Math.sin(dancers.dancers[i].orientation))+(d)*(int)(halfOfArrowWidth*Math.sin(dancers.dancers[i].orientation+(Math.PI/2))),(int)dancers.size/2+dancers.dancers[i].yposition+(int)(arrowLength*Math.sin(dancers.dancers[i].orientation))+(int)(halfOfArrowWidth*Math.sin(dancers.dancers[i].orientation))};
			
			g.fillPolygon(xPoints, yPoints, 3);
		
			
			g.drawLine(dancers.dancers[i].xposition+(int)dancers.size/2, dancers.dancers[i].yposition+(int)dancers.size/2, (int)dancers.size/2+dancers.dancers[i].xposition+(int)(arrowLength*Math.cos(dancers.dancers[i].orientation)), (int)dancers.size/2+dancers.dancers[i].yposition+(int)(arrowLength*Math.sin(dancers.dancers[i].orientation)));
		}
		
		
	
		
		}
	}
}