Skip to content

Instantly share code, notes, and snippets.

@phuctvt
Created February 9, 2020 05:04
Show Gist options
  • Save phuctvt/a24f3dd37f765f67e7e04c9f95058ac5 to your computer and use it in GitHub Desktop.
Save phuctvt/a24f3dd37f765f67e7e04c9f95058ac5 to your computer and use it in GitHub Desktop.
Fireworks 2.0 (add target to each firework)
class Firework {
constructor() {
this.color = Hsl.random();
this.color.s = 100;
this.color.l = 70;
this.exploder = new Particle(width / 2, height, undefined, this.color);
this.target = new Vector(random(50, width - 50), random(0, 3 * height / 4));
this.exploder.vel = this.exploder.loc.getForceTo(this.target, gravity);
this.explodeParticles = [];
this.nOfParticles = random(30, 40);
this.isExploded = false;
}
update() {
if (this.exploder.vel.y > 0 && !this.isExploded) {
this.isExploded = true;
this.initExplodeParticles();
}
if (!this.isExploded) {
this.exploder.update();
} else {
for (let p of this.explodeParticles) {
if (!p.wasDoneExploding()) {
p.update();
}
}
}
}
render() {
if (!this.isExploded) {
this.exploder.render();
} else if (!this.done) {
for (let p of this.explodeParticles) {
if (!p.wasDoneExploding()) {
p.render();
}
}
}
}
applyForce(force) {
if (!this.isExploded) {
this.exploder.applyForce(force);
} else if (!this.done) {
for (let p of this.explodeParticles) {
if (!p.wasDoneExploding()) {
p.applyForce(force);
}
}
}
}
initExplodeParticles() {
for (let i = 0; i < this.nOfParticles; i++) {
let particle = new Particle(
this.exploder.loc.x,
this.exploder.loc.y,
Vector.randomVector(),
this.color,
50
);
this.explodeParticles.push(particle);
}
}
wasDone() {
if (this.explodeParticles.length === 0) return false;
for (let p of this.explodeParticles) {
if (!p.wasDoneExploding()) {
return false;
}
}
return true;
}
}
let canvas;
let ctx;
let width, height;
window.onload = () => {
setup();
loopDraw();
}
function loopDraw() {
draw();
window.requestAnimationFrame(loopDraw);
}
function createCanvas(color, w, h) {
document.body.style.margin = '0px';
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
canvas.width = w || window.innerWidth;
canvas.height = h || window.innerHeight;
canvas.style.display = 'block';
width = canvas.width;
height = canvas.height;
document.body.append(canvas);
ctx.save();
ctx.fillStyle = color || 'white';
ctx.fillRect(0, 0, width, height);
ctx.restore();
}
function rect(x, y, w, h, color) {
ctx.save();
ctx.fillStyle = color || 'black';
ctx.fillRect(x, y, w, h);
ctx.restore();
}
function circle(x, y, r, color) {
ctx.save();
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = color || 'black';
ctx.fill();
ctx.restore();
}
class Hsl {
constructor(h, s, l, a) {
this.h = h;
this.s = s;
this.l = l;
this.a = a;
}
toString() {
return this.a ?
`hsla(${this.h}, ${this.s}%, ${this.l}%, ${this.a})` :
`hsl(${this.h}, ${this.s}%, ${this.l}%)`;
}
static random() {
let hsl = new Hsl();
hsl.h = random(0, 360);
hsl.s = random(0, 100);
hsl.l = random(0, 100);
return hsl;
}
}
<!DOCTYPE html>
<html>
<head>
<title>Fireworks</title>
<script type="text/javascript" src="tool.js"></script>
<script type="text/javascript" src="hsl.js"></script>
<script type="text/javascript" src="vector.js"></script>
<script type="text/javascript" src="graph.js"></script>
<script type="text/javascript" src="particle.js"></script>
<script type="text/javascript" src="firework.js"></script>
</head>
<body>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
class Particle {
constructor(x, y, vel, color, explodeLifespan) {
this.r = 3;
this.loc = new Vector(x, y);
this.vel = vel || new Vector(0, 0);
this.acc = new Vector(0, 0);
this.explodeLifespan = explodeLifespan;
this.explodeCurrentLs = 0;
this.color = color;
}
update() {
this.vel.add(this.acc);
this.loc.add(this.vel);
this.acc.mult(0);
if (this.explodeLifespan) {
this.explodeCurrentLs++;
let progress = this.explodeCurrentLs / this.explodeLifespan;
if (progress > 0.7 && progress < 1.0) {
this.color.a = 1 - (progress - 0.7) / 0.3;
}
}
}
render() {
circle(this.loc.x, this.loc.y, this.r, this.color.toString());
}
applyForce(force) {
this.acc.add(force);
}
wasDoneExploding() {
return this.explodeCurrentLs > this.explodeLifespan;
}
}
let gravity = new Vector(0, 0.1);
let fireworks = [];
function setup() {
createCanvas('black');
}
function draw() {
rect(0, 0, width, height, 'rgba(0, 0, 0, .3)');
if (random(1, 10) === 1) {
fireworks.push(new Firework());
}
for (let firework of fireworks) {
firework.applyForce(gravity);
firework.update();
firework.render();
}
for (let i = 0; i < fireworks.length; i++) {
if (fireworks[i].wasDone()) {
fireworks.splice(i, 1);
}
}
}
function random(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
}
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
add(vec) {
this.x += vec.x;
this.y += vec.y;
}
sub(vec) {
this.x -= vec.x;
this.y -= vec.y;
}
mult(value) {
this.x *= value;
this.y *= value;
}
getForceTo(tar, gra) {
let y = tar.y;
let i = 1;
while (y < this.y) {
y += gra.y * i;
i++;
}
i--;
let resX = (tar.x - this.x) / i;
let resY = - gra.y * (i + 1);
return new Vector(resX, resY);
}
static randomVector() {
let angle = random(0, 360) * Math.PI / 180;
let len = random(1, 5);
let x = Math.cos(angle) * len;
let y = Math.sin(angle) * len;
return new Vector(x, y);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment