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 · 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>
<a href="/tholman/pen/webbing-boids/1">Edit this Pen</a>
</div>
</body>
</html>