Sequentially filling shapes in canvas using setTimeout - javascript

I made a maze application with a route finder. As it travels along the route, it makes a call to draw the canvas, highlighting each cell en route. However what ends up happening is it blocks until it has completely finished and then draws to the canvas. Roughly like so:
Path.prototype.travelTo (cell) {
this.previous = this.cell;
this.cell = cell;
this.cell.fill = 'yellow';
this.maze.draw();
var choice = findChoice();
this.travelTo(choice);
};
The maze class keeps track of all cells and its draw function loops through each cell, calling the cells own draw function.
I made a quick jsfiddle (http://jsfiddle.net/amctammany/99VVu/) that emulates the problem.
Here it travels from one cell to the next by recursively calling itself via setTimeout. The result is the same, it instantly fills all cells, without even waiting for any amount of time.
Any help would be appreciated.

I had a look at your jsfiddle, and the first thing I noticed is your setTimeout:
window.setTimeout(fillNext(i + 1), 500);
But probably you meant to do this:
window.setTimeout(function() {fillNext(i + 1)}, 500);
You should set the fillNext(i+1) as a callback to setTimeout,
not use the return value of fillNext(i+1) as the argument of window.setTimeout()

Update the following line as given below.Then you can see the animation.
"window.setTimeout(fillNext(i + 1), 500);" To "window.setTimeout(fillNext, 100,(i + 1));"
I have updated the fiddle.You can check it now.

Related

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

Problems with making "Catch the falling hair" game

I know, this is a strange one. I'm trying to make a simple Javascript game where:
The player has to catch the randomly falling head hair.
The hair returns to the head when caught.
Catching the falling hair increases the Score
The hair falls faster and faster over time.
If all of the hair falls then it's GAME OVER.
I've given it a go, and copied most of it to my fiddle here, which is an abstract version of what I'm trying to achieve.
Current Javascript:
$(document).ready(function(){
//randomize hair initial rotation
$('.hair').each(function(){
var random = Math.random()*360;
var degree = "rotate("+random+"deg)";
$(this).css("transform",degree);
});
//set points to 0
$('#points').text(points);
});
function startGame() {
start = true;
var level = 1;
//move catcher with hand
$( document ).on("mousemove", function(event) {
var catcherX = event.pageX - 50;
$('#catcher').css("left",catcherX);
});
$('.hair').each(function() {
var wait = Math.ceil(Math.random()*10000)/level;
randomX = Math.random()*($('#gameDiv').width());
function makeDestination(hair) {
hair.css("top", 510);
hair.css("left", randomX);
}
setTimeout(makeDestination($(this)), wait)
})
};
startGame();
The biggest problems I'm having are:
How can I make the hair fall after a random interval? wait currently isn't doing anything in the setTimout function.
How can I make the hair function start again after being caught?
I also feel like there must be a much better way of writing this game, what do you guys think?
I made the setTimeout reference the function instead of calling it immediately (putting the parens calls it and references the return value, putting just the function name references). Then I tweaked the transition to animate the top over 3 seconds while the left takes just 1 second. Then I made makeDestination call itself after a delay. Lastly, the "hair" needs to jump back up to the top, so I change the transition to be immediate, change the CSS, then change the transition back to animate.
https://jsfiddle.net/9pq6xfxc/1/
I leave it to you to detect the intersection of the cyan box and the hair. While this can obviously be done on mouse movement, it's going to be trickier to find the hairs that fall on a stationary hand.

Canvas rendering once, after all actions

A little confused with one moment, appreciate any help.
I'm making an app, that uses canvas for rendering game board.
And I faced a problem that its not optimal, rendering canvas for each little change.
Here's what the structure is at the moment:
function renderCanvas() {
// calling for each row
}
function renderRow() {
// calling for each cell
}
function renderCell() {
// Here i use FillRect and StrokeRect both
}
Functions cooperate with passing context to each other.
Now it renders each cell. And using beginPath appears to deal only with stroke.
I wonder if i can startPath (like beginPath) somehow in renderCanvas function and after all operations with context are done - i could render that all once?
You can only do one styling per beginPath...
So if your cells require different colors, fonts, opacities then you must do a beginPath for each different style (but you can group same-styles together into one beginPath).

Sprite Animation using a for loop

I am trying to create an animation using a sprite sheet and a for loop to manipulate the background position until it has reached the total number or rows in the sheet. Ideally a reset back to the initial position would be practical, but I cannot even get the animation itself to trigger...
With the current function, no errors occur and the background position in my CSS does not change. I even recorded using Chrome DevTools Timeline and there was nothing either then everything related to my page loading. I have also tried using "background-position-y" as well as a simpler value rather then the math I currently have in place.
This is my function:
$(document).load(function() {
var $height= 324;
var $rows= 34;
for(var i=0; i<$rows; i++){
setTimeout(function() {
$('#selector').css("background-position", "0px ", "0" - ($height*i) + "px");
}, 10);
}
});
I hate to ask a question that is similar to previous issues, but I cannot seem to find another individual attempting sprite sheet animation with a for loop, so I suppose it is it's own problem.
p.s. I didn't include a snippet of my HTML and CSS because it is pretty standard and I don't see how that could be the problem. That being said, I am all ears to any potential thoughts!
I am completely revamping my answer
This issue is that the for() loop is not affected by the setTimeout so the function needs to be written on our own terms, not with a loop
Working Fiddle
Here it is..
var $height= 5;
var $rows= 25;
var i = 1; // Starting Point
(function animateMe(i){
if(i<=$rows){ // Test if var i is less than or equal to number of rows
var newHeight = 0-($height*i)+"px"; // Creat New Height Position
console.log(i); //Testing Purposes - You can Delete
$('#selector').css({"background-position": "0px "+ newHeight}); // Set New Position
i++; // Increment by 1 (For Loop Replacement)
setTimeout(function(){animateMe(i)}, 1000); // Wait 1 Second then Trigger Function
};
})(0);
Here is your solution
First Change
$(document).load() To $(document).ready()
And Change .css Syntex as
$('#selector').css("background-position",'0px '+(0 - ($height*i))+'px');
Here is fiddle Check it ihad implemented it on my recent project http://jsfiddle.net/krunalp1993/7HSFH/
Hope it helps you :)

Canvas element not updating

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.

Categories