Created
April 4, 2019 14:04
-
-
Save nilkun/f65b5f78b28f0b95c05bc235610c6b09 to your computer and use it in GitHub Desktop.
Explosions and fallout
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
<div> | |
<canvas id="canvas" width=800 height=600></canvas> | |
</div> | |
<div id="buttons"> | |
<button id="explosion">Explosion</button> | |
<button id="fallout">Nuclear Fallout</button> | |
<button id="spin">Galaxy formation</button> | |
<button id="amoeba">Amoeba</button> | |
<div id="colors"> | |
<div class="red box"></div> | |
<div class="green box"></div> | |
<div class="blue box"></div> | |
</div> | |
<button>Number of particles:<br><i id="particles">0</i></button> | |
<input type="range" min="1" max="10000" value="2000" id="slider"> | |
</div> |
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
class PixelManipulation { | |
constructor(canvas) { | |
this.context = canvas.getContext("2d"); | |
this.width = canvas.width; | |
this.height = canvas.height; | |
this.image = this.context.getImageData(0, 0, this.width, this.height); | |
} | |
getImage() { | |
this.image = this.context.getImageData(0, 0, this.width, this.height); | |
} | |
setImage() { | |
this.context.putImageData(this.image, 0, 0); | |
} | |
setPixel(x, y, red, green, blue) { | |
const pixelIndex = (y * this.width + x) * 4; | |
this.image.data[pixelIndex] = red; | |
this.image.data[pixelIndex + 1] = green; | |
this.image.data[pixelIndex + 2] = blue; | |
} | |
fillColor(red, green, blue, alpha = 255) { | |
for (let i = 0; i < this.width * this.height * 4; i+=4) { | |
this.image.data[i] = red; | |
this.image.data[i + 1] = green; | |
this.image.data[i + 2] = blue; | |
this.image.data[i + 3] = alpha; | |
} | |
} | |
} | |
class Particle { | |
constructor() { | |
this.x; | |
this.y; | |
this.direction; | |
this.speed; | |
this.init; | |
this.update; | |
} | |
} | |
class Swarm { | |
constructor(canvas, amount = 10000, color = 1) { | |
this.size = amount; | |
this.particles = []; | |
this.pixels = new PixelManipulation(canvas); | |
this.color = color; | |
this.style = this.initSpin; | |
this.update = this.updateSpin; | |
} | |
setPattern(pattern) { | |
switch(pattern) { | |
case "fallout": { | |
this.style = this.initFallout; | |
this.update = this.updateFallout; | |
break; | |
} | |
case "spin": { | |
this.style = this.initSpin; | |
this.update = this.updateSpin; | |
break; | |
} | |
case "amoeba": { | |
this.style = this.initAmoeba; | |
this.update = this.updateAmoeba; | |
break; | |
} | |
case "explosion": { | |
this.style = this.initExplosion; | |
this.update = this.updateExplosion; | |
break; | |
} | |
} | |
this.init(); | |
}; | |
setColor(color) { | |
this.color = color; | |
}; | |
setParticles(value) { | |
this.size = value; | |
this.init(); | |
} | |
init() { | |
; // 0 = red, 1 = green, 2 = blue | |
this.particles = []; | |
for(let i = 0; i < this.size; i++) { | |
this.particles.push(new Particle); | |
// this.particles[i].update = this.particles[i].updateSpin; | |
this.particles[i].update = this.update; | |
this.particles[i].init = this.style; | |
this.particles[i].init(); | |
} | |
this.pixels.fillColor(0, 0, 0); | |
this.pixels.setImage(); | |
} | |
initFallout() { | |
this.direction = 2 * Math.PI * Math.random(); | |
this.speed = 0.02 * Math.random(); | |
this.x = 0; | |
this.y = 0; | |
// this.update = this.updateFallout; | |
} | |
updateFallout(delta) { | |
const xspeed = this.speed * Math.cos(this.direction); | |
const yspeed = this.speed * Math.sin(this.direction); | |
this.x += xspeed * delta; | |
this.y += yspeed * delta; | |
if(this.x <= -1.0 || this.x >= 1.0 || this.y <= -1.0 || this.y >= 1.0) { | |
this.x = -1.10; | |
this.y = -1.10 | |
} | |
} | |
initExplosion() { | |
this.direction = 2 * Math.PI * Math.random(); | |
this.speed = 0.02 * Math.random(); | |
this.x = 0; | |
this.y = 0; | |
this.speed *= this.speed/2; | |
// this.update = this.updateExplosion; | |
} | |
updateExplosion(delta) { | |
const xspeed = this.speed * Math.cos(this.direction); | |
const yspeed = this.speed * Math.sin(this.direction); | |
this.x += xspeed * delta; | |
this.y += yspeed * delta; | |
if(this.x <= -1.0 || this.x >= 1.0 || this.y <= -1.0 || this.y >= 1.0) { | |
// this.init(); | |
this.x = -1.10; | |
this.y = -1.10 | |
} | |
} | |
initSpin() { | |
this.direction = 2 * Math.PI * Math.random(); | |
this.speed = 0.02 * Math.random(); | |
this.x = 0; | |
this.y = 0; | |
this.speed *= this.speed/2; | |
// this.update = this.updateSpin; | |
} | |
updateSpin(delta) { | |
this.direction += 0.01; | |
const xspeed = this.speed * Math.cos(this.direction); | |
const yspeed = this.speed * Math.sin(this.direction); | |
this.x += xspeed * delta; | |
this.y += yspeed * delta; | |
if(this.x <= -1.0 || this.x >= 1.0 || this.y <= -1.0 || this.y >= 1.0) { | |
// this.init(); | |
this.x = -1.10; | |
this.y = -1.10 | |
} | |
} | |
initAmoeba() { | |
this.direction = 2 * Math.PI * Math.random(); | |
this.speed = 0.02 * Math.random(); | |
this.x = 0; | |
this.y = 0; | |
this.speed *= this.speed/2; | |
// this.update = this.updateAmoeba; | |
} | |
updateAmoeba(delta) { | |
this.direction += Math.random();; | |
const xspeed = this.speed * Math.cos(this.direction); | |
const yspeed = this.speed * Math.sin(this.direction); | |
this.x += xspeed * delta; | |
this.y += yspeed * delta; | |
if(this.x <= -1.0 || this.x >= 1.0 || this.y <= -1.0 || this.y >= 1.0) { | |
// this.init(); | |
this.x = -1.10; | |
this.y = -1.10 | |
} | |
} | |
render(delta) { | |
const width = 800; | |
const height = 600; | |
const oldPixels = this.pixels.context.getImageData(0, 0, width, height).data; | |
for(let y=0; y<height; y++) { | |
for(let x = 0; x<width; x++) { | |
let redTotal = 0; | |
for(let row = -1; row <=1; row++) { | |
for(let col = -1; col <=1; col++) { | |
let currentX = x + col; | |
let currentY = y + row; | |
if(currentX >= 0 && currentX < width && currentY >= 0 && currentY < height) { | |
let red = oldPixels[4*(currentY * width + currentX) + this.color] | |
redTotal += red; | |
} | |
} | |
} | |
this.pixels.image.data[4*(y * width + x) + this.color] = redTotal / 9; | |
} | |
} | |
for(let i = 0; i < this.size; i++) { | |
const p = this.particles[i]; | |
p.update(delta); | |
const xPos = Math.floor((1 + p.x) * width/2); | |
const yPos = Math.floor(p.y * width/2 + height/2); | |
this.pixels.image.data[4 * (yPos * width + xPos) + this.color] = 255; | |
} | |
this.pixels.setImage(); | |
} | |
} | |
const fallout = document.querySelector("#fallout"); | |
const explosion = document.querySelector("#explosion"); | |
const spin = document.querySelector("#spin"); | |
const amoeba = document.querySelector("#amoeba"); | |
const red = document.querySelector(".red"); | |
const green = document.querySelector(".green"); | |
const blue = document.querySelector(".blue"); | |
const particles = document.querySelector("#particles"); | |
const slider = document.querySelector("#slider"); | |
fallout.addEventListener("click", () => swarm.setPattern("fallout")); | |
explosion.addEventListener("click", () => swarm.setPattern("explosion")); | |
amoeba.addEventListener("click", () => swarm.setPattern("amoeba")); | |
spin.addEventListener("click", () => swarm.setPattern("spin")); | |
slider.addEventListener("input", () => { | |
particles.innerHTML = slider.value; | |
}); | |
slider.addEventListener("mouseup", () => { | |
swarm.setParticles(slider.value); | |
}); | |
red.addEventListener("click", () => swarm.setColor(0)); | |
green.addEventListener("click", () => swarm.setColor(1)); | |
blue.addEventListener("click", () => swarm.setColor(2)); | |
// start | |
slider.value = 2000; | |
particles.innerHTML = slider.value; | |
let currentTime = Date.now(); | |
let previousTime = Date.now(); | |
let deltaTime = 0; | |
const swarm = new Swarm(canvas, slider.value); | |
swarm.init(); | |
setInterval(() => { | |
currentTime = Date.now(); | |
swarm.render(deltaTime); | |
deltaTime = currentTime - previousTime; | |
previousTime = currentTime; | |
}, 1000/48); |
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 { | |
display: flex; | |
flex-direction: row; | |
} | |
#buttons { | |
margin: 10px; | |
/* padding: 10px; */ | |
display: flex; | |
flex-direction: column; | |
} | |
#colors { | |
margin: 10px; | |
/* padding: 10px; */ | |
display: flex; | |
flex-direction: row; | |
justify-content: space-evenly; | |
/* background: grey; */ | |
} | |
.box { | |
width: 20px; | |
height: 20px; | |
} | |
.red { | |
background: red; | |
} | |
.green { | |
background: green; | |
} | |
.blue { | |
background: blue; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment