How to create an afterimage for some objects in JavaScript - javascript

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.

You could use separate "layers" in p5.js using createGraphics().
For example, the fireworks class could hold it's p5.Graphics instance which it can use to render the effect into, then in the main sketch's draw() you'd call image(), passing the p5.Graphics instance (as if it was an image) to display into the main p5.js canvas.
(Off-topic, you could look into object pooling to reset/reuse "dead" particles
instead of deleting/re-allocating new ones)
Update
Seems to work, here's what an approach to what I meant:
let particles, FPS;
// independent layers to render graphics into
let particlesLayer;
let fpsLayer;
function setup() {
createCanvas(1000, 800);
background(0);
particles = [];
FPS = new FPSMonitor(50, 50);
// particles will take up the whole sketch
particlesLayer = createGraphics(width, height);
// we can get away with a smaller frame buffer for the FPS meter
fpsLayer = createGraphics(256, 216);
}
function draw() {
particlesLayer.colorMode(RGB);
particlesLayer.background(0, 0, 0, 25);
for(let p in particles){
if(particles[p].isDead()){
particles.splice(p, 1);
continue;
}
particles[p].update();
}
// render the fireworks layers into the main sketch
image(particlesLayer, 0, 0);
// pass the layer to render the fps meter into and display it
FPS.update(fpsLayer);
}
function mousePressed(){
// pass the particles layer to each firework instance to render into
particles.push(new firework(mouseX, mouseY, random(0, 255), particlesLayer));
particles[particles.length-1].velocity = p5.Vector.random2D();
particles[particles.length-1].velocity.mult(random(0.5, 10));
}
function mouseDragged(){
FPS.x = mouseX - FPS.size * 0.5;
FPS.y = mouseY - FPS.size * 0.5;
}
class FPSMonitor {
constructor(x, y){
this.x = x;
this.y = y;
this.size = 100;
this.delay = millis();
}
update(g){
g.textAlign(LEFT, TOP);
g.textSize(this.size/6);
g.rectMode(CORNER);
g.strokeWeight(3);
g.stroke("red");
g.fill("white");
g.rect(0, 0, this.size * 1.2, this.size);
g.noStroke();
g.fill(0);
g.text("FPS: " + round(1/(millis()-this.delay)*1000, 3), 5, 5);
g.text("Average FPS:", 5, 25);
g.text(round(frameCount/millis()*1000, 3), 5, 48);
g.text("MS: " + round(millis()-this.delay), 5, 72);
this.delay = millis();
// render the graphics
image(g, this.x, this.y);
}
}
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);
}
}
class firework {
constructor(x, y, hue, graphicsLayer){
// store the reference to the same particle layers
this.g = graphicsLayer;
this.renderFunction = self => {
// use the layer to draw into, not the global p5.js graphics
this.g.colorMode(HSB);
this.g.strokeWeight(3);
this.g.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);
this.g.point(self.position.x, self.position.y);
};
this.explodeRenderFunction = self => {
this.g.colorMode(HSB);
this.g.strokeWeight(3);
this.g.stroke(self.hue, 255, 255, self.life/self.maxLife)
//line(self.otherInfo.mouseAtStart.x, self.otherInfo.mouseAtStart.y, self.position.x, self.position.y);
this.g.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;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
And here's a screenshot:
The the fireworks have trails, but the text is clear (witout blur/trails)

Related

How can I integrate an app made with create-react-app with p5.js, with a specific goal to make sound visualization that responds to played sound?

I have read a good number of related posts, but I feel they are not exactly giving me the required solution.
I want to implement in React, the following p5.js JavaScript code that I have written following this tutorial on YouTube => https://www.youtube.com/watch?v=uk96O7N1Yo0:
let sound;
let fft;
let image;
let particles = [];
function preload() {
sound = loadSound("sound-path.mp3");
image = loadImage("image-path.jpg");
}
function setup() {
createCanvas(windowWidth, windowHeigh);
angleMode(DEGREES);
imageMode(CENTER);
rectMode(CENTER);
fft = new p5.FFT(0.3);
image.filter(BLUR, 12);
noLoop();
}
function draw() {
background(0);
stroke(255);
strokeWeight(3);
noFill();
translate(width / 2, height / 2);
fft.analyze();
amp = fft.getEnergy(20, 200);
push();
if (amp > 230) {
rotate(random(-0.5, 0.5));
}
image(image, 0, 0, width + 100, height + 100);
pop();
let alpha = map(amp, 0, 255, 180, 150);
fill(0, alpha);
noStroke();
rect(0, 0, width, height);
stroke(255);
strokeWeight(3);
noFill();
let wave = fft.waveform();
for (let t = -1; t <= 1; t += 2) {
beginShape();
for (let i = 0; i <= 180; i += 0.5) {
let index = floor(map(i, 0, 180, 0, wave.length - 1));
let radius = map(wave[index], -1, 1, 150, 350);
let x = radius * sin(i) * t;
let y = radius * cos(i);
vertex(x, y);
}
endShape();
}
let particle = new Particle();
particles.push(particle);
for (let i = particles.length - 1; i >= 0; i--) {
if (!particles[i].edges()) {
particles[i].update(amp > 230);
particles[i].show();
} else particles.splice(i, 1);
}
}
function mouseClicked() {
if (sound.isPlaying()) {
sound.pause();
noLoop();
} else {
sound.play();
loop();
}
}
// Particles around the Wave
class Particle {
constructor() {
this.position = p5.Vector.random2D().mult(250);
this.velocity = createVector(0, 0);
this.acceleration = this.position.copy().mult(random(0.0001, 0.00001));
this.width = random(3, 5);
this.color = [random(200, 255), random(200, 255), random(200, 255)];
}
update(condition) {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
if (condition) {
this.position.add(this.velocity);
this.position.add(this.velocity);
this.position.add(this.velocity);
}
}
edges() {
if (
this.position.x < -width / 2 ||
this.position.x > width / 2 ||
this.position.y < -height / 2 ||
this.position.y > height / 2
)
return true;
else return false;
}
show() {
noStroke();
fill(this.color);
ellipse(this.position.x, this.position.y, this.width);
}
}
I have the following component in which I want that implementation of this sound visualization to happen:
import React from "react";
import { FormInput } from "../Forms/Form";
import "./Visualization.css";
const Visualization = () => {
// TODO: Implement p5.js to create visualization as in the linked video
const handleChange = () => {
// Play the selected audio file in that input
};
return (
<div className="visualizer-canvas-container">
<canvas id="landing-visualizer-canvas"></canvas>
<audio id="landing-audio-controls" controls />
<FormInput
accept="audio/*"
id="file-upload"
onChange={handleChange}
type="file"
/>
</div>
);
};
export default Visualization;

p5: Using Sine wave in WEBGL to change y-axis

I have some spheres that I want to move straight on the x axis with only their y-axis changing based on the sine wave (you know the up and down yo-yo pattern). It is pretty simple in 2d but for some reason, in WEBGL, the angle changes in the sin function is not working for this.y.
let particles = [];
let quantity = 20;
function setup() {
createCanvas(300, 300, WEBGL);
for (let i = 0; i < quantity; i++) {
let particle = new Particle();
particles.push(particle);
}
}
function draw() {
background(15);
orbitControl();
directionalLight([255], createVector(0, 0, -1));
translate(-width / 2, 0);
particles.forEach(particle => {
particle.update();
particle.edges();
particle.show();
});
};
// particle.js
function Particle() {
this.angle = 0;
this.r = 10;
this.x = random(width);
this.y = sin(this.angle) * 200; // I am changing this angle later but it's not working
this.z = random(-50, 50);
this.pos = createVector(this.x, 0, 0);
this.vel = createVector(2, this.y, 0);
this.update = function() {
this.pos.add(this.vel);
this.vel.limit(4);
this.angle += 3;
// print(this.pos);
}
this.edges = function() {
if (this.pos.x >= width) {
this.pos.x = 0;
}
}
this.show = function() {
noStroke();
push();
translate(this.pos.x, this.pos.y, 0);
sphere(this.r);
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
You only call sin one time in the construtor. You probably meant to apply it to this.y on every frame based on this.angle, or some other incrementing value. Also, there are duplicate vectors; pick either an x/y pair or use a vector x/y, but not both.
let particles = [];
let quantity = 20;
function setup() {
createCanvas(300, 300, WEBGL);
for (let i = 0; i < quantity; i++) {
let particle = new Particle();
particles.push(particle);
}
}
function draw() {
background(15);
orbitControl();
directionalLight([255], createVector(0, 0, -1));
translate(-width / 2, 0);
particles.forEach(particle => {
particle.update();
particle.edges();
particle.show();
});
};
// particle.js
function Particle() {
this.angle = 0;
this.r = 10;
this.x = random(width);
this.y = 0;
this.update = function() {
this.angle += 0.05;
this.y = sin(this.angle) * 100;
}
this.edges = function() {
if (this.x >= width) {
this.x = 0;
}
}
this.show = function() {
noStroke();
push();
translate(this.x, this.y, 0);
sphere(this.r);
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>

Array.forEach Updating each Item in Array on click

When the program runs the mouse is clicked creating a projectile from the center of the screen moving with every frame in the direction it was fired (mouse position on click).
When N+1 projectiles have fired all projectiles on-screen move to the new clicked location instead of continuing their path.
I am can not figure out why the current projectiles change direction when the New projectile's velocity should have no effect on prior projectiles.
index.html
<canvas></canvas>
<script src="./guns.js"></script>
<script src="./indexh.js"></script>
<script src="./runh.js"></script>
runh.html
const projectilesArray = [];
let frameCount = 0;
function animate() {
animationID = requestAnimationFrame(animate);
c.fillStyle = "rgba(0, 0, 0, 1)";
c.fillRect(0, 0, canvas.width, canvas.height);
projectilesArray.forEach((Projectile, pIndex) => {
Projectile.update();
console.log(Projectile)
if (
Projectile.x + Projectile.radius < 0 ||
Projectile.x - Projectile.radius > canvas.width ||
Projectile.y + Projectile.radius < 0 ||
Projectile.y - Projectile.radius > canvas.height
) {
setTimeout(() => {
projectilesArray.splice(pIndex, 1);
}, 0);
}
});
frameCount++;
if (frameCount > 150) {
}
}
var fire = 1;
let fireRate = 1;
const mouse = {
x: 0,
y: 0,
click: true,
};
canvas.addEventListener('mousedown', (event) => {
if (fire % fireRate == 0) {
if (mouse.click == true) {
mouse.x = event.x;
mouse.y = event.y;
const angle = Math.atan2(mouse.y - (canvas.height / 2), mouse.x - (canvas.width / 2));
const fireY = Math.sin(angle);
const fireX = Math.cos(angle);
//score -= 0;
//scoreL.innerHTML = score;
var weapon = new Projectile(cannon);
weapon.velocity.x = fireX * 9;
weapon.velocity.y = fireY * 9;
projectilesArray.push(weapon);
//var gun = object.constructor()
}
}
});
animate();
indexh.js
const canvas = document.querySelector("canvas");
const c = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
class Projectile {
constructor(config) {
this.color = config.color || "rgb(60, 179, 113)";
this.radius = config.radius || 1;
this.speed = config.speed || 5;
this.rounds = config.rounds || 2;
this.x = config.x || canvas.width / 2;
this.y = config.y || canvas.height /2;
this.velocity = config.velocity;
}
draw() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.fillStyle = this.color;
c.fill();
}
update() {
this.draw();
this.x = this.x + this.velocity.x * this.speed;
this.y = this.y + this.velocity.y * this.speed;
}
}
gums.js
let pistol = {
color : "rgb(255, 0, 0)",
radius : 10,
speed : 1,
rounds : 1,
velocity : {
x: 1,
y: 1
}
}
let cannon = {
color : "rgb(0, 0, 255)",
radius : 30,
speed : .5,
rounds : 1,
velocity : {
x: 1,
y: 1
}
}
Thanks
The issue is that you have this cannon object used as a configuration object:
let cannon = {
color : "rgb(0, 0, 255)",
radius : 30,
speed : .5,
rounds : 1,
velocity : {
x: 1,
y: 1
}
}
And in your Projectile constructor you assign this.velocity = config.velocity; You are assigning this.velocity to be the same object instance for all Projectiles. To fix it, try copying the object, like:
this.velocity = {...config.velocity};
That will make a copy of the object rather than sharing the same object instance.
Also note that you have a bug that you didn't ask about in this line:
projectilesArray.splice(pIndex, 1);
If two timeouts are queued in the same loop, the array will shift when the first timeout fires, and the second timeout will be operating on the wrong index.

How to reset CreateCanvas() in JS after being called

When I was writing the code I saw that the code would not reset the canvas to (400, 400) after being changed to (600, 600). It would disorientate the canvas and stretch all the shapes with it in evaporation(). When going through all the screens and trying to go back to reset back.
//Variables
let screen = 0;
let bugs = [];
let amt = 1000;
let xpos=0;
function setup() {
colorMode(HSB);
//Changes Colormode to HSB(Hue-Saturation-Brightness)
//Creates the particles for the evaporation screen
//For loop with increasement that states more of the smoke is created
for (let i = 0; i < amt; i++) {
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs[i] = b;
}
}
//Says if the value of screen changes so does the screen
function draw() {
if(screen == 0) {
evaporationscreen();
} else if(screen == 1) {
condensation();
} else if(screen == 2) {
presipitation();
}
}
//Evaporation
function evaporationscreen() {
background('#d2b48c');
createCanvas(400, 400);
//NOT RGB, HSB COLOR PALLETE(DO NOT MIX UP);
//HTML Color pallete('e928320');
noStroke();
fill('#3895d3') //Lake
circle(400, 400, 600)
fill('#18bdf0') //Sky
rect(0, 0, 400, 200);
fill('#ffff00'); //Sun
circle(300, 60, 70);
fill('#e9bd15'); //Darkspots on Sun
circle(315, 75, 10);//Forms the Sun and Darkspots
circle(280, 52, 8);//Forms the Sun and Darkspots
circle(299, 60, 13);//Forms the Sun and Darkspots
circle(320, 48, 9);//Forms the Sun and Darkspots
circle(295, 30, 6);//Forms the Sun and Darkspots
circle(284, 79, 9);//Forms the Sun and Darkspots
fill(240, 100, 50);//Forms the Sun and Darkspots
rect(0, 200, 400, 400); //Beach
console.log("EVAPORATION");
//Lots of variables
let stoprip = 45;
let lake = int(dist(400, 400, mouseX, mouseY));
var starx = random(0, 400);
var stary = random (10, 190);
var sun = int(dist(300, 60, mouseX, mouseY));
//If Statement that creates ripples
if (mouseIsPressed && lake < 300) {
if (mouseY >= 200) {
noFill();
stroke('#3895d3');
strokeWeight(4);
circle(mouseX, mouseY, ripple);
ripple = ripple + 5;
console.log('lake rippling');
if (ripple >= stoprip) {
ripple = 10
}
} else {
ripple = 10
}
} else if (mouseIsPressed && sun <=35) {
fill('#fee12b');
circle(starx, stary, 10);
console.log('stars');
}
background(50, 0.25);
//For loop that creates the smoke effect with an increasement
for (let i = 0; i < bugs.length; i++) {
bugs[i].show();
bugs[i].move();
if( bugs[i].radius > 100 ) {
bugs.splice(i, 1);
}
}
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs.push(b);
}
//Particles for evaporation
class Bug {
constructor(tempX, tempY, tempRadius) {
this.x = tempX;
this.y = tempY;
this.radius = tempRadius;
this.color = color(random(80,100), 0.05);
}
//Creates the sketch for it
show() {
noStroke();
fill(this.color);
ellipse(this.x, this.y, this.radius);
}
//Moves it up at a random pace
move() {
this.x = this.x + random(-5, 5);
this.y = this.y - random(2);
this.radius = this.radius + 0.4;
}
}
function condensation() {
//Changes the canvas from 400,400 to 600,600
createCanvas(600, 600);
//Changes background to grey to imitate storm,
background(50);
console.log("CONDENSATION");
//Colors the cloud and fills it with white
noStroke();
fill(255);
//States where cloud spawns
cloud(xpos,50,1);
cloud(xpos,50,2);
cloud(xpos,80,0.75);
xpos++;
//Has cloud with an increasement
if (xpos>600) {
xpos=0;
}
}
function presipitation() {
createCanvas(600, 600);
ellipseMode(RADIUS);
noFill();
background(211, 69, 93);
console.log("PRESIPITATION")
//If statement that create a for loop that spawns new particles(rain)
if (particles.length < 200) particles.push(new Particle());
for (var i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].display();
}
}
var particles = [];
//Variable
//Rain drop / Particle
class Particle {
constructor() {
this.reset();
}
//Resets Particle after update
reset() {
this.x = random(width);
this.y = random(-150, 0);
this.vy = random(0.1, 2);
this.maxy = this.y + height;
this.r = 0;
this.tr = 50;
this.w = random(0.1, 2);
}
//If statement that creates the gravity for the particle
update() {
if (this.y < this.maxy) {
this.y += this.vy;
} else {
this.r++;
}
if (this.r > this.tr) this.reset();
}
//If statement(says it will remain the raindrop form or change into the puddle
display() {
strokeWeight(this.w);
if (this.y < this.maxy) {
stroke(255);
push();
translate(this.x,this.y);
beginShape();
strokeWeight(1);
vertex(0,-5);
quadraticVertex(3, 0, 0, 1);
quadraticVertex(-3,0, 0, -5);
endShape(CLOSE);
pop();
} else {
stroke(255, map(this.r, 0, this.tr, 255, 0));
ellipse(this.x, this.y, this.r, this.r*.5);
}
}
}
//Changes Screen from evaporation, condensation, precipitation
function mousePressed(){
if(screen==0){
screen=1;
}else if(screen==1){
screen = 2;
} else if(screen == 2) {
screen = 0;
}
}
//Makes cloud
function cloud(x,y,sc){
push()
scale(sc);
ellipse(x,y,50,30);
ellipse(x,y+20,80,30);
ellipse(x+20,y,40,30);
ellipse(x+30,y+10,70,40);
pop()
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sketch</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="libraries/p5.min.js"></script>
<script src="libraries/p5.sound.min.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
From the documentation for createCanvas:
Creates a canvas element in the document, and sets the dimensions of it in pixels. This method should be called only once at the start of setup. Calling createCanvas more than once in a sketch will result in very unpredictable behavior.
Instead of calling createCanvas repeatedly in your drawing functions, you should use resizeCanvas once when transitioning from one screen to another.
I couldn't actually reproduce whatever issue you were describing (partly because I could not make sense of your description). However I did also notice an issue with the variable ripple not being declared anywhere, so I fixed that, and now the sketch appears to be working correctly.
//Variables
let previousScreen = 0;
let screen = 0;
let bugs = [];
let amt = 1000;
let xpos = 0;
let ripple = 0;
function setup() {
createCanvas(400, 400);
colorMode(HSB);
//Changes Colormode to HSB(Hue-Saturation-Brightness)
//Creates the particles for the evaporation screen
//For loop with increasement that states more of the smoke is created
for (let i = 0; i < amt; i++) {
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs[i] = b;
}
}
//Says if the value of screen changes so does the screen
function draw() {
if (screen == 0) {
if (previousScreen !== screen) {
resizeCanvas(400, 400);
previousScreen = screen;
}
evaporationscreen();
} else if (screen == 1) {
if (previousScreen !== screen) {
resizeCanvas(600, 600);
previousScreen = screen;
}
condensation();
} else if (screen == 2) {
if (previousScreen !== screen) {
resizeCanvas(600, 600);
previousScreen = screen;
}
presipitation();
}
}
//Evaporation
function evaporationscreen() {
background('#d2b48c');
//NOT RGB, HSB COLOR PALLETE(DO NOT MIX UP);
//HTML Color pallete('e928320');
noStroke();
fill('#3895d3') //Lake
circle(400, 400, 600)
fill('#18bdf0') //Sky
rect(0, 0, 400, 200);
fill('#ffff00'); //Sun
circle(300, 60, 70);
fill('#e9bd15'); //Darkspots on Sun
circle(315, 75, 10); //Forms the Sun and Darkspots
circle(280, 52, 8); //Forms the Sun and Darkspots
circle(299, 60, 13); //Forms the Sun and Darkspots
circle(320, 48, 9); //Forms the Sun and Darkspots
circle(295, 30, 6); //Forms the Sun and Darkspots
circle(284, 79, 9); //Forms the Sun and Darkspots
fill(240, 100, 50); //Forms the Sun and Darkspots
rect(0, 200, 400, 400); //Beach
console.log("EVAPORATION");
//Lots of variables
let stoprip = 45;
let lake = int(dist(400, 400, mouseX, mouseY));
var starx = random(0, 400);
var stary = random(10, 190);
var sun = int(dist(300, 60, mouseX, mouseY));
//If Statement that creates ripples
if (mouseIsPressed && lake < 300) {
if (mouseY >= 200) {
noFill();
stroke('#3895d3');
strokeWeight(4);
circle(mouseX, mouseY, ripple);
ripple = ripple + 5;
console.log('lake rippling');
if (ripple >= stoprip) {
ripple = 10
}
} else {
ripple = 10
}
} else if (mouseIsPressed && sun <= 35) {
fill('#fee12b');
circle(starx, stary, 10);
console.log('stars');
}
background(50, 0.25);
//For loop that creates the smoke effect with an increasement
for (let i = 0; i < bugs.length; i++) {
bugs[i].show();
bugs[i].move();
if (bugs[i].radius > 100) {
bugs.splice(i, 1);
}
}
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs.push(b);
}
//Particles for evaporation
class Bug {
constructor(tempX, tempY, tempRadius) {
this.x = tempX;
this.y = tempY;
this.radius = tempRadius;
this.color = color(random(80, 100), 0.05);
}
//Creates the sketch for it
show() {
noStroke();
fill(this.color);
ellipse(this.x, this.y, this.radius);
}
//Moves it up at a random pace
move() {
this.x = this.x + random(-5, 5);
this.y = this.y - random(2);
this.radius = this.radius + 0.4;
}
}
function condensation() {
//Changes background to grey to imitate storm,
background(50);
console.log("CONDENSATION");
//Colors the cloud and fills it with white
noStroke();
fill(255);
//States where cloud spawns
cloud(xpos, 50, 1);
cloud(xpos, 50, 2);
cloud(xpos, 80, 0.75);
xpos++;
//Has cloud with an increasement
if (xpos > 600) {
xpos = 0;
}
}
function presipitation() {
ellipseMode(RADIUS);
noFill();
background(211, 69, 93);
console.log("PRESIPITATION")
//If statement that create a for loop that spawns new particles(rain)
if (particles.length < 200) particles.push(new Particle());
for (var i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].display();
}
}
var particles = [];
//Variable
//Rain drop / Particle
class Particle {
constructor() {
this.reset();
}
//Resets Particle after update
reset() {
this.x = random(width);
this.y = random(-150, 0);
this.vy = random(0.1, 2);
this.maxy = this.y + height;
this.r = 0;
this.tr = 50;
this.w = random(0.1, 2);
}
//If statement that creates the gravity for the particle
update() {
if (this.y < this.maxy) {
this.y += this.vy;
} else {
this.r++;
}
if (this.r > this.tr) this.reset();
}
//If statement(says it will remain the raindrop form or change into the puddle
display() {
strokeWeight(this.w);
if (this.y < this.maxy) {
stroke(255);
push();
translate(this.x, this.y);
beginShape();
strokeWeight(1);
vertex(0, -5);
quadraticVertex(3, 0, 0, 1);
quadraticVertex(-3, 0, 0, -5);
endShape(CLOSE);
pop();
} else {
stroke(255, map(this.r, 0, this.tr, 255, 0));
ellipse(this.x, this.y, this.r, this.r * .5);
}
}
}
//Changes Screen from evaporation, condensation, precipitation
function mousePressed() {
if (screen == 0) {
screen = 1;
} else if (screen == 1) {
screen = 2;
} else if (screen == 2) {
screen = 0;
}
}
//Makes cloud
function cloud(x, y, sc) {
push();
scale(sc);
ellipse(x, y, 50, 30);
ellipse(x, y + 20, 80, 30);
ellipse(x + 20, y, 40, 30);
ellipse(x + 30, y + 10, 70, 40);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>

Matter.js collision not detecting after setting velocity

var Engine = Matter.Engine,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
var ground;
var engine;
var player = [];
function setup() {
createCanvas(400, 400);
engine = Engine.create();
world = engine.world;
Engine.run(engine)
var options = {
isStatic: true
}
engine.world.gravity.y = 0
my = new Cell(200, 200, 32)
ground = Bodies.rectangle(200, height, width, 20, options)
World.add(world, ground)
// engine.world.gravity.y = 0;
console.log(player)
}
function keyPressed() {
player.push(new Cell(mouseX, mouseY, 32));
}
function draw() {
background(0);
my.show();
for (var i = 0; i < player.length; i++) {
player[i].show();
}
}
function Cell(x, y, r) {
this.body = Matter.Bodies.circle(x, y, r, r);
// World.add(world,this.body);
this.r = r;
World.add(world, this.body)
// player[player.length] = this;
this.show = function() {
var pos = this.body.position;
Body.setVelocity(this.body, {
x: mouseX - pos.x,
y: mouseY - pos.y
})
push();
translate(pos.x, pos.y)
// noStroke()
ellipseMode(CENTER);
ellipse(0, 0, this.r * 2, this.r * 2)
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
If I comment out Body.setVelocity, then collision works fine but not when using Body.setVelocity. Code above is working, please help me with broken collision detection. You can check collision problem by pressing keys more than 4 times.
It is a bit unclear what you try to achieve. But the code
Body.setVelocity(this.body, {
x: mouseX - pos.x,
y: mouseY - pos.y
})
in show, sets a velocity to the body, which is equal the distance of the mouse position to the body, repeatedly in every frame. This causes that each body moves too the mouse position immediately and breaks down the collision detection.
You have to modify the actual velocity of the body, by a certain value, witch depends on the distance of the bod to the mouse position. e.g.:
vx = this.body.velocity.x + (mouseX - pos.x) * 0.001
vy = this.body.velocity.y + (mouseY - pos.y) * 0.001
Body.setVelocity(this.body, {x: vx, y: vy } )
var Engine = Matter.Engine,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
var ground;
var engine;
var player = [];
function setup() {
createCanvas(400, 400);
engine = Engine.create();
world = engine.world;
Engine.run(engine)
var options = {
isStatic: true
}
engine.world.gravity.y = 0
my = new Cell(200, 200, 32)
ground = Bodies.rectangle(200, height, width, 20, options)
World.add(world, ground)
// engine.world.gravity.y = 0;
console.log(player)
}
function keyPressed() {
player.push(new Cell(mouseX, mouseY, 32));
}
function draw() {
background(0);
my.show();
for (var i = 0; i < player.length; i++) {
player[i].show();
}
}
function Cell(x, y, r) {
this.body = Matter.Bodies.circle(x, y, r, r);
// World.add(world,this.body);
this.r = r;
World.add(world, this.body)
// player[player.length] = this;
this.show = function() {
var pos = this.body.position;
vx = this.body.velocity.x + (mouseX - pos.x) * 0.001
vy = this.body.velocity.y + (mouseY - pos.y) * 0.001
Body.setVelocity(this.body, {x: vx, y: vy } )
push();
translate(pos.x, pos.y)
// noStroke()
ellipseMode(CENTER);
ellipse(0, 0, this.r * 2, this.r * 2)
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

Categories