Skip to content

Instantly share code, notes, and snippets.

@lilgreenland
Last active April 1, 2016 13:20
Show Gist options
  • Save lilgreenland/685febe3fb63a7687cba to your computer and use it in GitHub Desktop.
Save lilgreenland/685febe3fb63a7687cba to your computer and use it in GitHub Desktop.
particles with settings
var particles = new function() {
// canvas setup
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
//resize canvas if window changes
window.onresize = function(event) {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
};
// variables
var settings = new function() {
this.totalParticles = window.innerWidth*window.innerHeight/5000
this.composite = "source-over"
this.alpha = 1;
this.wipeAlpha = 1;
this.gravity = 0;
this.verticalGravity = 0;
this.horizontalGravity = 0;
this.collision = true;
this.restitution = 1; //speed loss on collision with wall or particle
this.friction = 1; //speed loss every cycle
this.repulse = 0.016; //controls force of collision (no idea why this needs to be 0.004)
this.spawnSpeed = 15;
this.spawnVx = 1;
this.spawnVy = 1;
this.fill = false;
this.stroke = true;
this.strokeWidth = 2;
this.strokeColor = "#ffffff";
this.fillColor = "#ffffff";
this.push = function() {
for (var i = 0; i < stars.length; i++) {
stars[i].Vx += -5 * Math.cos(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
stars[i].Vy += -5 * Math.sin(Math.atan2(stars[i].y - mousePos.y, stars[i].x - mousePos.x));
}
};
/* this.message = 'dat.gui';
this.speed = 0.8;
this.displayOutline = false;
this.explode = function() {}; */
}
//setup dat.GUI to adjust things inside the function controls
var gui = new dat.GUI();
var spawnFolder = gui.addFolder('spawn');
spawnFolder.add(settings, 'spawnVx', -50, 50);
spawnFolder.add(settings, 'spawnVy', -50, 50);
var physicsFolder = gui.addFolder('physics');
//physicsFolder.open();
physicsFolder.add(settings, 'friction', 0.95, 1);
physicsFolder.add(settings, 'restitution', 0.6, 1);
physicsFolder.add(settings, 'collision');
physicsFolder.add(settings, 'repulse', 0.001, 0.02);
physicsFolder.add(settings, 'gravity', -0.1, 0.1);
physicsFolder.add(settings, 'verticalGravity', -0.1, 0.1);
physicsFolder.add(settings, 'horizontalGravity', -0.1, 0.1);
physicsFolder.add(settings, 'push');
var looksFolder = gui.addFolder('looks');
var compositeController = looksFolder.add(settings, 'composite', ['source-over', 'lighter', 'lighten', 'darker', 'darken']);
compositeController.onChange(function(value) {
ctx.globalCompositeOperation = value;
});
looksFolder.add(settings, 'wipeAlpha', 0,1);
var controller = looksFolder.add(settings, 'alpha', 0, 1);
controller.onChange(function(value) {
ctx.globalAlpha = value;
});
looksFolder.add(settings, 'fill');
looksFolder.add(settings, 'stroke');
ctx.lineWidth = settings.strokeWidth;
var controller = looksFolder.add(settings, 'strokeWidth', 0, 20);
controller.onChange(function(value) {
ctx.lineWidth = value;
});
var colorController = looksFolder.addColor(settings, 'strokeColor');
colorController.onChange(function(value) {
ctx.strokeStyle = value;
console.log(settings.fillColor);
});
/* var colorController = looksFolder.addColor(settings, 'fillColor');
colorController.onChange(function(value) {
ctx.fillStyle = value;
}); */
var stars = [];
function pushStar(x,y,Vx,Vy) {
stars.push({
x: x, // + 20 * (Math.random() - 0.5),
y: y, // + 20 * (Math.random() - 0.5),
Vx: Vx,
Vy: Vy,
r: 300 * Math.random()* Math.random()*Math.random()*Math.random()* Math.random() * Math.random() + 10*Math.random()+2, // mass, and radius of circle
color: '#' + Math.floor(Math.random() * 16777216).toString(16), //random color
});
}
//spawns stars at the start
for (var i = 0; i < settings.totalParticles; i++) {
pushStar(canvas.width * Math.random(),canvas.height * Math.random(),
settings.spawnSpeed*Math.random()-settings.spawnSpeed*0.5 ,
settings.spawnSpeed*Math.random()-settings.spawnSpeed*0.5);
}
var mousePos = {
x: 0,
y: 0
};
//gets mouse position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
// waits for mouse move and then updates position
canvas.addEventListener('mousemove', function(evt) {
mousePos = getMousePos(canvas, evt);
}, false);
//onclick add a new star
document.addEventListener("mousedown", function() {
pushStar(mousePos.x,mousePos.y, settings.spawnVx, settings.spawnVy);
});
function wallBounce(i) {
if (stars[i].x > canvas.width - stars[i].r) {
stars[i].Vx *= -settings.restitution;
stars[i].x = canvas.width - stars[i].r;
} else if (stars[i].x < stars[i].r) {
stars[i].Vx *= -settings.restitution;
stars[i].x = stars[i].r;
}
if (stars[i].y > canvas.height - stars[i].r) {
stars[i].Vy *= -settings.restitution;
stars[i].y = canvas.height - stars[i].r;
} else if (stars[i].y < stars[i].r) {
stars[i].Vy *= -settings.restitution;
stars[i].y = stars[i].r;
}
}
function moveStar(i) {
//change position, velocity, size of object elements for each location in array
stars[i].x += stars[i].Vx;
stars[i].y += stars[i].Vy;
//friction slows velocity
stars[i].Vx *= settings.friction;
stars[i].Vy *= settings.friction;
}
function gravity(i) {
if (settings.gravity) {
for (var j = 0; j < stars.length; j++) {
if (i != j) {
var distSquared = (((stars[i].x - stars[j].x) * (stars[i].x - stars[j].x)) + ((stars[i].y - stars[j].y) * (stars[i].y - stars[j].y)));
//limit the magnitude of gravity by capping min distance at 1, to avoid dividing by 0
if (distSquared < 1) {
distSquared = 1;
}
stars[i].Vx += settings.gravity * stars[j].r * stars[i].r * Math.cos(Math.atan2(stars[j].y - stars[i].y, stars[j].x - stars[i].x)) / distSquared;
stars[i].Vy += settings.gravity * stars[j].r * stars[i].r * Math.sin(Math.atan2(stars[j].y - stars[i].y, stars[j].x - stars[i].x)) / distSquared;
}
}
}
}
function collision(i) {
if (settings.collision) {
for (var j = i + 1; j < stars.length; j++) {
if (!(i === j)) {
var dX = stars[i].x - stars[j].x
var dY = stars[i].y - stars[j].y
var dist = Math.sqrt(dX * dX + dY * dY);
if (dist < stars[i].r + stars[j].r) {
/* ctx.beginPath();
ctx.moveTo(stars[i].x, stars[i].y);
ctx.lineTo(stars[j].x, stars[j].y);
ctx.stroke();
*/
var angle = Math.atan2(stars[i].y - stars[j].y, stars[i].x - stars[j].x)
var d_Vx = stars[i].Vx-stars[j].Vx
var d_Vy = stars[i].Vy-stars[j].Vy
var momentum = Math.sqrt(d_Vx*d_Vx + d_Vy*d_Vy) * stars[i].r * stars[j].r * settings.repulse;
stars[i].Vx += Math.cos(angle)*momentum/stars[i].r// * settings.restitution;
stars[i].Vy += Math.sin(angle)*momentum/stars[i].r// * settings.restitution;
stars[i].Vx *= settings.restitution;
stars[i].Vy *= settings.restitution;
stars[j].Vx -= Math.cos(angle)*momentum/stars[j].r// * settings.restitution;
stars[j].Vy -= Math.sin(angle)*momentum/stars[j].r// * settings.restitution;
stars[j].Vx *= settings.restitution;
stars[j].Vy *= settings.restitution;
dist = Math.sqrt(dX * dX + dY * dY);
var overlap = ((stars[i].r + stars[j].r) - dist)
stars[i].x += overlap * Math.cos(angle);
stars[i].y += overlap * Math.sin(angle);
stars[j].x -= overlap * Math.cos(angle);
stars[j].y -= overlap * Math.sin(angle);
}
}
}
}
}
function uniformGravitation(i) {
stars[i].Vx += settings.horizontalGravity;
stars[i].Vy += settings.verticalGravity;
}
function draw(i) {
ctx.beginPath();
ctx.arc(stars[i].x, stars[i].y, stars[i].r, 0, 2 * Math.PI, true);
if (settings.stroke) ctx.stroke();
if (settings.fill) {
ctx.fillStyle = stars[i].color;
ctx.fill();
}
}
function wipeScreen(){
ctx.fillStyle="rgba(255, 255, 255, "+settings.wipeAlpha+")";
ctx.fillRect(0, 0, window.innerWidth, window.innerHeight);
}
function cycle() {
wipeScreen();
for (var i = 0; i < stars.length; i++) {
draw(i);
gravity(i);
uniformGravitation(i)
moveStar(i);
collision(i);
wallBounce(i);
}
requestAnimationFrame(cycle);
}
requestAnimationFrame(cycle);
};
<script src="http://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
body {
font: 15px arial, sans-serif;
background-color: white;
overflow:hidden;
cursor: crosshair;
}
canvas {
position: absolute;
left: 0;
top: 0;
z-index: -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment