Particles in a gravitational field, randomly inverting charge to create interesting behaviors. Uses sketch.js to manage the 2d context and power animation.
A Pen by Justin Windle on CodePen.
Particles in a gravitational field, randomly inverting charge to create interesting behaviors. Uses sketch.js to manage the 2d context and power animation.
A Pen by Justin Windle on CodePen.
| NUM_PARTICLES = 250 | |
| TAIL_LENGTH = 12 | |
| MAX_FORCE = 8 | |
| FRICTION = 0.75 | |
| GRAVITY = 9.81 | |
| COLORS = [ | |
| '#FF4746' | |
| '#E8DA5E' | |
| '#92B55F' | |
| '#487D76' | |
| ] | |
| class Particle | |
| constructor: ( @x = 0.0, @y = 0.0, @mass = 1.0 ) -> | |
| @tail = [] | |
| @radius = @mass * 0.15 | |
| @charge = random [ -1, 1 ] | |
| @color = random COLORS | |
| @fx = @fy = 0.0 | |
| @vx = @vy = 0.0 | |
| Sketch.create | |
| particles: [] | |
| setup: -> | |
| for i in [0..NUM_PARTICLES] by 1 | |
| x = random @width | |
| y = random @height | |
| m = random 0.5, 8.0 | |
| @particles.push new Particle x, y, m | |
| draw: -> | |
| @lineCap = @lineJoin = 'round' | |
| for i in [0..NUM_PARTICLES] by 1 | |
| a = @particles[i] | |
| # invert charge | |
| if random() < 0.08 then a.charge = -a.charge | |
| for j in [i+1..NUM_PARTICLES] by 1 | |
| b = @particles[j] | |
| # delta vector | |
| dx = b.x - a.x | |
| dy = b.y - a.y | |
| # distance | |
| dst = sqrt dSq = ( dx * dx + dy * dy ) + 0.1 | |
| rad = a.radius + b.radius | |
| if dst >= rad | |
| # derivative of unit length for normalisation | |
| len = 1.0 / dst | |
| fx = dx * len | |
| fy = dy * len | |
| # gravitational force | |
| f = min MAX_FORCE, ( GRAVITY * a.mass * b.mass ) / dSq | |
| a.fx += f * fx * b.charge | |
| a.fy += f * fy * b.charge | |
| b.fx += -f * fx * a.charge | |
| b.fy += -f * fy * a.charge | |
| # integrate | |
| a.vx += a.fx | |
| a.vy += a.fy | |
| a.vx *= FRICTION | |
| a.vy *= FRICTION | |
| a.tail.unshift x: a.x, y: a.y | |
| a.tail.pop() if a.tail.length > TAIL_LENGTH | |
| a.x += a.vx | |
| a.y += a.vy | |
| # reset force | |
| a.fx = a.fy = 0.0 | |
| # wrap | |
| if a.x > @width + a.radius | |
| a.x = -a.radius | |
| a.tail = [] | |
| else if a.x < -a.radius | |
| a.x = @width + a.radius | |
| a.tail = [] | |
| if a.y > @height + a.radius | |
| a.y = -a.radius | |
| a.tail = [] | |
| else if a.y < -a.radius | |
| a.y = @height + a.radius | |
| a.tail = [] | |
| # draw | |
| @strokeStyle = a.color | |
| @lineWidth = a.radius * 2.0 | |
| @beginPath() | |
| @moveTo a.x, a.y | |
| @lineTo p.x, p.y for p in a.tail | |
| @stroke() |
| <script src="http://soulwire.github.io/sketch.js/js/sketch.min.js"></script> |
| @import compass | |
| html, body | |
| background: #1b1b1b |