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?

有帮助吗?

解决方案

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');
});

其他提示

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top