Preventing onclick-function to be active when in settimeout function - javascript

Im creating a memory and I almost have it all done. My remaining problem is that while in the setTimeout function,
setTimeout(function(){
for(i = 0; i < guesses.length; i++){
if(clearedPairs[i] != i){
var reset = document.getElementById(cardPosition[i]);
reset.removeAttribute("style");
}
}
score.innerHTML = parseInt(score.innerHTML,10) - 10;
resetValues();
}, 800);
If a click occurs on another card, while its waiting to turn the two open cards back over, the player will receive additional minus point, and thats not whats supposed to happen. Can anyone help?
I can post more of the code if needed.

You can use a variable to watch your state: when in the setTimeout function, set it to true. When it's finished and clicks are acceptable, set it to false. Then just use an if statement in your click handlers to check the state.
var inFunction = false;
setTimeout(function(){
inFunction = true;
for(i = 0; i < guesses.length; i++){
if(clearedPairs[i] != i){
var reset = document.getElementById(cardPosition[i]);
reset.removeAttribute("style");
}
}
score.innerHTML = parseInt(score.innerHTML,10) - 10;
resetValues();
inFunction = false;
}, 800);
Does that address your issue?

Related

JS: setInterval running as if there were multiple intervals set

So, I've been trying to figure out JS, and what better way to do so than to make a small project. It's a small trivia game, and it has a question timer I've made using setInterval. Unfortunately, after answering multiple questions, the interval's behaviour gets very weird - it runs the command twice every time. I guess it's my faulty implementation of buttonclicks?
By the way, if my code is awful I am sorry, I've been desperate to fix the issue and messed with it a lot.
function startGame(){
if (clicked === true){
return;
}
else{
$("#textPresented").html("Which anthem is this?");
$("#button").css("display", "none");
currentCountry = getRndInteger(0,8);
console.log(currentCountry);
var generatedURL = anthemnflags[currentCountry];
console.log(generatedURL);
audios.setAttribute("src", generatedURL);
audios.play();
$("#button").html("I know!");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
console.log("cleared y" + y);
x = setInterval(function(){
y = y - 1;
console.log("Counting down..." + y)
}, 1000);
console.log("INTERVAL SET");
}
}
Here is the console output:
cleared y10 flaggame.js:59:17
INTERVAL SET flaggame.js:64:17
AbortError: The fetching process for the media resource was aborted by the user agent at the user's request. flaggame.js:49
Counting down...9 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...8 flaggame.js:62:20 ---- THESE TWO ARE BEING PRINTED AT THE SAME TIME
Counting down...7 flaggame.js:62:20
Counting down...6 flaggame.js:62:20
Counting down...5 flaggame.js:62:20
Counting down...4 flaggame.js:62:20
Counting down...3 flaggame.js:62:20
Counting down...2 flaggame.js:62:20
Counting down...1 flaggame.js:62:20
Counting down...0
THE REST OF MY CODE:
function middleGame(){
$("#button").css("display", "none");
var n = document.querySelectorAll(".flagc").length;
correctIMG = getRndInteger(0,n-1);
showFlags();
var taken = new Array();
for (var i = 0; i < n; ++i){
if (i === correctIMG){
images[i].attr("src", "res/" + flagsfiles[currentCountry]);
taken[currentCountry] = true;
}
else{
var randomFlag = getRndInteger(0, flagsfiles.length);
if (randomFlag !== currentCountry && taken[randomFlag] !== true){
images[i].attr("src", "res/" + flagsfiles[randomFlag]);
taken[randomFlag] = true;
}
}
}
$(".flagc").click(function(){
clickregister(this);
});
}
function continueManager(){
if (!clicked){
audios.pause()
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function clickregister(buttonClicked){
if ($(buttonClicked).attr("id") != correctIMG){
points = points - 1;
flagARR[$(buttonClicked).attr("id")].css("display", "none");
console.log("INCORRECT");
}
else{
if (y >= 0) {
var addedPoints = 1 + y;
points = points + addedPoints;
$("#points").html(points);
}
else{
points = points + 1;
}
hideFlags();
clicked = false;
startGame();
}
}
$(function(){
hideFlags();
$("#textPresented").html("When you're ready, click the button below!");
$("#button").html("I am ready!");
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
alert("STARTING GAME");
startGame();
}
});
});
Basically this is how it works:
When the "I am ready" button is clicked, startGame() is called. It plays a random tune and counts down, until the player hits the "I know" button. That button SHOULD stop the interval and start the middleGame() function, which shows 4 images, generates a random correct image and awaits input, checks if it's true, then launches startGame() again.
The first and second cycles are perfect - after the third one things get messy.
I also noticed that the "INCORRECT" log gets printed twice, why?
EDIT: here is the minimized code that has the same issue:
var x;
var gameStarted = false;
var y;
var clicked;
$(function(){
$("#button").click(function () {
if (!gameStarted){
gameStarted = true;
startGame();
}
});
});
function startGame(){
console.log("startgame()");
if (clicked === true){
return;
}
else{
console.log("!true");
$("#button").css("display", "block");
$("#button").click(function () {
continueManager();
});
y=10;
x = setInterval(function(){
y = y - 1;
console.log(y);
}, 1000);
}
}
function continueManager(){
if (!clicked){
clearInterval(x);
x = 0;
clicked = true;
middleGame();
return;
}
}
function middleGame(){
$("#button").css("display", "none");
var taken = new Array();
$(".flagc").click(function(){
clickregister(this);
});
}
function clickregister(buttonClicked){
console.log("clickgregister");
//Irrelevant code that checks the answers
clicked = false;
startGame();
}
EDIT2: It appears that my clickregister() function gets called twice, and that function then calls startGame() twice.
EDIT3: I have found the culprit! It's these lines of code:
$(".flagc").click(function(){
console.log("button" + $(this).attr("id") + "is clicked");
clickregister(this);
});
They get called twice, for the same button
I fixed it!
It turns out all I had to do was to add
$(".flagc").unbind('click');
Before the .click() function!
You need to clear the interval first then call it again. You can do that by creating a variable outside of the event listener scope and in the event listener check if the variable contains anything if yes then clear the interval of x. After clearing the interval you can reset it.
Something like this:
<button class="first" type="submit">Button</button>
const btn = document.querySelector('.first');
let x;
btn.addEventListener("click", () => {
x && clearInterval(x)
x = setInterval(() => console.log("yoo"), 500)
})
This is because if you don't clear the interval of x it will create a new one on every button press.

I'm stuck in a project about snow animation in javascript

I have to create a script that simulates the animation of snow in javascript (I would prefer without using canvas if possible). I'm stuck at this point and I don't know where the mistake is. when I run the program google chrome crashes and the console does not give me errors, I think the error is due to a loop or some incorrect statements, I am attaching the code hoping for your help!
var direction=true; //true=right false =left
var active=true; //if true run the cycle,false stops the cycle
function startSnow() {
var _snowflakes = new Array(30);
var wid=50; //distance from a snowflake to another
var counterX; //var for editing the x position
var counterY; //var for editing the y position
for (var i=0; i< 30; i++) //cycle that initializes snowflakes
{
_snowflakes[i] = document.createElement("img");
_snowflakes[i].setAttribute("src","snowflake.png"); // setting the image
_snowflakes[i].setAttribute("class", "snowflake"); //setting the css style
_snowflakes[i].style.visibility ="inherit"; //when the function is running snowflakes have to be visible, when it finishes they have to be invisible
_snowflakes[i].style.right = (wid*i)+"px"; //set the distance from the left margin
_snowflakes[i].style.top = "30px"; // set the distance from the top
document.getElementById("background").appendChild(_snowflakes[i]);
}
while(active)
{
move();
}
function move() //function that moves the snowflake
{
for(;;)
{
if(counterY>=600) //when the snowflake reaches 600px from the top the function has to stop and hide snowflakes
{
for(var i=0;i<30;i++)
_snowflakes[i].style.visibility = "hidden";
active=false;
break;
}
else
{
if ((counterY%50)==0)
{
direction=!direction //every 50 Y pixels the snoflake change direction
}
counterY++;
for(var i=0;i<30;i++)
{
_snowflakes[i].style.top = counterY+"px"; //Y movement
if (direction==true)
{
_snowflakes[i].style.right = (_snowflakes[i].offsetLeft+counterX) + "px"; //x right movement
counterX++;
}
else
{
_snowflakes[i].style.right = (_snowflakes[i].offsetLeft+counterX) + "px"; //x left movement
counterX--;
}
}
}
}
}
}
Indeed, your code gets into an infinite loop because your variable counterY is not initialised and so it has the value undefined. Adding one to undefined gives NaN, and so you never get to that break statement.
But more importantly, you need a different approach, because even if you fix this, you'll never see an animation happening. For actually seeing the animation, you need to give the browser time to update the display. So a while and for(;;) loop are out of the question.
Instead call move once, and inside that function, in the else block, call requestAnimationFrame(move). This will give the browser time to repaint before move is called a gain. Remove the for(;;) loop, and remove the break.
There is also a logical error in how you move horizontally. As you read the current offsetLeft it makes no sense to increment counterX as that will lead to increasing (relative) jumps to the right (or left). Instead you should just add (or subtract) 1 to offsetLeft -- you can do away with counterX. Also, don't assign that to style.right, but to style.left.
So everything put together (cf. comments where there is a change):
var direction=true;
var active=true;
function startSnow() {
var _snowflakes = new Array(30);
var wid=50;
// var counterX = 0; -- not used.
var counterY = 0; // Need to initialise!
for (var i=0; i< 30; i++) {
_snowflakes[i] = document.createElement("img");
_snowflakes[i].setAttribute("src", "snowflake.png");
_snowflakes[i].setAttribute("alt", "❄"); // added for when image not found
_snowflakes[i].setAttribute("class", "snowflake");
_snowflakes[i].style.visibility = "inherit";
_snowflakes[i].style.left = (wid*i)+"px"; // assign to style.left
_snowflakes[i].style.top = "30px";
document.getElementById("background").appendChild(_snowflakes[i]);
}
// No while loop. Just call move
move();
function move() {
//No for (;;) loop
if (counterY>=600) {
for (var i=0;i<30;i++) {
_snowflakes[i].style.visibility = "hidden"; // you forgot the underscore
}
active=false;
// No break -- function will just return
} else {
if ((counterY%50)==0) {
direction=!direction
}
counterY++;
for (var i=0;i<30;i++) {
_snowflakes[i].style.top = counterY+"px";
if (direction==true) {
// assign to style.left,
_snowflakes[i].style.left = (_snowflakes[i].offsetLeft+1) + "px"; // add 1
} else {
_snowflakes[i].style.left = (_snowflakes[i].offsetLeft-1) + "px"; // sub 1
}
}
requestAnimationFrame(move); // schedule next run of this function
}
}
}
startSnow(); // Need to start it!
#background { width: 800px; height: 800px }
.snowflake { position: absolute; font-size: 40px }
<div id="background">
</div>

Change img src every second using Jquery and Javascript

I have been trying to write a script that changes an image src every two seconds based on a list.
So, everything is inside a forloop that loops over that list:
$(document).ready(function() {
var lis = {{dias|safe}}; <----- a long list from django. This part of the code works fine.
for (i=0; i<lis.length; i++){
src_img = lis[i][1];
var timeout = setInterval(function(){
console.log(src_img)
$("#imagen").attr("src", src_img);
}, 2000)
}
});
It doesn't work, the console logs thousands of srcs that correspond to the last item on the list. Thanks a lot for your help.
you don't need to run cycle in this case, you just save "pointer" - curentImage and call next array item through function ever 2 sec
var curentImage = 0;
function getNextImg(){
var url = lis[curentImage];
if(lis[curentImage]){
curentImage++;
} else {
curentImage = 0;
}
return url;
}
var timeout = setInterval(function(){
$("#imagen").attr("src", getNextImg());
}, 2000)
var curentImage = 0;
var length = lis.length;
function NewImage(){
var url = lis[curentImage];
if(curentImage < length){
currentImage++;
}
else{
currentImage = 0;
}
return url;
}
var timeout = setInterval(function(){
$("#imagen").attr("src", getNextImg());
}, 2000)
PS: Better than the previous one, Checks for lis length and starts from first if you reach end.
You need something like this
$(document).ready(function() {
var index = 0;
setInterval(function(){
src_img = lis[index++ % lis.lenght][1]; // avoid arrayOutOfBounds
$("#imagen").attr("src", src_img);
}, 2000)
});

Stop awaiting input after fixed time

I'm new to web programming and I stumbled upon a problem that I couldn't solve and I'm not sure it can be solved. I'm creating a very simple "game" using jquery, and I want to make the thread to stop waiting for the (keydown) input and just carry on with the code, so I can perform either a simple upwards "jump", or a " left jump"/"right jump". Can it be done?
Here follows the codebit from what I've been doing so far:
http://www.codecademy.com/pt/pySlayer10761/codebits/OYQ11a/edit
You need a game loop thats running independantly from your keydown-handler. Elsewise any animation you might hack into the keydown handler might stop the moment no inputs are made anymore.
By looking at your code, I can see you tried to do it by creating a new setTimeout() on those keydowns. You are creating this for every keydown event fired. This is very likely to crash/freeze your browser at some point if the engine does not realize you are creation the same timeout over and over again.
Do it like this: in the onkeydown handler you only set a variable keydowncode to the keycode value. Then you create a new game loop like this
<script>
var keydownCode = 0;
var isInAnimation = false;
var animatedKeydownCode = 0;
var animationStartTime = 0;
var animationStartValue = 0;
// Lightweight keydown handler:
$(document).keydown(function(key) {
keydownCode = parseInt(key.which,10);
}
$(document).keyup(function(key) {
keydownCode = 0;
}
function animation() {
// here comes your animation logic..
// e.g. keep moving for 100 to 200 milliseconds after keypress
// Milli secs difference from
var nowTime = Date.now();
// Animations get prioritized: Only one animation at the same time!
if(isInAnimation) {
switch(animatedKeydownCode) {
case 37:
var delta = (nowTime-animationStartTime)/100*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').left(animationStartValue-delta);
case 37:
var delta = (nowTime-animationStartTime)/200*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').top(animationStartValue-delta);
case 39:
var delta = (nowTime-animationStartTime)/100*10;
if(delta > 10) { delta = 10; isInAnimation = false; }; // Animation over!
$('img').left(animationStartValue+delta);
}
// Ready to take new input, if its not outdated
} else {
// If some key is down and no animations active
if(keydownCode > 0) {
switch(keydownCode) {
case 37:
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').left();
isInAnimation = true;
case 38:
// Only start a jump if on bottom
if($('img').css("top") == '390px') {
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').top();
isInAnimation = true;
}
case 39:
animationStartTime = nowTime;
animatedKeydownCode = keydownCode;
animationStartValue = $('img').left();
isInAnimation = true;
}
}
}
window.requestAnimationFrame(animation);
}
window.requestAnimationFrame(animation);
</script>
This is no full game, you need to adjust it by yourself to get a working game. E.g. you might want to add some gravity to get mario down again when there is no input..
I think you are looking for setTimeout().
Like this:
setTimeout(function(){
// do something here which will be executed after 5 seconds.
},5000);
You can't stop a thread in javascript as it is single threaded.

Javascript slideshow won't stop

I'm creating a web page with a slide show activated by clicking a button. When I click the button the first time, I want the user to be prompted with how fast they want it to change to the next image before actually running the slide show. The next time the button is clicked, I want the slideshow to stop. Right now the first part is working, but when I click it a second time it just shows the prompt again and doesn't stop the slideshow. Can anyone tell me what I'm doing wrong? Here is my code for the given function:
function slideShow(){
var temp2 = 0;
if (temp2 == 0){
var speed = prompt("How fast would you like to the slideshow to go?");
var timerID = setInterval("clock()",speed);
temp2 = 1;
}
else if (temp2 == 1){
clearInterval(timerID);
temp2 = 0;
}
}
Move
var timerID
to outside of the function declaration.
var timerID
function slideShow(){
var temp2 = 0;
if (temp2 == 0){
var speed = prompt("How fast would you like to the slideshow to go?");
timerID = setInterval("clock()",speed);
temp2 = 1;
}
else if (temp2 == 1){
clearInterval(timerID);
temp2 = 0;
}
}
That would be the easiest way. You are basically just throwing that variable away everytime you call that function.
Just so other advice. You don't really ever want to use a string in setInterval.

Categories

Resources