The for loop does not run like I would expect it to. I would expect the for loop to run only once, but when I run it, it shows an animation.
The programming environment I am using:
https://www.khanacademy.org/computing/computer-programming/programming/arrays/pp/project-make-it-rain
var xPositions = [200];
var yPositions = [0];
draw = function() {
background(204, 247, 255);
for (var i = 0; i < xPositions.length; i++) {
noStroke();
fill(0, 200, 255);
ellipse(xPositions[i], yPositions[i], 10, 10);
yPositions[i] += 5;
}
};
When we say i++ then the condition i < xPositions.length is no longer true.
So why does the the loop run more than once?
I was told that because the draw function is called forever, the loop will also get called forever.
But, the second time the loop tries to run, the condition of the for loop is not met and therefore should not run.
Thanks.
Blockquote
.
Blockquote
I would expect the for loop to run only once
This is the correct expectation...with one addtion: the for loop will only run once per function call. If draw() is called more than once, then it will execute the loop every time you call the function.
draw() creates a single frame of the animation. In this case, you move the rain drop down 5 pixels and then render the frame with it at the new position. But to get the animation, you need to call draw() several times a second. This is similar to flipping the corners of your notebook with a slightly different version of a stick man drawn on each page to create an illusion of motion. The repeated calls to draw() are taken care of in your programming environment.
The for loop you write inside of draw() is intended to iterate over each raindrop. In this case, you only have one. I suggest adding 3 or 4 raindrops at different positions. Then you will see how the for loop iterates over each raindrop, moving them each down 5 pixels. Then your programming environment on Kahn Academy will call draw() several time per second for each frame in the animation.
The loop should run only once, but in processing js, the draw function is called forever.
Related
I'm trying to convert an image into a picture that only has a certain amount of colors in p5.js. I am doing this by picking num random colors. Then, I'm going through every pixel in the image with loadPixels() and giving it a score. This score is determined by how close the color is to one of the random colors. I do this by adding the difference individually from the rgb values and then choosing the lowest score. For example, if I had num = [color(100, 100, 100), color(200, 200, 200)] and I was looking at a pixel that has color(100, 150, 110) then the score would be not 240 (the difference between the image pixel and the 200 color) but instead 60. This all works fine. Next, what I'm trying to do is make sure that every pixel has a score under scoreBoundary. Originally, this variable is set to 0. If the score of a pixel is more than scoreBoundary, I alter the closest random color to bring the pixel's score under scoreBoundary. This all should work fine. After a few loops (I haven't decided how many yet, maybe it has to do with the average pixel score or something), if there is still a pixel over scoreBoundary, I increase scoreBoundary. Eventually, I should have the best picture I can have with num colors. (If you want to know, I'm trying to make a sort of Cross-Stitch Clone.)
Now for my problem. I want to make a temporary progress bar, because this method is very slow. Originally, I tried putting text that said pixelNum + " out of " + pixels.length. However, since this process was in a for loop, this didn't show up. So, I tried putting this process in the draw loop. Now the text shows up, but it's unbearably slow. After about a minute, I was maybe 1% done with the first loop (and remember, there will be thousands) because it was only performing one calculation per frame. Now I ask you two things, and either solution helps.
One, is there a way to have a process that works as fast as it can away from the draw loop? For example, can I have this process run multiple times per frame (without just adding i < previousBoundary * howMuchFasterIWantItToBe) while still being linked to draw for the progress bar?
Two, is there another way to go about this? Another library or method that reduces the number of colors in an image to num?
You don't really show any code that is reproducible to explain what issue you are having.
In any case, what you are looking for (for your first question) is an async function.
SEIZURE WARNING FOR PHOTOSENSITIVITY
Seriously, this example sketch will wreck your eyes but you can see two ellipses working on different schedules because of the async function
Importantly, I had to append the start of the sketch with /*jshint esversion: 9 */ for the editor to allow async to be used:
/*jshint esversion: 9 */
let thing = 10;
let thing2 = 10;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
drawOther();
for(let i = 0; i < 1000; i++){
if(thing <= 400){
thing += 2;
}else{
thing = 10;
}
fill(255)
stroke(0);
ellipse(width, height, thing, thing);
}
}
const drawOther = async () => {
for(let i = 0; i < 100; i++){
if(thing2 <= 400){
thing2 += 2;
}else{
thing2 = 10;
}
fill(0);
stroke(255)
ellipse(0, 0, thing2, thing2);
}
}
You can read more about async functions here but basically, it does what you want - to launch a separate thread of activity that won't block your main loop.
If you want to return anything from an async function you would need to read about await and promises as well.
I am a beginner and am working on learning generative art and creative coding. this code aims at generating lines randomly and the number of iterations is random as well.
https://editor.p5js.org/rawrro/sketches/j4V6zpnMr
code:
function setup() {
createCanvas(windowWidth-20, windowHeight-20);
for (let i = random(100); i>0; i--);
{
line(random(0,600),random(0,600),random(0,600),random(0,600))
}
}
function draw() {
background(GRAY);
}
First, there is a problem of syntax in the for loop, There must not be a semicolon after for(). Correct syntax:
for (let i = random(100); i>0; i--) {
line(random(0,600),random(0,600),random(0,600),random(0,600));
}
Second, the setup() function is executed once at the start, the draw() function is executed 60 times per second. Here, you erase the lines by defining a background color in draw(). If you want the lines to be generated each frame, the for loop should be in draw() (but the animation will be too fast!)
Third, but it's not important, the random function doesn't need two arguments: random(600) will generate a random value between 0 and 600.
In p5.js I'm trying to visualise a Linear Search Algorithm. I have an array of numbers and want to visualise them by drawing them as lines pointing upwards.
When I put the forEach loop in the setup function, nothing appears. If I put it in draw function, I see the exact result that I'm looking for pop up for half a second and then dissapear...
(The setup function is called when the program is run, and the draw loop is continuously called every frame) (The line function draws a line from the first x,y to the second x,y line(x,y x,y)
Here's the code:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let buffer = 0
function setup() {
createCanvas(400, 400);
numbers.forEach((number) => {
stroke(0);
strokeWeight(4);
line(buffer, height, buffer, number * 50)
buffer += 15
});
}
function draw() {
background(255);
}
Think about the order that things happen in.
You said it yourself:
The setup function is called when the program is run, and the draw loop is continuously called every frame
So with the code you have, the setup function runs once at the very beginning of your program, and then the draw function is called 60 times per second. The only thing you're doing inside the draw function is drawing a background, which removes what you drew in the setup function. Try removing the call to background(255) to see what I mean.
Then when you move your code into the draw function, I'll offer this hint: What is the value of the buffer variable each frame? You might use some console.log() statements to answer that.
I have a couple of SVG Lines that connect to dots. I want to animate these lines one by one to give the impression they're being drawn.
My code is set up like this:
function connectDots(dots){
var lines = document.querySelectorAll(".connection-line")
var wait = 300 //Execute 1 animation every 300 ms
for(i=1; i<dots.length; i++){
// Some irrelevant logic
drawLine(line,wait*(i-1));
}
}
function drawLine(line, offset){
var interval = 5;
var animation = setInterval(draw,interval)
function draw(){
setTimeout(function(){
// Animation logic
}, offset)
}
}
The connectDots loop iterates through the dots and draws the corresponding lines between those dots.
The animation logic is there but I'm excluding it because it's not relevant here. I think the problem is with the for-loop, which doesn't work probably because it's executed synchronously in some way and adding a controlled delay (300 * the position of the animation, like 0 for the first, 300 for the second, 600 for the third, and so forth) for every one of those animations is not reliable.
My question: How can I properly create a queue of these lines and animate them one by one? I think I'm looking for either Deferred objects or callbacks, but I'm not sure how to start.
Additional info: The size of the array of dots (and lines) is static, not dynamic. Perhaps that simplifies the issue in this scenario.
I am trying to visualise a reinforcement agent moving through a 2d grid. I coded up a visualisation using canvas, and everytime my agent makes a move I try to update the grid. I was hoping to see an animation, but instead I see nothing until the agent has completed all this moves and I see the final state. If I step through with Google Chromes Developer tools then I can see the individual steps. I do not think it is a problem of my code just running to fast, because each step takes a couple of seconds.
My implementation is as follows, with the function gridWorld() called once to create a new object and executeAction called every time I want to draw. As shown I have used ctx.save(), and ctx.restore(), but that is only an attempt to solve this problem, and it seems to have made no difference.
Thanks
var execute gridWorld = function(action) {
var canvas = document.getElementById("grid");
this.ctx = canvas.getContext("2d");
this.executeAction = function(action) {
this.ctx.save()
// ... Do reinforcement learning stuff
// For every cell in grid, do:
this.ctx.fillStyle = "rgb(244,0,0)"
this.ctx.fillRect(positionX, poisitonY, 10,10)
this.ctx.restore();
}
}
Even if the code takes a long time to execute, the browser will not update the display until there is an actual break in the code. Use setTimeout() to cause a break in code execution whenever you want the canvas to update.
Your not going to see animations because they are happening way too fast. You need to break them up like in the following example.
Live Demo
If I did something like this for example
for(x = 0; x < 256; x++){
player.x = x;
ctx.fillStyle = "#000";
ctx.fillRect(0,0,256,256);
ctx.fillStyle = "#fff";
ctx.fillRect(player.x,player.y,4,4);
}
You would only ever see the player at the end of the board every time that function is called, and you wouldn't see any of the animations in between, because the loop runs too fast. Thats why in my live demo I do it in small increments and call the draw every 15 milliseconds so you have a chance to actually see whats being put on the canvas.