danwhite85
6/18/2012 - 9:43 PM

A web page created at CodePen.io

A web page created at CodePen.io


var width = window.innerWidth - 8, height = window.innerHeight - 8, timerID = 0, c2 = document.getElementById('c'), ctx = c2.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
    c2.width = width;
    c2.height = height;
	
	var speed = 10;
	var size = 1;
	var boids = [];
    var points = new Array();
	var totalBoids = 7;
    var pointCount = 0;
	
	var init = function(){
	
		for (var i = 0; i < totalBoids; i++) {
		
			boids.push({
				x: Math.random() * width,
				y: Math.random() * height,
				v: {
					x: Math.random() * 2 - 1,
					y: Math.random() * 2 - 1
				}
			});
		}
		setInterval(update, 40);	
	}
	
	var calculateDistance = function(v1, v2){
		x = Math.abs(v1.x - v2.x);
		y = Math.abs(v1.y - v2.y);
		
		return Math.sqrt((x * x) + (y * y));
	}
	
	var checkWallCollisions = function(index){
		if (boids[index].x > width) {
			boids[index].x = 0;
		}
		else 
			if (boids[index].x < 0) {
				boids[index].x = width;
			}
		
		if (boids[index].y > height) {
			boids[index].y = 0;
		}
		else 
			if (boids[index].y < 0) {
				boids[index].y = height;
			}
	}
	
	var addForce = function(index, force){
	
		boids[index].v.x += force.x;
		boids[index].v.y += force.y;
		
		magnitude = calculateDistance({
			x: 0,
			y: 0
		}, {
			x: boids[index].v.x,
			y: boids[index].v.y
		});
		
		boids[index].v.x = boids[index].v.x / magnitude;
		boids[index].v.y = boids[index].v.y / magnitude;
	}
	
	//This should be in multiple functions, but this will
	//save tons of looping - Gross!
	var applyForces = function(index){
		percievedCenter = {
			x: 0,
			y: 0
		};
		flockCenter = {
			x: 0,
			y: 0
		};
		percievedVelocity = {
			x: 0,
			y: 0
		};
		count = 0;
		for (var i = 0; i < boids.length; i++) {
			if (i != index) {
			
				//Allignment
				dist = calculateDistance(boids[index], boids[i]);
				
				//console.log(dist);
				if (dist > 0 && dist < 50) {
					count++;
					
					//Alignment
					percievedCenter.x += boids[i].x;
					percievedCenter.y += boids[i].y;
					
					//Cohesion
					percievedVelocity.x += boids[i].v.x;
					percievedVelocity.y += boids[i].v.y;
					//Seperation
					if (calculateDistance(boids[i], boids[index]) < 10) {
						flockCenter.x -= (boids[i].x - boids[index].x);
						flockCenter.y -= (boids[i].y - boids[index].y);
					}
				}
			}
		}
		if (count > 0) {
			percievedCenter.x = percievedCenter.x / count;
			percievedCenter.y = percievedCenter.y / count;
			
			percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
			percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
			
			percievedVelocity.x = percievedVelocity.x / count;
			percievedVelocity.y = percievedVelocity.y / count;
			
			flockCenter.x /= count;
			flockCenter.y /= count;
		}
		
		addForce(index, percievedCenter);
		
		addForce(index, percievedVelocity);
		
		addForce(index, flockCenter);
	}
	
	var update = function(){
	
		for (var i = 0; i < boids.length; i++) {
		
        
            var d, dx, dy,j;
        
			//Draw boid
			
			ctx.strokeStyle = "rgba(0, 0 , 0, 0.5)";
			ctx.lineWidth = size;
            
            ctx.beginPath();
			ctx.moveTo(boids[i].x, boids[i].y);
			
            boids[i].x += boids[i].v.x * speed;
			boids[i].y += boids[i].v.y * speed;
			applyForces(i);
            
			ctx.lineTo(boids[i].x, boids[i].y);
            ctx.stroke();
            
            
            points.push( [ boids[i].x, boids[i].y ] );
			
            
            //Web
            ctx.strokeStyle = "rgba(0, 0 , 0, 0.1)";
            			
            for (j = 0; j < points.length; j++)
        	{
    			dx = points[j][0] - points[pointCount][0];
    			dy = points[j][1] - points[pointCount][1];
    			d = dx * dx + dy * dy;
    			
				
    			if (d < 2500 && Math.random() > 0.9)
    			{				
    			    ctx.beginPath();
    				ctx.moveTo( points[pointCount][0], points[pointCount][1]);
    				ctx.lineTo( points[j][0], points[j][1]);
    				ctx.stroke();
    			}
    		}       
		
			pointCount++;
			checkWallCollisions(i);	
			
		}
	}
	
	//Gui uses this to clear the canvas
	 var clearCanvas = function(){
		ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
		ctx.beginPath();
		ctx.rect(0, 0, width, height);
		ctx.closePath();
		ctx.fill();
	}
    
    init();
<canvas id='c'></canvas>


<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">

  <title>Webbing Boids &middot; CodePen</title>

  <style>
    #codepen-footer, #codepen-footer * {
      -webkit-box-sizing: border-box !important;
      -moz-box-sizing: border-box !important;
      box-sizing: border-box !important;
    }
    #codepen-footer {
      display: block !important;
      position: absolute !important;
      bottom: 0 !important;
      left: 0 !important;
      width: 100% !important;
      padding: 0 10px !important;
      margin: 0 !important;
      height: 30px !important;
      line-height: 30px !important;
      font-size: 12px !important;
      color: #eeeeee !important;
      background-color: #505050 !important;
      text-align: left !important;
      background: -webkit-linear-gradient(top, #505050, #383838) !important;
      background: -moz-linear-gradient(top, #505050, #383838) !important;
      background: -ms-linear-gradient(top, #505050, #383838) !important;
      background: -o-linear-gradient(top, #505050, #383838) !important;
      border-top: 1px solid black !important;
      border-bottom: 1px solid black !important;
      box-shadow: inset 0 1px 0 #6e6e6e, 0 2px 2px rgba(0, 0, 0, 0.4) !important;
      z-index: 300 !important; 
      font-family: "Lucida Grande", "Lucida Sans Unicode", Tahoma, sans-serif !important;
      letter-spacing: 0 !important;
      word-spacing: 0 !important;
    }
    #codepen-footer a {
      color: #a7a7a7 !important; 
      text-decoration: none !important;
    }
    #codepen-footer a:hover {
      color: white !important; 
    }
  </style>

  <script src="http://codepen.io/javascripts/libs/prefixfree.min.js"></script>

</head>
<body>

  <canvas id='c'></canvas>

  <script src="http://codepen.io/javascripts/libs/modernizr.js"></script>

  <script>
(function() {

var width = window.innerWidth - 8, height = window.innerHeight - 8, timerID = 0, c2 = document.getElementById('c'), ctx = c2.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
    c2.width = width;
    c2.height = height;

	var speed = 10;
	var size = 1;
	var boids = [];
    var points = new Array();
	var totalBoids = 7;
    var pointCount = 0;

	var init = function(){

		for (var i = 0; i < totalBoids; i++) {

			boids.push({
				x: Math.random() * width,
				y: Math.random() * height,
				v: {
					x: Math.random() * 2 - 1,
					y: Math.random() * 2 - 1
				}
			});
		}
		setInterval(update, 40);	
	}

	var calculateDistance = function(v1, v2){
		x = Math.abs(v1.x - v2.x);
		y = Math.abs(v1.y - v2.y);

		return Math.sqrt((x * x) + (y * y));
	}

	var checkWallCollisions = function(index){
		if (boids[index].x > width) {
			boids[index].x = 0;
		}
		else 
			if (boids[index].x < 0) {
				boids[index].x = width;
			}

		if (boids[index].y > height) {
			boids[index].y = 0;
		}
		else 
			if (boids[index].y < 0) {
				boids[index].y = height;
			}
	}

	var addForce = function(index, force){

		boids[index].v.x += force.x;
		boids[index].v.y += force.y;

		magnitude = calculateDistance({
			x: 0,
			y: 0
		}, {
			x: boids[index].v.x,
			y: boids[index].v.y
		});

		boids[index].v.x = boids[index].v.x / magnitude;
		boids[index].v.y = boids[index].v.y / magnitude;
	}

	//This should be in multiple functions, but this will
	//save tons of looping - Gross!
	var applyForces = function(index){
		percievedCenter = {
			x: 0,
			y: 0
		};
		flockCenter = {
			x: 0,
			y: 0
		};
		percievedVelocity = {
			x: 0,
			y: 0
		};
		count = 0;
		for (var i = 0; i < boids.length; i++) {
			if (i != index) {

				//Allignment
				dist = calculateDistance(boids[index], boids[i]);

				//console.log(dist);
				if (dist > 0 && dist < 50) {
					count++;

					//Alignment
					percievedCenter.x += boids[i].x;
					percievedCenter.y += boids[i].y;

					//Cohesion
					percievedVelocity.x += boids[i].v.x;
					percievedVelocity.y += boids[i].v.y;
					//Seperation
					if (calculateDistance(boids[i], boids[index]) < 10) {
						flockCenter.x -= (boids[i].x - boids[index].x);
						flockCenter.y -= (boids[i].y - boids[index].y);
					}
				}
			}
		}
		if (count > 0) {
			percievedCenter.x = percievedCenter.x / count;
			percievedCenter.y = percievedCenter.y / count;

			percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
			percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;

			percievedVelocity.x = percievedVelocity.x / count;
			percievedVelocity.y = percievedVelocity.y / count;

			flockCenter.x /= count;
			flockCenter.y /= count;
		}

		addForce(index, percievedCenter);

		addForce(index, percievedVelocity);

		addForce(index, flockCenter);
	}

	var update = function(){

		for (var i = 0; i < boids.length; i++) {

            var d, dx, dy,j;

			//Draw boid

			ctx.strokeStyle = "rgba(0, 0 , 0, 0.5)";
			ctx.lineWidth = size;

            ctx.beginPath();
			ctx.moveTo(boids[i].x, boids[i].y);

            boids[i].x += boids[i].v.x * speed;
			boids[i].y += boids[i].v.y * speed;
			applyForces(i);

			ctx.lineTo(boids[i].x, boids[i].y);
            ctx.stroke();

            points.push( [ boids[i].x, boids[i].y ] );

            //Web
            ctx.strokeStyle = "rgba(0, 0 , 0, 0.1)";

            for (j = 0; j < points.length; j++)
        	{
    			dx = points[j][0] - points[pointCount][0];
    			dy = points[j][1] - points[pointCount][1];
    			d = dx * dx + dy * dy;

    			if (d < 2500 && Math.random() > 0.9)
    			{				
    			    ctx.beginPath();
    				ctx.moveTo( points[pointCount][0], points[pointCount][1]);
    				ctx.lineTo( points[j][0], points[j][1]);
    				ctx.stroke();
    			}
    		}       

			pointCount++;
			checkWallCollisions(i);	

		}
	}

	//Gui uses this to clear the canvas
	 var clearCanvas = function(){
		ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
		ctx.beginPath();
		ctx.rect(0, 0, width, height);
		ctx.closePath();
		ctx.fill();
	}

    init();

})();
  </script>

  <div id="codepen-footer">
    <a style="color: #f73535 !important;" href="https://codepen.wufoo.com/forms/m7x3r3/def/field14=" onclick="window.open(this.href,  null, 'height=517, width=680, toolbar=0, location=0, status=1, scrollbars=1, resizable=1'); return false">Report Abuse</a>

    &nbsp;

    <a href="/tholman/pen/webbing-boids/1">Edit this Pen</a>
  </div>

</body>

</html>