Reputation: 546
What I have is an element that have been linked with a keydown event.
The answer in similar questions all pointed to clearInterval, which I can't get to work.
First of all, I am using keyup events to check which arrow key is being pressed:
var counter = 0;
var yPosArray = [];
var right = true;
var done = false;
var leftX;
var rightX;
$(document).keydown (function(e)
{
rightX = parseInt(($('#movingObject').css('left')).replace('px','')) + 50;
leftX = parseInt(($('#movingObject').css('left')).replace('px',''));
if(e.which == 39)// right
{
$('#movingObject').find('img').attr('src','assets/images/mario_right.png');
right = true;
$('#xRight').val(rightX);
$('#xLeft').val(leftX);
move();
}
if(e.which == 37) //left
{
$('#movingObject').find('img').attr('src','assets/images/mario_left.png');
right = false;
$('#xRight').val(rightX);
$('#xLeft').val(leftX);
move();
}
if(e.which == 38) //up
{
if($('#movingObject').css('bottom') == '0px' && !false)
{
done = true;
gravity();
done = false;
}
}
});
As seen above, when this condition, e.which == 37
, is met, the method move()
is called. What the move method does, as seen below is to increase the element's left
style attribute. The reason I have a timer, is so that the speed increases as the time goes by, but when the key is released, the event should stop firing. Because of this, I want to call the keyup event as seen in my last code snippet. Explanation will continue there.
var speed = 0;
var maxspeed = 0;
var timer;
function move()
{
var counter = 0;
timer = setInterval(function ()
{
maxspeed++;
$('#movingObject').css('left', moveX + maxspeed + 'px');
++counter;
}, 70);
}
As seen above, the timer variable was declared before the move
function was created, where it was set to the setInterval
method. Because the variable is on the root level, if that makes sense, it can be used in all functions.
As seen below, I have initiated the keyup event to check for the different keys.
$(document).keyup (function(e)
{
var posX = parseInt(($('#movingObject').css('left')).replace('px',''));
if(e.which == 39)// right
{
maxspeed = 0;
clearInterval(timer);
timer = 0;
}
if(e.which == 37) //left
{
maxspeed = 0;
clearInterval(timer);
timer = 0;
}
$('#movingObject').css('left', posX + 'px');
});
Above, I used clearInterval and tried setting timer
equal to 0,after which it continues to increase.
Here's a fiddle with all my script for the stucture of my code.
Any ideas why this is happening?
Upvotes: 0
Views: 1057
Reputation: 1210
Each time the setInterval
will create a new timer
,so when you clearInterval
you have to clear all the timer(maybe some of them) you created.See this blow:
var speed = 0;
var maxspeed = 0;
var timer=[];
function move()
{
var counter = 0;
timer.push(setInterval(function ()
{
maxspeed++;
$('#movingObject').css('left', moveX + maxspeed + 'px');
++counter;
}, 70));
}
$(document).keyup (function(e)
{
var posX = parseInt(($('#movingObject').css('left')).replace('px',''));
if(e.which == 39)// right
{
maxspeed = 0;
$.each(timer,function(i,n){
clearInterval(n);
});
timer=[];
}
if(e.which == 37) //left
{
maxspeed = 0;
$.each(timer,function(i,n){
clearInterval(n);
});
timer=[];
}
$('#movingObject').css('left', posX + 'px');
});
Upvotes: 1
Reputation: 664444
This can happen when a user presses two (or more) keys at the same time. Then you will call move()
subsequently without a keyup in between that clears the an interval - which means you're overwriting the timer
interval id of the first one and never will be able to stop it again, basically having forgotten it when the keyup happens.
How to solve this? There are some choices:
Have only one interval running at one time. That can easily be implemented by preceding every timer = setInterval(…)
with clearInterval(timer)
(nothing will happen if it was already cleared).
Have a set of running intervals. An array, as @jarvanJiang implemented it, doesn't make much sense since you don't want to stop all intervals if only one key was released (as in while(timers.length) clearInterval(timers.pop())
). Neither does a kind of FIFO queue where the oldest intervals are cleared.
Instead, you want one timer id per key - a map of running intervals. When a key is released, you can determine which of the intervals you want to clear by looking it up in the map.
Even better to implement would be only one interval, the game loop, and a map of boolean keys indicating which ones are currently pressed. This will allow you to manage interfering inputs, and make animations run smoother.
Upvotes: 1