Created
April 7, 2018 23:08
-
-
Save uqmessias/c44138fc02d0f3358408c612aa26e69e to your computer and use it in GitHub Desktop.
playing on canvas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Bouncing Circles</title> | |
<script> | |
// shim layer with setTimeout fallback | |
window.requestAnimFrame = (function(){ | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function( callback ){ | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
</script> | |
</head> | |
<body style="margin: 0px"> | |
<canvas width="1290" height="800" | |
id="myCanvas"></canvas> | |
<script src="script-canvas.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
var canv = document.getElementById('myCanvas'), | |
c = canv.getContext('2d'), | |
/*gravity = 0.91, | |
dampening = 0.09, | |
pullStrength = 0.09, | |
circles = [ ], | |
numCircles = 3, | |
radius = 100, | |
repulsion = 0.710,*/ | |
gravity = 0.1, | |
dampening = 0.90, | |
pullStrength = 0.09, | |
circles = [ ], | |
numCircles = 15, | |
radius = 100, | |
repulsion = 15, | |
mouseDown = false, automatic = false, | |
mouseX, mouseY, counterBase = 0; | |
function initializeCircles(){ | |
// Initialize the array of circle objects | |
for(var i = 0; i < numCircles; i++){ | |
var thisRadius = Math.random() * radius; | |
circles.push({ | |
x: Math.random() * canv.width, | |
y: Math.random() * canv.height, | |
// (vx, vy) = Velocity vector | |
vx: 0, | |
vy: 0, | |
dampening : dampening, | |
repulsion : thisRadius / 180, | |
pullStrength: pullStrength, | |
radius: thisRadius, | |
gravity: thisRadius / 100 | |
}); | |
} | |
} | |
function getX(maxWidth){ | |
var second = new Date().getSeconds(); | |
return (second * maxWidth) / 60; | |
} | |
function getY(maxHeight){ | |
var millisecond = new Date().getMilliseconds(); | |
return (millisecond * maxHeight) / 1000; | |
} | |
function xEhDivisorDeY(x, y){ | |
return x % y == 0; | |
} | |
// This function is called 60 times each second | |
function executeFrame(){ | |
var i, j, circle; | |
for(i = 0; i < numCircles; i++){ | |
circle = circles[i]; | |
// Handle velocity, gravity, and dampening | |
incrementSimulation(circle); | |
// Bounce off the 4 walls | |
bounce(circle); | |
// Collision for all pairs | |
for(j = i+1; j < numCircles; j++){ | |
collide(circle, circles[j]); | |
} | |
// Draw each circle | |
c.beginPath(); | |
c.arc(circle.x, circle.y, circle.radius, | |
0, 2*Math.PI); | |
c.closePath(); | |
c.fillStyle = xEhDivisorDeY(i, 9) ? 'red' : (xEhDivisorDeY(i, 8) ? 'green' : (xEhDivisorDeY(i, 7) ? 'yellow' : (xEhDivisorDeY(i, 6) ? 'gray' : (xEhDivisorDeY(i, 5) ? 'silver' : (xEhDivisorDeY(i, 4) ? 'blue' : (xEhDivisorDeY(i, 3) ? 'pink' : (xEhDivisorDeY(i, 2) ? 'purple' : 'cyan') ) ) ) ) ) ); | |
c.fill(); | |
} | |
// Fill a semi-transparent white rectangle | |
// for the ghosting trail effect. | |
//c.fillStyle = 'rgba(255,255,255,0.05)'; | |
c.fillStyle = 'rgba(0,0,0,0.4)'; | |
c.fillRect(0, 0, canv.width, canv.height); | |
// Increment mouse interaction (pulling) | |
executeInteraction(); | |
// Schedule the next frame | |
requestAnimFrame(executeFrame); | |
} | |
function incrementSimulation(circle){ | |
// Increment location by velocity | |
circle.x += circle.vx; | |
circle.y += circle.vy; | |
// Increment Gravity | |
circle.vy += circle.gravity; | |
// Slow it down | |
circle.vy *= circle.dampening; | |
circle.vx *= circle.dampening; | |
} | |
function bounce(circle){ | |
// bottom | |
if(circle.y + circle.radius > canv.height){ | |
circle.y = canv.height - circle.radius; | |
circle.vy = -Math.abs(circle.vy); | |
} | |
// right | |
if(circle.x + circle.radius > canv.width){ | |
circle.x = canv.width - circle.radius; | |
circle.vx = -Math.abs(circle.vx); | |
} | |
// top | |
if(circle.y - circle.radius < 0){ | |
circle.y = circle.radius; | |
circle.vy = Math.abs(circle.vy); | |
} | |
// left | |
if(circle.x - circle.radius < 0){ | |
circle.x = circle.radius; | |
circle.vx = Math.abs(circle.vx); | |
} | |
} | |
// Collides two circles `a` and `b`. | |
function collide(a, b){ | |
// (dx, dy) distance in x and y | |
var dx = b.x - a.x, | |
dy = b.y - a.y, | |
// d = distance from `a` to `b` | |
d = Math.sqrt(dx*dx + dy*dy), | |
// (ux, uy) = unit vector | |
// in the a -> b direction | |
ux = dx / d, | |
uy = dy / d; | |
// If the balls are on top of one another, | |
if(d < a.radius + b.radius){ | |
// then execute a repulsive force to | |
// push them apart, which resembles collision. | |
a.vx -= ux * b.repulsion; | |
a.vy -= uy * b.repulsion; | |
b.vx += ux * a.repulsion; | |
b.vy += uy * a.repulsion; | |
} | |
} | |
document.addEventListener('keyup', function(e){ | |
if(e.keyCode == 32){ | |
automatic = !automatic; | |
mouseDown = automatic; | |
} | |
}); | |
canv.addEventListener('mousedown', function(e){ | |
mouseDown = true; | |
mouseX = e.pageX; | |
mouseY = e.pageY; | |
}); | |
canv.addEventListener('mouseup', function(e){ | |
mouseDown = false; | |
}); | |
canv.addEventListener('mousemove', function(e){ | |
mouseX = e.pageX; | |
mouseY = e.pageY; | |
}); | |
// Pulls circles toward the mouse when it is down. | |
function executeInteraction(){ | |
var dx, dy, i, circle, x = getX(canv.width), y = getY(canv.height); | |
if(automatic) | |
customAnimation(x, y, 50); | |
if(mouseDown){ | |
for(i = 0; i < numCircles; i++){ | |
circle = circles[i]; | |
dx = mouseX - circle.x; | |
dy = mouseY - circle.y; | |
circle.vx += dx * circle.pullStrength; | |
circle.vy += dy * circle.pullStrength; | |
} | |
} | |
} | |
function customAnimation(x, y, maxSeconds){ | |
if((++counterBase) > maxSeconds){ | |
console.log(counterBase); | |
mouseX = x; | |
mouseY = y; | |
counterBase = 0; | |
} | |
mouseDown = true; | |
} | |
initializeCircles(); | |
// Start animation | |
executeFrame(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment