A Pen by lilgreenland on CodePen.
Last active
April 1, 2016 13:20
-
-
Save lilgreenland/685febe3fb63a7687cba to your computer and use it in GitHub Desktop.
particles with settings
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
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); | |
}; |
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
<script src="http://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script> |
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
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