I'm working on a firework display with the p5.js library (although I doubt this will effect answers). My current program uses the p5.js background function with can create an afterimage for the entire project. You can view the project here: https://editor.p5js.org/KoderM/sketches/WsluEg00h
But you can also view the code here:
let particles, FPS;
function setup() {
createCanvas(1000, 800);
background(220);
particles = [];
FPS = new FPSMonitor(50, 50);
}
function draw() {
colorMode(RGB);
background(0, 0, 0, 25);
for(let p in particles){
if(particles[p].isDead()){
particles.splice(p, 1);
continue;
}
particles[p].update();
}
FPS.update();
}
function mousePressed(){
particles.push(new firework(mouseX, mouseY, random(0, 255)));
particles[particles.length-1].velocity = p5.Vector.random2D();
particles[particles.length-1].velocity.mult(random(0.5, 10));
}
class FPSMonitor {
constructor(x, y){
this.x = x;
this.y = y;
this.size = 100;
this.delay = millis();
this.mouse = [0, 0];
}
update(){
this.checkMouse();
if(this.mouse[0] !== 0){
this.x = mouseX - this.mouse[0];
this.y = mouseY - this.mouse[1];
}
textAlign(LEFT, TOP);
textSize(this.size/6);
rectMode(CORNER);
strokeWeight(3);
stroke("red");
fill("white");
rect(this.x, this.y, this.size*1.2, this.size);
strokeWeight(4);
stroke("black");
text("FPS: " + round(1/(millis()-this.delay)*1000, 3), this.x+5, this.y+5);
text("Average FPS:", this.x+5, this.y+25);
text(round(frameCount/millis()*1000, 3), this.x+5, this.y+48);
text("MS: " + round(millis()-this.delay), this.x+5, this.y+72);
this.delay = millis();
}
checkMouse(){
if(mouseIsPressed && this.mouse[0] !== 0){
return;
}
if(this.x < mouseX && (this.x + this.size) > mouseX &&
this.y < mouseY && (this.y + this.size) > mouseY && mouseIsPressed){
if(this.mouse[0] == 0){
this.mouse = [ mouseX - this.x, mouseY - this.y ]
}
return;
}
this.mouse = [0, 0];
}
}
Particle.js:
class particle {
constructor(x, y, hue, gravity, life, weight, renderFunction){
if(!hue){ throw new TypeError(this + " : hue is not defined") }
this.defaults = {
x: 0,
y: 0,
gravity: createVector(0, 0),
life: 100,
weight: 1,
renderFunction: (self) => {colorMode(HSB);strokeWeight(2);stroke(this.hue, 255, 255, this.life/this.maxLife);point(this.position.x, this.position.y)}
}
this.position = x && y ? createVector(x, y) : createVector(this.defaults.x, this.defaults.y);
this.gravity = gravity || this.defaults.gravity;
this.life = life || this.defaults.life;
this.maxLife = this.life;
this.acceleration = createVector(0, 0);
this.velocity = createVector(0, 0);
this.weight = weight || this.defaults.weight;
this.renderFunction = renderFunction || this.defaults.renderFunction;
this.hue = hue;
this.otherInfo = {
mouseAtStart: createVector(mouseX, mouseY),
}
}
isDead(){
return this.life < 0;
}
applyForce(force){
this.acceleration.add(force);
}
update(){
this.life--;
this.acceleration.add(this.gravity);
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.velocity.mult(this.weight*0.96>1?0.96:this.weight*0.96);
this.acceleration.mult(0.1);
this.renderFunction(this);
}
}
And finally, firework.js:
class firework {
constructor(x, y, hue){
this.renderFunction = self => {
colorMode(HSB);
strokeWeight(3);
stroke(self.hue, 255, 255, (self.life+self.maxLife*0.5)/self.maxLife)
//line(self.otherInfo.mouseAtStart.x, self.otherInfo.mouseAtStart.y, self.position.x, self.position.y);
point(self.position.x, self.position.y);
};
this.explodeRenderFunction = self => {
colorMode(HSB);
strokeWeight(3);
stroke(self.hue, 255, 255, self.life/self.maxLife)
//line(self.otherInfo.mouseAtStart.x, self.otherInfo.mouseAtStart.y, self.position.x, self.position.y);
point(self.position.x, self.position.y);
}
this.particle = new particle(x, y, hue, createVector(0, 0.1), height/53.3 * 4, 1, this.renderFunction);
this.particle.applyForce(createVector(random(-3, 3), random(height/-53.3, height/-43.3)));
this.explodeParticles = [];
this.exploded = false;
this.hue = hue;
}
update(){
this.particle.update();
if(this.particle.isDead() && !this.exploded){
this.particle.renderFunction = (self) => {};
this.exploded = true;
for(let p = 0; p < 500; p++){
this.explodeParticles.push(new particle(this.particle.position.x, this.particle.position.y, this.hue, createVector(0, 0.1), 100, 1, this.explodeRenderFunction));
this.explodeParticles[this.explodeParticles.length-1].velocity = p5.Vector.random2D();
this.explodeParticles[this.explodeParticles.length-1].velocity.mult(random(0.5, 10));
}
}
if(this.exploded){
for(let p in this.explodeParticles){
if(this.explodeParticles[p].isDead()){
this.explodeParticles.splice(p, 1);
continue;
}
this.explodeParticles[p].update();
}
}
}
isDead(){
return this.explodeParticles.length == 0 && this.exploded;
}
}
The fireworks DON'T look at all like fire works without the trail the afterimage provides, but I've also implemented an FPS monitor I created, which also blurs because of the background function (this effect is unwanted.)
A bit more information on the background function:
I'm using the syntax: background(v1, v2, v3, [a])
v1, v2, and v3 are HSB variables. The optional variable [a] is defined as: Opacity of the background relative to current color range (default is 0-255)
The full background website: https://p5js.org/reference/#/p5/background
THE QUESTION
How do I have the fireworks look the same, WITHOUT having other things in the canvas be effected? For example, the FPS monitor in the project can move by dragging your mouse, but it also has that afterimage effect that comes from the background function. I want the fireworks to stay the same, but anything else that renders needs to be "not" blurry.
Really appreciate any help.