I translate a p5js scetch to processing because I want to generate a mov file. The scetch is based on a tutorial from daniel shiffman on kadenze but I´ve got a problem now with a boolean output. How can I code this piece of p5js code in processing?
function draw() {
for( var i = 0; i < particles.length; i++) {
if(particles[i].isDead()) {
//code
}
}
}
function Particles() {
this.isDead = function() {
var distance = p5.Vector.sub(attractor.pos, this.pos);
var d = distance.mag();
if(d < 5) {
return true;
} else {
return false;
}
}
}
First I tried it with void, but void hasn´t got an output. Then I tried something like this with boolean but it also doesn´t work.
void setup() {
//code
}
void draw () {
for (int i = 0; i < particles.length; i++) {
if(particles[i].isDead()) {
//code
}
}
}
Class Particle {
Particle() {
//code
}
boolean isDead() {
PVector distance = PVector.sub(a.location, location);
float d = distance.mag();
if(d < 5) {
return true;
} else {
return false;
}
}
}
It will be great if somebody can help me.
regards mattias
The first problem is that you aren't ever actually doing anything if isDead() returns true. You need to actually put code inside that if statement, or maybe move that if statement to somewhere that makes logical sense.
For example, you could modify your display() function inside your Mover class to draw in green when the Mover is dead:
void display() {
if (isDead()) {
fill(0, 255, 0);
} else {
fill(255, 0, 0);
}
stroke(0);
strokeWeight(2);
ellipse(location.x, location.y, 10, 10);
}
That's just an example, and what you actually do depends on what you want to happen when a Mover is dead.
But even if you make that change, you'll notice that a Mover only dies when it reaches the middle of the gray circle. That's because of this if statement inside your isDead() function:
PVector distance = PVector.sub(a.location, location);
float d = distance.mag();
if (d < 5) {
return true;
} else {
return false;
}
You're measuring the distance between the center of the gray circle and the center of each little red circle. But you're only returning true if the d < 5. The problem with that is the gray circle has a diameter of 50, so if you want the little red circles to die when they enter the gray circle, you have to factor that diameter into your calculations. Try using if(d < 30) instead. I got 30 by dividing the diameter 50 by 2 and then adding 5 for the small circle size. You might have to play with it to get the effect you're looking for.
By the way, you might be interested in the dist() function, which returns the distance between two points. More info can be found in the reference.
Related
I am new to the amazing world of creative coding and p5js. I want to create a website for my design studio with a p5js effect that I can't find the solution for. I searched everywhere and I can't find anyone with the same problem as me, that's why I'm posting my very first message here. Here's the idea: in a canvas, I would like that with each mouse click, a different image can appear. Currently, my code allows to display images randomly but I would like to be able to set a cyclic order of appearance : work0.png, work1.png, work2.png... and it starts again.
If someone has seen this problem somewhere or could explain it to me I would be very grateful. Thanks !
let works = []
function preload() {
for (let i = 0; i < 5; i++) {
works[i] = loadImage("work" + i + ".png")
}
}
function setup() {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0, 0);
canvas.style('z-index', '1');
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
canvas.position(0, 0);
canvas.style('z-index', '1');
}
function draw() {
cursor(CROSS);
}
function mouseClicked() {
imageMode(CENTER);
let r = floor(random(0, 6));
image(works[r], mouseX, mouseY, 500, 600);
}
instead of using random, you can use a counter
let works = []
function preload() {
for (let i = 0; i < 5; i++) {
works[i] = loadImage("work" + i + ".png")
}
}
function setup() {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0, 0);
canvas.style('z-index', '1');
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
canvas.position(0, 0);
canvas.style('z-index', '1');
}
function draw() {
cursor(CROSS);
}
var counter = 0
function mouseClicked() {
imageMode(CENTER);
counter++ //add one to the counter
image(works[counter%5], mouseX, mouseY, 500, 600); // the % symbols is modulo, which is a fancy word for remainder when divided by that number, so it would cycle from 0 to 4
}
So the counter starts at zero, and every time you click we increase the counter by one. to stop it from increasing constantly, we can use the modulo operator %(in programming this isn't the percent sign). examples: 2%5 is 2, 16%5 is 1, 25%5 is 0.
this essentially makes the value cycle from 0 to 4. the counter is constantly increasing, but the remainder when divided by five will always cycle.
also btw p5.js is a javascript library, and you are loading in code made by other people, which means without the p5.js library the code doesn't run in this code snippet on StackOverflow
I have a program where I want a circle to change color when it's pressed on and then if it's pressed again to change back to the original color.
I have managed to change it on the first click but don't know how to change it back when I click it again.
Do anyone have any tips on how I can change back the color or change to a different color when clicked
the second time?
Current code:
// My function for changing the color when clicked.
function mousePressed () {
for (var i = 0; i < 10; i++) {
bubbles[i].interact();
}
}
// function inside the class for the circle
// to determine distance and what color.
interact () {
let d = dist (this.x, this.y, mouseX, mouseY);
if (d < this.r) {
this.col = 0;
}
}
If you can reproduce your problem in a codepen or similar sandbox it would be easier for someone to help you solve it.
2 things spring to mind:
You could use element.classlist.toggle() to toggle a class on/off and style that class.
Or you could extend your code like so:
if (d < this.r) {
if (this.col === 0) {
this.col = 1; // I'm guessing this is the correct value
} else {
this.col = 0;
}
}
I wasn't sure how to word this, because I don't actually know what exactly causes this bug. I'm trying to put together a simple Asteroids knockoff.
When the player shoots, a new object (Bullet) is created using array.push(...). Once this bullet goes beyond the canvas (out of bounds), it is deleted using array.splice(...);
The problem is that the bullets are moving in unpredictable ways. I don't know how to word it so here's the full code (working, including html/css): https://pastebin.com/tKiSnDzX
Hold spacebar for a few seconds (to shoot) and you'll see the issue clearly. You can also use A/D to turn and W to go forward.
Here's what I think is happening. The code runs fine as long as there is only one bullet on the screen (in the array). This means that either the incorrect element is being deleted or the values that go into the constructor of the object are messed up somewhere along the way.
Exhibit A (bullet constructor and its methods):
function Bullet(x,y,rot,vel) {
this.x = x;
this.y = y;
this.rot = rot;
this.vel = (vel+5);
this.move = function() {
this.x += this.vel*Math.cos(this.rot-Math.PI/2);
this.y += this.vel*Math.sin(this.rot-Math.PI/2);
}
this.draw = function() {
engine.circle(this.x, this.y, 4, "black");
var c = engine.canvas.getContext('2d');
c.translate(this.x, this.y);
c.rotate(this.rot);
c.beginPath();
c.strokeStyle="#00FF00";
c.strokeRect(-5, -5, 10, 10);
c.closePath();
c.stroke();
}
}
Exhibit B (function that creates/deletes the bullets):
shoot: function() {
if(engine.keyDown.sp == true) {
if(this.fire > 20) {
engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
this.fire = 0;
} else {
this.fire++
}
}
for(i = 0; i < engine.bullets.length; i++) {
engine.bullets[i].move();
engine.bullets[i].draw();
if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5
|| engine.bullets[i].y > engine.canvas.height+5 || engine.bullets[i].y < -5) {
console.log('bullet gone, '+i);
engine.bullets.splice(i, 1);
}
}
}
the array is declared like so: bullets: []
Thank you for any answers.
How about just tag any bullets that need to die as you come across them in your loop with something like engine.bullets[i].dead = true; Then, at the end outside the loop, filter out the dead bullets with engine.bullets = engine.bullets.filter(b => !b.dead);
You're using splice inside a for loop. When you remove element index 1, then element index 2 becomes index 1, and element index 3 becomes index 2. But your i variable is already 1, so the next iteration of the loop goes to the new index 2. But the new index 2 is the original index 3, and the original index 2 is skipped. You might be better served by a linked list:
var bulletList = null;
function bullet(){
this.next = bulletList;//if there was a list, record that
if (this.next)//and set that one to point back to this
this.next.prev = this;
bulletList = this;//place new bullet at start of list
this.previous = null;
this.draw = function(){
//do stuff here
this.next && this.next.draw();//call next item in the list, if any
if (shouldIBeRemoved){//placeholder, obviously
if (this.next && this.prev){//remove from middle of list
this.prev.next = this.next;
this.next.prev = this.prev;
}
else if (this.next && !this.prev){//remove from beginning of list
bulletList = this.next;
this.next.prev = null;
}
else if (this.prev && !this.next){//remove from end of list
this.prev.next = null;
}
else if (!this.prev && !this.next){//remove only item in list
bulletList = null;
}
}
}
}
then to draw every bullet, simply call:
if (bulletList)
bulletList.draw();
The problem was that I was translating the context in which all the bullets are, each time a new bullet was created. This meant that each bullet would be moved by x and y away from the previous one. It made it seem like the bullets were being created where they weren't supposed to be. The "unpredictability" was caused by the fact that the bullet takes on the player's rotation, so whenever a new bullet was created, it's rotation was increased by however much the player rotated before the new bullet was fired, on top of the previous bullet's rotation.
Putting context.save(); before the translation/rotation of the bullet's hitbox and context.restore(); after it perfectly solved the issue:
Bullet.draw = function() {
engine.circle(this.x, this.y, 4, "black");
if(hitbox == true) {
var c = engine.canvas.getContext('2d');
c.save();
c.translate(this.x, this.y);
//c.rotate(this.rot);
c.beginPath();
c.strokeStyle="#00FF00";
c.strokeRect(-5, -5, 10, 10);
c.closePath();
c.stroke();
c.restore();
}
}
Someone else mentioned that I was using array.splice(); in a for loop. This made it so that when a bullet (i) is deleted, the bullet right after (i+1) is moved one index back (i). So that bullet was essentially skipped over.
I could notice this sometimes when looking at the bullets while one was deleted- They "jumped" ahead.
The solution was to put i -= 1 after bullets.splice(i, 1);. This makes the next iteration of the loop go one index back, solving the occassional stuttering of the bullets:
shoot: function() {
if(engine.keyDown.sp == true) {
if(this.fire > 5) {
engine.bullets.unshift(new Bullet(this.x, this.y, this.rot, this.velocity));
this.fire = 0;
}
}
if(this.fire<=5) {
this.fire++
}
for(i = 0; i < engine.bullets.length; i++) {
engine.bullets[i].move();
engine.bullets[i].draw();
if(engine.bullets[i].x > engine.canvas.width+5 || engine.bullets[i].x < -5
|| engine.bullets[i].y > engine.canvas.height+5 || engine.bullets[i].y < -5) {
engine.bullets.splice(i, 1);
i-=1;
}
}
}
Thanks for all the answers.
I am creating a very basic sprite for a game (it is drawn in Canvas/Context/LineTo). I want its expression to change randomly based on two different draw methods. This is my attempt at this:
drawFace = function () {
if (Math.random() < 0.05) {
Player.drawhappyface(context);
}
else if (Math.random() < 0.1) {
Player.drawsadface(context);
}
}
drawFace();
I can confirm that the drawhappyface and drawsadface draw methods work independent of this function (respectively drawing a smile and a frown). But using this function and its logic, they're simply never drawn (the player entirely lacks a face). So, have I written this wrong? I'm inspired by the following simulation which has constantly animating expressions also using Math.random: http://www.blobsallad.se/
If I instead write the function like this, then absolutely nothing is drawn on the canvas (all other sprites, etc. also not drawn):
drawFace = function (context) {
if (Math.random() < 0.05) {
Player.drawhappyface(context);
}
else if (Math.random() < 0.1) {
Player.drawsadface(context);
}
}
drawFace();
The problem might be that you call Math.random() in both if statements and then they will have different values. Call Math.random() only once and save the value for every time you need/call drawFace Try like so:
drawFace = function () {
var randomNumber = Math.random();
console.log(randomNumber);
if (randomNumber < 0.05) {
console.log('randomNumber < 0.05');
}
else if (randomNumber < 0.1) {
console.log('randomNumber < 0.1');
}
}
drawFace();
if you just want to draw happy or sad face you can do even simpler if else
drawFace = function () {
var randomNumber = Math.random();
console.log(randomNumber);
if (randomNumber < 0.5) {
console.log('draw happy face');
} else {
console.log('draw sad face');
}
}
drawFace();
I hope this code explains what I'm trying to do. I have a pool table, and I want the balls to accelerate into the pockets if they are close enough. At this point I'm not yet checking the distance, just working to figure out how to do it.
I'm sure there is a better way!
balls.forEachAlive(
pockets.forEachAlive( moveBallTowardPocket, this), this);
Update: The following code is working except one thing, the scale change for balls on the first five pockets. Acceleration is working for all balls to all pockets. Scale change is only working on the last pocket, not the first five.
function update() {
pockets.forEachAlive(function(pocket) {
accelerateBallToPocket(flipper, pocket, 60);
balls.forEachAlive(function(ball) {
accelerateBallToPocket(ball, pocket, 60);
});
});
//...
}
function accelerateBallToPocket(ball, pocket, speed) {
if (typeof speed === 'undefined') {
var speed = 120;
}
var pocket_body_x = pocket.body.x;
var pocket_body_y = pocket.body.y;
var ball_body_x = ball.body.x;
var ball_body_y = ball.body.y;
// move ball toward pocket if close enough
var dx = ball_body_x - pocket_body_x; //distance ship X to enemy X
var dy = ball_body_y - pocket_body_y; //distance ship Y to enemy Y
var dist = Math.sqrt(dx*dx + dy*dy); //pythagoras
if (dist < pocket_radius * pocket_leniency_factor) {
// accelerate ball to pocket on right angle
var angle = Math.atan2(pocket.y - ball.y,
pocket.x - ball.x);
ball.body.rotation = angle + game.math.degToRad(90);
ball.body.force.x = Math.cos(angle) * speed;
ball.body.force.y = Math.sin(angle) * speed;
// change scale
// FIXME only works on the last pocket lower right
if (ball === flipper) {
ball.scale.setTo(Math.tan(pocket.x - ball.x),
Math.tan(pocket.y - ball.y));
} else {
ball.scale.setTo(Math.sin(pocket.x - ball.x),
Math.cos(pocket.y - ball.y));
}
} else {
// reset the scale when the ball is out of range of the pocket
ball.scale.setTo(1.0, 1.0);
}
}
2nd Update:
The following, based on the solution, has me going in the right direction again, I think...
for (var i = 0; i < pockets.children.length; i++) {
accelerateBallToPocket(cue, pockets.children[i], 60);
if (cue.pocketing) break;
}
for (var i = 0; i < balls.children.length; i++) {
if (balls.children[i].pocketing) continue;
for (var j = 0; j < pockets.children.length; j++) {
accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
if (balls.children[i].pocketing) return;
}
}
Ok, the problem is that you set the scale to 1 if the ball isn't close to a pocket. And, as you check each ball against each pocket, there will always be one pocket (that is checked later in the loop) that the ball is not close too, except the last pocket in the pocket list. So, even if the ball scale is set to the correct value, it will be reset when the next pocket is being checked.
What you can do is check whether a ball is close to at least one pocket, if it is then it can't be close the the other pockets so you don't check again agaist the other pockets.
// Consider that every ball is not inside a pocket
balls.forEachAlive(function(ball) {
ball.inPocket = false;
});
flipper.inPocket = false; // You should really add the flipper to the balls group to remove duplicate code
pockets.forEachAlive(function(pocket) {
if(!flipper.inPocket) accelerateBallToPocket(flipper, pocket, 60);
balls.forEachAlive(function(ball) {
if(!ball.inPocket) accelerateBallToPocket(ball, pocket, 60);
});
});
Then, in your move function you have to set the inPocket member to true if a ball is close to the pocket.
function accelerateBallToPocket(ball, pocket, speed) {
...
if (ball === flipper) {
ball.scale.setTo(Math.tan(pocket.x - ball.x),
Math.tan(pocket.y - ball.y));
ball.inPocket = true;
} else {
ball.scale.setTo(Math.sin(pocket.x - ball.x),
Math.cos(pocket.y - ball.y));
ball.inPocket = true;
}
} else {
// reset the scale when the ball is out of range of the pocket
ball.scale.setTo(1.0, 1.0);
}
}
And alternative would be to revers the loop order, first iterate through all balls and for each ball check each pocket, once you find that is in a pocket continue the outer loop (skipping the check for the other pockets). In order to do this your accelerateBall function should return true or false, being true when the ball is close enough to the pocket and false otherwise.
I would re-write your iterations like this:
for (var i = 0; i < pockets.children.length; i++) {
accelerateBallToPocket(cue, pockets.children[i], 60);
if (cue.pocketing) break;
}
// Stumped...
for (var i = 0; i < balls.children.length; i++) {
// No need for the check here, each ball should have pocketing=false, set at the top of the update loop
// This means, that balls.children[i].pocketing will always be false here
for (var j = 0; j < pockets.children.length; j++) {
accelerateBallToPocket(balls.children[i], pockets.children[j], 60);
if (balls.children[i].pocketing) break; // stop checking the rest of the pockets for this ball
}
}