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();