Have particles appear OnClick function in p5.js - javascript

New to p5.js and trying to learn more every day. Basically, I am currently learning about particle systems and objects, and getting confused by the amount of code. Anyways, I'd like that on function mousePressed(), an array of particles (particle system) that I've created appears. It'd also be awesome if the particle system could trail the position of the mouse. So, basically, if you click your mouse on the screen particles appear in that position, and also trail your mouse.
I can't figure out what I'm missing in the code. I feel kind of lost about what half of it is even doing (my professor wrote a lot of it). When I add in the mousePressed function, everything goes to pot. I feel like I'm too overwhelmed to even know what's missing. Any help, plus detailed insight into what I need to do and why that solution works would be super appreciated. Thank you!
var particles = [];
var now = null;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(255, 25, 25);
function mousePressed() {
particles.push(new Particle(new p5.Vector(mouseX, mouseY)));
//particles.push(new Particle(new p5.Vector(width / 2, height / 1.5)));
for (var i = 0; i < particles.length; i++) {
// if our particle is dead, remove it
if (particles[i].lifespan <= 0) {
//splice is a way of removing a specific
//element from an array
particles.splice(i, 2);
} else {
particles[i].update();
particles[i].display();
}
//this.particle = new ParticleSystem(createVector(mouseX, mouseY));
// patricles.push(p);
}
}
}
function Particle(loc) {
this.loc = loc;
this.acc = new p5.Vector();
this.vel = new p5.Vector(random(-100, 100), random(-2, 0));
this.lifespan = 555;
}
Particle.prototype = {
constructor: Particle,
update: function() {
this.vel.add(this.acc);
this.loc.add(this.vel);
this.lifespan -= 4.0;
},
display: function() {
stroke(random(0), this.lifespan);
fill(random(255), random(255), random(255))
ellipse(this.loc.x, this.loc.y, 20, 20);
}
}

First of all, your mousePressed() function is inside your draw() function. That doesn't make a ton of sense. You want your mousePressed() function to be at the same level as your draw() function.
function draw(){
//draw code here
}
function mousePressed(){
//mousePressed code here
}
If I were you, I would start smaller. Can you create a program that draws a single ellipse? Can you then make it so that single ellipse appears when you click the mouse? Then can you have that ellipse follow the mouse? Only if you can get that working perfectly by itself, then you should start thinking about adding multiple ellipses.
You're trying to go from your end goal and work backwards, which is just going to confuse you. Instead, start from the simplest sketch possible and take one small step at a time. Then if you get stuck you can post an MCVE along with a specific question, and it'll be easier to help you.

Related

Animate a flying bird in p5.js

I want to create an animation of a bird with p5 js. I have 6 pictures of the bird - when the wings are up, in the middle, and so on... When I press 'space bar' on the keyboard, the bird should fly - so all the pics should be shown as an animation (as if the bird is really flying). I want to build this code snippet without spritemap.
This is my code, but somehow it doesn't work..
let time = 0;
let frame = 0;
let img = [];
function preload() {
img.push(loadImage("assets/Bird/bird-1.png"));
img.push(loadImage("assets/Bird/bird-2.png"));
img.push(loadImage("assets/Bird/bird-3.png"));
img.push(loadImage("assets/Bird/bird-4.png"));
img.push(loadImage("assets/Bird/bird-5.png"));
}
function draw() {
function keyPressed() {
if (key == ' ') {
const speed = 1;
const numImage = img.length;
let current = frame % numImage;
let display = img[current];
image(display, width / 2, height / 2, display.width, display.length);
time += speed;
if (time > 5) {
time = 0;
frame++;
}
}
}
}
Looking forward to reading some ideas! Thank you in advance.
First things first you should not need to handle frames and such things. It is better to use keyPressed function outside of scope draw since it is a special event function and automatically called when a key is pressed.
It is better to use setup functionality instead of preload since preload is a little bit more early function then we needed. Setup is more relevant in such things like loading an array and so on.
I see that you forgot to create a canvas to draw an image on it. I added that on setup and also set the framerate of canvas regarding the img array's size.
function setup() {
createCanvas(400, 400);
background(51);
img.push(loadImage("1.png"));
img.push(loadImage("2.png"));
img.push(loadImage("3.png"));
img.push(loadImage("4.png"));
frameRate(img.length * 2); // double speed on animate sprites
}
From this point it is only a matter of checking the keyCode and looping through array.
function draw() {
if (keyIsDown(32)) {
background(51);
const numImage = img.length;
let current = frameCount % numImage;
let display = img[current];
image(display, width / 2 - display.width , height / 2 - display.height , display.width, display.length);
}
}
Here in the keyIsDown(32) check, 32 represents spacebar. You can check others from here easily : http://keycode.info/
You want to re-set the background of canvas on each sprite display. If not, they will still be showing on each render.
You can see the working version of your code in here :
https://editor.p5js.org/darcane/sketches/rVl22hkv7

Adding delay to function during drawing objects

i placed setInterval into the code but this obviously delaying all the lasers by 1 second.
I want it to be working in the following sequence:
- at start laser1 and laser2 are fired.
- 1 second break and fire another set of lasers etc.
Also if someone could teach me how to move all block of code by four spaces on forum, that would be amazing, as none of the ways i found in google solve this ridiculous problem.
Code shortcut:
let laser1;
let lasers1 = [];
let laser2;
let lasers2 = [];
function createLaser() {
laser1 = new Laser(bossOne.x, bossOne.y + bossOne.sizeY, 10, 50, 5);
lasers1.push(laser1);
laser2 = new Laser(bossOne.x + bossOne.sizeX - 10, bossOne.y +
bossOne.sizeY, 10, 50, 5);
lasers2.push(laser2);
}
function draw() {
requestAnimationFrame(draw);
setInterval(createLaser, 1000);
for (i = 0; i < lasers1.length; i++) {
lasers1[i].show();
lasers1[i].move();
}
for (i = 0; i < lasers2.length; i++) {
lasers2[i].show();
lasers2[i].move();
}
}
requestAnimationFrame(draw);
Remote host for full code if needed:
https://stacho163.000webhostapp.com/
lasers are red
I think i should work with booleans, but can't handle to set it there.
Got a similar topic with key activation, but i lost contact with the one who proposed a solution on the basis of booleans (as it didn't work well) so i took the easiest part first without involving the keys.
Any tips are appreciated :)
Try changing setInterval to setTimeout, as it's already looping recursively - just add a delay to it. Also move the requestAnimationFrame call to the bottom of draw, not the top:
function draw()
setTimeout(createLasers, 1000);
//Loops
requestAnimationFrame(draw);
}

Constant not staying constant?

I made a code with the intention of having a square appear where the mouse is pressed down, stay in that spot despite mouse movement and not disappear when the mouse it released.
THIS IS P5.JS ! https://p5js.org/reference/
Instead, the square follows the mouse until it is released then it disappears!
I believe that my code keeps declaring a new constant and deleting the old one every time the shoot() function is run.
var clocker = 0;// NOT YET USED
var player = {
x:400,
y:400,
};
function shoot(x1, y1, x2, y2, speed, range, power, playerDirection){
var bulletAlive = true;
var bulletDamage = power;
const startX = x1;
const startY = y1;
const destX = x2;
const destY = y2;
var bulletX = startX;
var bulletY = startY;
if(bulletAlive){
fill(0,100,200);
rect(destX-12.5,destY-12.5,25,25);
};
};
function setup() {
createCanvas(1000,650);
}
function draw() {
background(204,204,204);
if(mouseIsPressed){
shoot(player.x,player.y,mouseX,mouseY,2,100,0,"right");
}
}
Perhaps I am using const wrong. If so how should I use it? How can I make it so that destX and destY don't change? (Don't follow mouse or disappear)
PS: sorry for the miscellaneous information, this is supposed to build up to simple bullet physics.
It sounds like there is some confusion about scoping, and there is probably a better way to think about this problem.
First let's look at what is going wrong, and talk through a few details to explain why.
Just like variables (let, var), constants are always declared in a specific scope.
Scopes are like containers for constants and variables. Scopes are private, that is they cannot be accessed from the outside. Scopes can be created and destroyed.
When you declare a constant directly inside a function, the scope is the function itself (like startX inside shoot). (Note that if you declare a constant inside an if statement or other block, the scope is the block. That's not the case here, though.)
Function scopes are created each time the function is called, and destroyed when the function is finished executing.
Each time a function is called and its scope is created, all constants (and variables) are reinitialized with new values.
A constant appearing in your code may have different values during different function calls. It is only constant during its lifetime, which in your case is a single given execution of the function.
This is why your constants aren't staying constant. You are calling shoot() repeatedly while the mouse is down, and so the constants are repeatedly being recreated and assigned new values.
With this information, hopefully you can see the problems with the current approach. As for a solution, let's think about what exactly is happening. shoot() is an action that should be triggered when the user issues a "shoot" command, such as a mouse click. The draw() function is a continuous event triggered to say "hey, update the screen". Putting the shoot action inside the draw event is kind of a mis-match of intentions and is the root of struggles like this.
Instead, let's introduce the idea of a bullet object. A bullet has an x and a y value. A bullet is created when the user shoots, and is given a specific x and y value at the moment of creation. None of this happens inside draw, it happens in another event listener such as "click".
The job of draw is to check to see if there is an active bullet, and if there is one, draw it at the specified x and y coordinate. If there is no bullet, do nothing. (Of course you might need to draw other things as well, but that's unrelated to drawing the bullet).
Keeping object creation and object drawing separate makes it easier to have the kind of control you're looking for.
Edit: Adding some code examples
Here's what the code would look like to do exactly what you asked, using the bullet object idea above. The inline comments should explain each step.
// This is where we'll store an active bullet object.
// The `shoot()` function is responsible for setting this.
// `draw()` is responsible for rendering the bullet.
// Initially we'll set the value to `null` to explicitly
// indicate that there is no bullet.
let activeBullet = null;
// The purpose of `shoot()` is to create a bullet
// and make it available to be rendered.
function shoot(x, y) {
// Create the bullet object.
const newBullet = {
x: x,
y: y,
size: 25
};
// Set the active bullet to the new bullet. This will
// cause any previously active bullet to disappear.
activeBullet = newBullet;
}
// P5 functions
// ------------
function setup() {
createCanvas(1000, 650);
}
// Shoot when the player clicks.
function mousePressed() {
shoot(mouseX, mouseY);
}
function draw() {
// Always start with a blank canvas.
clear();
// If there is an active bullet, draw it!
// (`null` is "falsy", objects are "truthy", so the
// `if` statement will only run after the `activeBullet`
// variable is assigned a bullet object.)
if (activeBullet) {
fill(0, 100, 200);
rect(
activeBullet.x - activeBullet.size / 2,
activeBullet.y - activeBullet.size / 2,
activeBullet.size,
activeBullet.size
);
}
}
You also mentioned you wanted to build up to simple bullet physics. Just to show how the bullet object idea works nicely, here's a demo where you can click to shoot multiple bullets, they all move independently, and collide with a wall at which point they are removed. There's a lot more involved in building games, but hopefully it's an inspiring starting point :)
// Store canvas dimensions globally so we have easy access.
const canvasWidth = 1000;
const canvasHeight = 650;
// We'll add a "wall" object so we have something the bullets can
// collide with. This value is the X position of the wall.
const wallX = canvasWidth - 200;
// Instead of a single bullet, using an array can accommodate
// multiple bullets. It's empty to start, which means no bullets.
// We can also use `const` for this, because we won't ever assign
// a new value, we'll only modify the contents of the array.
const activeBullets = [];
function shoot(x, y) {
// Create the bullet object.
const newBullet = {
x: x,
y: y,
size: 25,
speed: 4
};
// Instead of overwriting a single bullet variable, we'll push
// the new bullet onto an array of bullets so multiple can exist.
activeBullets.push(newBullet);
}
// P5 functions
// ------------
function setup() {
createCanvas(canvasWidth, canvasHeight);
}
// Shoot when the player clicks.
function mousePressed() {
shoot(mouseX, mouseY);
}
function draw() {
// Always start with a blank canvas.
clear();
// Draw our "wall".
fill(50);
rect(wallX, 0, 60, canvasHeight);
// Set the fill color once, to use for all bullets. This doesn't
// need to be set for each bullet.
fill(0, 100, 200);
// Loop through the array of bullets and draw each one, while also
// checking for collisions with the wall so we can remove them. By
// looping backwards, we can safely remove bullets from the array
// without changing the index of the next bullet in line.
for (let i=activeBullets.length-1; i>=0; i--) {
// Grab the current bullet we're operating on.
const bullet = activeBullets[i];
// Move the bullet horizontally.
bullet.x += bullet.speed;
// Check if the bullet has visually gone past the wall. This
// means a collision.
if (bullet.x + bullet.size / 2 > wallX) {
// If the bullet has collided, remove it and don't draw it.
activeBullets.splice(i, 1);
} else {
// If the bullet hasn't collided, draw it.
rect(
bullet.x - bullet.size / 2,
bullet.y - bullet.size / 2,
bullet.size,
bullet.size
);
}
}
}
The const declaration exists only within the scope of shoot. So once the shoot function is finished executing, startX startY destX destY, being const, are deleted.
Possible fix:
var didShootAlready = false;
var startX, startY, destX, destY;
function shoot(/*params*/){
if(!didShootAlready){
didShootAlready = true;
startX = x1;
startY = y1;
destX = x2;
destY = y2;
}
//do the rest
}

Tooltips for data in javascript using p5.js

I am trying to make tooltips for a data visualization I made using p5.js but I am completely lost. Nothing I tried works. This is my code as is.
var table;
var i;
var j;
var cellValue;
var label;
var test;
function preload() {
matrix = loadTable("dataLayer2matrix.csv","csv")
labels = loadTable("dataLayer2labels.csv","csv")
test = matrix
}
function setup() {
createCanvas(1500,1500)
noStroke()
fill(0,0,255,10)
angleMode(DEGREES)
background(255,255,255)
matrixStartX = 200
matrixStartY = 250
var matrixRows = matrix.getRows()
var matrixSize = matrixRows.length
// Experiment with grid
fill(75, 75, 75, 50)
for (r = 0; r <= matrixSize; r++) {
rect(matrixStartX , matrixStartY + r * 20 - 1 , 20 * matrixSize, 1)
rect(matrixStartX + r * 20 - 1 , matrixStartY, 1, 20 * matrixSize)
}
// Draw matrix
for (var mr = 0; mr < matrixSize; mr++) {
for (var mc = 0; mc < matrixSize; mc++) {
cellValue = matrixRows[mr].getNum(mc)
fill(49,130,189,cellValue*10)
rect(mc * 20 + matrixStartX, mr * 20 + matrixStartY, 19 ,19)
}
}
// Labels - horizontal
fill(75, 75, 75, 255)
labelsRow = labels.getRows()
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 10, mc*20+matrixStartY + 15)
}
// Labels - vertical
push()
translate(matrixStartX + 15, matrixStartY - 15)
rotate(-90)
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 0, mc*20)
}
pop()
//Tooltip when clicked
}
/* if(mouseIsPressed){
fill(50);
text(cellValue, 10,10,70,80);
}*/
}
}
It makes this image:
I want it so that when I go over a square I get the data in it. I really can't seem to do it. Thanks.
I think the advice telling you to use bootstrap is missing the fact that you're using p5.js. Bootstrap is more for dealing with html components, not internal Processing sketches.
Instead, you probably want to do this with p5.js code. The best thing you can do is break your problem down into smaller steps:
Step 1: Can you draw a single rectangle?
Instead of trying to add this new functionality to your existing sketch, it might be easier if you start with a simpler example sketch with just a single rectangle.
Step 2: Can you detect when the mouse is inside that rectangle?
If you know where you're drawing the rectangle, you know its coordinates. You also know the coordinates of the mouse from the mouseX and mouseY variables. So to detect whether the mouse is inside the rectangle, you simply have to use if statements that compare the coordinates of the mouse to the coordinates of the rectangle. There are a ton of resources on google for this, and it might help if you draw some examples out on a piece of paper.
Also, don't worry about the tooltip just yet. Just do something simple like change the color of the rectangle when the mouse is inside it.
Step 3: Can you display the information box?
Again, do this in its own sketch first. Maybe create a function that takes a position and the information you want to display as parameters and displays it in a rectangle. Don't worry about making it a tooltip yet. Just get it displaying. Use hard-coded values for the information.
Step 4: Can you combine your small example sketches?
You have code that triggers when the mouse is inside a rectangle. You have code that draws the tooltip. Can you make it so the tooltip is drawn when the mouse is inside the rectangle?
Step 5: Only when all of the above works, then you should start thinking about adding it to your full sketch.
Instead of using an example rectangle, you'll have to use the rectangles you're drawing on the screen. Instead of calling the tooltip function with hard-coded values, use the values you get from the squares.
Take on those pieces one at a time, and make small steps toward your goal. Then if you get stuck, you can post an MCVE of the specific step you're on. Good luck!

Image appearing multiple times on canvas?

I'm drawing a simple dynamic canvas and I'm wondering how I can make the .png file in my drawImage method appear like 40 times at different places on my canvas at the same time?
Thanks beforehand! :)
Thank you all very much for your reply! This is as far as I've gotten now:
<script type="text/javascript">
var ctx;
var imgBg;
var imgDrops;
var x = 40;
var y = 0;
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
setInterval('draw();', 36);
imgBg = new Image();
imgBg.src = 'dimma.jpg';
imgDrops = new Image();
imgDrops.src = 'drop.png';
}
}
function draw() {
drawBackground();
for(var i=0; i <= 40; i++) {
ctx.drawImage (imgDrops, x, y);
y += 3;
if(y > 450)
y = -20;
x=Math.random()*600;
}
}
function drawBackground(){
ctx.drawImage(imgBg, 0, 0);
}
</script>
My problem is now that the images are jumping all over the place... I want them "falling" down slowly from above and coming back around:(
Have a look at this fiddle http://jsfiddle.net/joevallender/D83uC/10/
I made it to explain some basics of canvas to a friend recently. Although I'm using shapes instead of .png files I think the loop you are looking for is the same.
The key bit of code being this loop below
setInterval(function(){
// clear stage
context.clearRect(0, 0, width, height);
for(var i = 0; i < balls.length; i++) {
balls[i].move(balls);
}
}, 1000/FPS)
FPS is a variable, and .move() is a function that calculated new co-ordinates for and then re-draws the ball object.
I think it might simply not clearing the 'stage' context.clearRect(0, 0, width, height);
EDIT Perhaps that example had too much going on in it to be useful.
Please see a much earlier version http://jsfiddle.net/joevallender/D83uC/2 that simple animates the ball. The main point remains though, you need to clear the canvas if you don't want the 'trails'
Think of canvas like windows paint, not flash. The things you have drawn aren't editable objects. You need to redraw the whole thing each time. (Unless you use a JS library that makes things seem more like flash - but I'm guessing you want to learn without helper libraries at first)
As I said, I was explaining canvas to someone recently and you can see the various stages between the two links I've sent you by changing the number on the end of the URL http://jsfiddle.net/joevallender/D83uC/3
http://jsfiddle.net/joevallender/D83uC/4
etc.
EDIT2
Or if I've misunderstood, post a jsfiddle and let us know what is wrong with it
This is what you need: http://edumax.org.ro/extra/new/imagetut/
You can get the code here: http://edumax.org.ro/extra/new/imagetut/script.js
The relevant part is this:
function draw_image(){
//draw one image code
}
window.onload = function () {
for (var i=0;i<10;i++){
for (var j=0;j<10;j++){
draw_image(10+i*40, 10+j*40, 40, 40);
}
}
}
This code only explains the concept, it will not work by itself, for a full version check the link above.

Categories