variable doesn't update when function restarts (javascript) - javascript

I'm going to try my best to ask this question without a huge wall of code. Basically I have written a very simple math quiz game. In this game you select a difficulty, the number of questions you want, and the game starts. It asks that number of questions and then you get a score and then the game is over. However, you can restart the game. When you restart, it simply returns you to the home screen, then you can select your options again. The only problem is, we need to keep track of the number of questions remaining in the quiz, the first time around, it works well. We pass numQuestions to the game function. The second time, however, even if I pass numQuestions=10, the value remains 0 from the first time I played the game. Here is the game function:
function startGame(difficulty,numQuestions,score){
// begins game, excluded that come its just some acsii art
// asks question
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
// gives answer options
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
// starts timer
var b = document.getElementById("timer");
timer = new stopWatch(b, {delay: 100});
timer.start();
},5500)
// when answer is clicked, go here
$("#gameScreen").on("click",".answerButton",function() {
// this seems to be the problem: on the second time I play the game, numQuestions remains the value from the first game and continues to go down (-1,-2) and since my selector is (>0), the else statement fires.
numQuestions--;
var time = parseFloat($("#timer span").html());
var correct = parseFloat($("#gameInside").data('answer'));
var userAnswer = parseFloat($(this).html());
if (correct==userAnswer)
tempScore = Math.round(calculateScore(time)*100)/100;
else
tempScore = 0;
score += tempScore;
$("#score").html(Math.round(score*100)/100);
if (numQuestions > 0) {
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
$("#answers").empty();
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
timer.reset();
} else {
$("#answers").empty();
$("#gameInside").html('Game Over! Thanks for Playing!');
timer.stop();
}
});
}
any ideas? Thanks
edit:
$(".numberQButton").click(function(){
numQuestions = parseFloat($(this).html());
$("#numQuestionsScreen").hide();
$("#gameScreen").show();
$("#score").html(0);
startGame(difficulty,numQuestions,score);
});

You're problem (I think) lies in closures. When you declare a function in javascript, any accessing of a variable from outside it's own scope generates what is called a closure. In this case, numQuestions is accessed from inside your event function, creating a closure. The effect of this is that any accessing of the variable numQuestions inside your event functions references the variable as it was from the moment your javascript interpreter came across the event function itself- ie, the first time you play your game.
Have a look at these to get an idea of where it's going wrong.

It sounds like you need to instantiate a new Game object when the game is restarted.

Where do you define the on click listener? If it triggers two times, it seems like you are defining the on click listener in such way, that after you completed one game and start all over, a new listener will be registered so you got 2 in the end.

Related

How to stop a timer from counting when a Javascript memory game finishes?

I have a question on how to stop the timer in a "find the pair" game, built in javascript for a school project.
While trying to look for help online I noticed other javascript projects for a similar game.
However, the ones I found had more use of CSS functionalities, while the one I am trying to finish has practically all the functionalities built in javascript.
To give a description, there is a board (6x8) with random logos, let's call them 'cards'.
The game starts and all the cards are sorted randomly and then hidden.
For 60 seconds all the cards remain in the same position while the player tries to match them.
After that time, only the cards that have not been paired are sorted again, and the player will have to try to pair them again.
One of the things that the code must do is to stop the time when all the cards are correctly paired, i.e. when the game is finished.
Below there is the last version of the code made to end the game.
The function tempo() is supposed to define the time.
The temporizador is the time progress bar.
The contador is the variable used to count the time.
function tempo(){ //function that controls our time progress bar, uses 60 seconds (maxCount) for its cycle
let contador=0;
let maxCount=60;
temporizador=null;
if (temporizador != null) clearInterval(temporizador)
else
temporizador=setInterval(()=>{
contador++;
document.getElementById("time").value=contador;
if(contador===maxCount-5)document.getElementById("time").classList.add("warning"); //when it takes 5 seconds to end the 60 seconds
if(contador===maxCount) { //in the time bar, you can see the bar in red, blinking
clearInterval(temporizador);
document.getElementById("time").classList.remove("warning"); //when cycle finished the red blinking stops
scramblerEscondidas(); //and the function scramblerEscondidas() to sort the unmatched pairs, is executed
}
},1000)
for (let i=0; i<6; i++) { //cycle to iterate the rows of the board
for(let j=0; j<8; j++){ //cycle to iterate the columns of the board
if (game.board[i][j].virada=true) tempo.stop(); //'virada' is a property of each card of the board, if true it displays the logo. defined in the 'const' for the card
game.sounds.win.play();
}
}
}
The last cycle for in this function is supposed to check if all the cards are turned to the player, meaning the game is finished.
It is supposed to stop the time (the progress in the time bar) when this happens, but the timer doesn't stop.
Sorry for my noobness. Can anyone give any tips on how to find a solution for this?
I also tried different approaches but I fear they all used the same logic, which is likely faulty.
Any simple tip would help as I just recently started using javascript.
I didn't see what are you trying to do with these code.
But I got your point in stopping the timer.
To make a timer stop, you just have to make a boolean variable called isHaveWinner set it with with default false value.
Then wrap your counter function with
if (!isHaveWinner) {
...your timer iteration
}
In your game logic, if the game finished set the isHaveWinner to true. So your timer won't run no more

Javascript setInterval: multiple intervals

I'm playing with animations. I'm trying to have two circles move a specified distance and then stop. The issue I'm having is with multiple intervals. I assign each interval to a unique variable, and clearInterval that variable, but the first interval continues on.
Here is the code:
function moveRight(player){
if(player==1){
currentLoc = p1Loc[0]; //global var with player's current location
intervalR1 = setInterval(function(){
p1Loc[0]+=1;
draw(); //function that redraws the canvas
if(p1Loc[0]>currentLoc+wu){ //wu is a single "width-unit"
clearInterval(intervalR1);
}
},5)
}
else{
currentLoc = p2Loc[0];
intervalR2 = setInterval(function(){
p2Loc[0]+=1;
draw();
if(p2Loc[0]>currentLoc+wu){
clearInterval(intervalR2);
}
},5)
}
}
Then, let's say I give the following instructions within a while loop:
instructions = ["moveRight(1)", "moveRight(2)"];
for(instruction in instructions){
eval(instructions[instruction]); //I know, eval(), ugh. Is just temporary
}
What ends up happening is, both players start moving right, but player 2 stops after a single wu, or width-unit while player one keeps going. If i change the instructions to only "moveRight(1);", then player one moves a single wu and stops.
What's going on here?
This is just a guess, since is a bit hard to tell what is going on with only part of the code, but could it be that you are assigning currnetLoc twice, and thus the first player's location will always be always be compared against p2Loc[0]?
So when you call moveRight(1) it sets currentLoc to p1Loc[0] then proceeds. Then immediately after you call moveRight(2) which sets currentLoc to p2Loc[0]. So now the comparison for the interval for player 1 is no longer p1Loc[0]>currentLoc+wu, but rather p2Loc[0]>currentLoc+wu. Depending on the value of p2Loc this may always be false.
This line:
currentLoc = p1Loc[0]; //global var with player's current location
is kinda scary. Don't use a global for this, especially when you re-assign its value on the second entry to the function:
currentLoc = p2Loc[0];
That's likely your problem.
If you need to keep track of a single player's position, create a player object and keep track of it in there, something like:
function Player(number) {
this.number = number
this.position = 0 //some default initial position
}
and pass this into moveRight()

Adobe edge play animation 3 times then stop on a specific frame

I have an animation created in Edge that I need to play 3 times and then stop on a specific frame.
I'm new to javascript and I think I need to use a variable and if/else statement, but am unsure what to use and how to write it. Any help would be much appreciated. Thank you!
Reluctantly I reply, really you need to provide some code to show your attempts. However, as this is a useful starter question I'll attempt an answer.
First thing you'll need is a global scoped variable to store the loop counter. Add something like this to your Stage.compositionComplete function.
// Add a numLoops variable to global storage
sym.setVariable("numLoops", 0);
Next at the end of your animation via the Timelines actions, create an event to capture that variable, increment, and replay the animation if applicable like so:
// capture numLoops variable and increment the counter
var numLoopsHolder = sym.getVariable("numLoops");
numLoopsHolder = numLoopsHolder + 1;
// set new numLoops variable back to global storage
sym.setVariable("numLoops", numLoopsHolder);
if (numLoopsHolder <= 2) {
// replay scene until 3 iterations are complete
sym.play(0);
}
This will get it looping 3 times, but you still need to add a stop check at the desired timeline location via:
// capture numLoops variable to check for 3 loops (ie. 0, 1, 2 = 3 loops)
var numLoopsHolder = sym.getVariable("numLoops");
if (numLoopsHolder >= 2) {
// we've completed 3 loops now stop here
sym.stop();
}
Here's a screenshot of the timeline for action event references.

How to trace in the console how many intervals are being executed - JavaScript

I have a problem trying to know if a setInterval() is taking place or it was killed.
I am creating an interval and saving it into a variable:
interval = setInterval('rotate()',3000);
Then on click to an element I stop the interval and wait 10 seconds before starting a new one, by the way the variable interval is global:
$(elm).click(function(){
clearInterval(interval);
position = index;
$('#banner div').animate({
'margin-left':position*(-img_width)
});
setTimeout('startItnerval()',10000);
});
function startItnerval(){
interval = setInterval('rotate()',3000);
}
It seems to work but eventually I can realize that there are intervals still being in place, everytime I start a new interval it is saved in the interval variable, which is global, so in theory even if I start 100 intervals they are all saved in the same variable replacing the previous interval right? So I should only have one instance of interval; then on clearInterval(interval); it should stop any instance.
After looking at the results, apparently even if it is saved in the same variable, they are all separate instances and need to be killed individually.
How can I trace how many intervals are being executed, and if possible identify them one by one? even if I am able to solve the problem I really would like to know if there is a way to count or show in the console how many intervals are being executed?
thanks
jsFiddle Demo
As pointed out in comments, the id's constantly increase as timers are added to a page. As a result, it may be possible to clear all timers running on a page like this:
function clearTimers(){
var t = window.setTimeout(function(){
var idMax = t;
for( var i = 0; i < idMax; i++ ){
window.clearInterval(i);
window.clearTimeout(i);
}
},4);
}
The reason that you can only see one interval is because every time you start a new interval, you overwrite the value in interval. This causes the previous intervals to be lost but still active.
A suggestion would be to just control access to your variable. Clearly there is an issue where the start function is called too often
clearInterval(interval);//when you clear it, null it
interval = null;
and then take advantage of that later
if( interval != null ){
interval = setInterval('rotate()',3000);
}
Also, as Pointy noted in a comment, using a string to call a function is not best practice. What it basically does is converts it into a Function expression which is similar to using eval. You should probably either use the function name as a callback
setInterval(rotate,3000);
or have an anonymous function issue the callback
setInterval(function(){ rotate(); },3000);
setInterval returns an Id, not the actual object, so no, no interval will be overriden if you repeat the line
var xy = setInterval(function() {...}, 1000);
If you want to stop the interval you have to clear it:
clearInterval(xy);
And if your startInterval can be called multiple times in a row, but you don't want to create multiple intervals, just clear the inverval before you start a new one:
function startInterval(){
clearInterval(interval);
interval = setInterval('rotate()',3000);
}
If you have to create multiple intervals, you could save the ids in an array to keep track of them:
var arr = [];
//set the interval
arr.push(setInterval(...));
//get number of currently running intervals
var count = arr.length //gives you the number of currently running intervals
//clear the interval with index i
clearInterval(arr[i]);
arr.splice(i, 1);

Javascript, object with set lifetime?

I have run in to a problem I do not know how to code in JavaScript really. The thing is I would like to be able to create a lot of objects added to an Array. when objects are created to be added to this array they will have a "lifetime". When this lifetime runs out this object should be removed from the array.
What Im trying to build here is a particle system where particles will vanish from being rendered after the particles lifetime in question have expired.
Anyone who have a good idea or example for this?
I have thought about using setTimeout, setInterval and clearInterval but not sure how this would be most effective.
Something like this?
Update for Felix Kling:
var a = [], next = function() {
a = a.slice(0,-1);
document.body.innerHTML += a.length + "<br />";
if (a.length != 0)
setTimeout(next, 100);
};
for (var i = 0; i < 100; i++) {
a.push({hi: 1});
}
setTimeout(next, 100);​
You can use the code sample of micha. On every call of "next" function you can update the state of you particles (position, velocity, etc). Also you can track the time of the creation of the particles and on every "next" call check if the current time minus the creation time exceeds certain constant and if it does then remove the particles. Depending on the required quality of the animation you may want to reduce the time between timeouts, e.g. setTimeout(next, 25);
Good luck :)

Categories

Resources