Skip to content

Instantly share code, notes, and snippets.

@uqmessias
Created April 7, 2018 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uqmessias/c44138fc02d0f3358408c612aa26e69e to your computer and use it in GitHub Desktop.
Save uqmessias/c44138fc02d0f3358408c612aa26e69e to your computer and use it in GitHub Desktop.
playing on canvas
<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>
(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