为什么JavaScript setTimeout不会降低keydown的速度?

时间:2012-09-27 20:36:20

标签: javascript jquery

为什么当我连续按下keydown事件(字母k)时,以下keydown事件不会减慢3000 mil?如果我把手指放下,计数会迅速加起来,因为mcount上没有setTimeout。这是为什么?每次计数之间应该有延迟,但我无法让它工作......

var mcount = 0;
function playershoot() {
if(!game.playerHit){ 
      $(document).keydown(function(e){ 
        switch(e.keyCode){
        case 75: 
        clearTimeout();
        setTimeout(console.log(mcount++), 3000);
        break;
        }
    });
}

}
playershoot();

任何建议都将不胜感激!

由于

5 个答案:

答案 0 :(得分:6)

1:setTimeout()返回timeoutId,可以使用clearTimeout(timeoutId)清除该console.log。你没有这样做......所以,在你的3秒延迟之后,所有这些超时都会被召回。

2:你的setTimeout(function() { console.log(mcount++) }, 3000); 被立即执行,因为你没有将它包装在这样的函数中:

{{1}}

答案 1 :(得分:4)

setTimeout不会导致延迟,它会启动一个计时器,在指定的时间后触发事件。

You cannot "sleep" in Javascript,您需要重构代码,以便它可以处理事件。对于您的代码,看起来您需要在第一次按键时设置标志。然后返回,并且仅在标志被清除时才允许新的按键(即仅响应)。然后可以在setTimeout的时间后自动清除该标志。

答案 2 :(得分:4)

与@Norguard所说的一样,这是一个实现:http://jsfiddle.net/apu3P/

this.fire = function(){
    var cFire = new Date();

    if ((cFire - lastFire) / 1000 > 1/me.fireRate){            
        // code to fire the projectile
        lastFire = cFire;
    }
};

我将fireRate设置为一个整数,表示玩家可以每秒发射多少次。

在演示中,我设置了3个玩家,每个玩家都有不同的火力。如果按住空格键,您可以看到这一点。

答案 3 :(得分:2)

虽然这里的每个人都是正确的,但他们缺少的是你需要延迟解雇,而不是被召唤的事件......

在keydown事件内部,设置时间戳,具有事件的上一个时间和当前时间。 在函数内部,有一个time_limit。

因此,当您按键(或反复触发)时,请检查:

current_time - last_fired >= rate_limit;

如果自上次拍摄后当前时间超过3000毫秒,则将last_fired时间戳设置为当前时间,然后开火。

修改

考虑这个简单的例子:

var Keyboard = {};

var player = (function () {
    var gun = {
            charging  : false,
            lastFired : 0,
            rateLimit : 3000
        },

        controls = { shoot : 75 },

        isHit = false,
        public_interface;


    function shoot () {
        var currentTime = Date.now();

        if (gun.rateLimit > currentTime - gun.lastFired) { return; }
        /* make bullet, et cetera */

        gun.lastFired = currentTime;
    }

    function update () {
        if (Keyboard[controls.shoot] || gun.charging) { this.shoot(); }
        // if key was released before this update, then the key is gone...
        // but if the gun was charging, that means that it's ready to be fired

        // do other updates
    }

    function draw (ctx) { /* draw player */ }

    public_interface = {
        shoot : shoot,
        damage : function (amt) { isHurt = true; /* rest of your logic */ }
        draw : draw,
        update : update
    };

    return public_interface;

}());


document.addEventListener("keydown", function (e) {
    // if key is already down, exit
    if (!!Keyboard[e.keyCode]) { return; }
    // else, set the key to the time the key was pressed
    // (think of "charging-up" guns, based on how long you've held the button down)
    Keyboard[e.keyCode] = e.timeStamp;
});

document.addEventListener("keyup", function (e) { delete Keyboard[e.keyCode]; });

在你的游戏循环中,你现在要做的事情有点不同:
您的播放器将自行更新。
在更新内部,它询问键盘是否按下了拍摄键 如果是,则会调用拍摄方法。

这仍然不是100%正确,因为播放器不应该关心或了解键盘。
它应该通过某种服务来处理,而不是要求window.Keyboard。 无论...

您的控件现在已包含在播放器中 - 因此您可以定义这些控件的内容,而不是在整个地方keyCode询问。

你的活动现在正在做他们应该做的事情:设置钥匙然后离开 在您当前的迭代中,每当浏览器触发keydown(可能是300x /秒)时,如果需要,该事件 ALSO 必须调用所有你的玩家逻辑... 300x / sec ......

在较大的游戏中,您可以更进一步,并使用ControlsHealth制作组件,每个组件都具有所有属性以及执行所需的所有方法自己的工作,没有别的。

以这种方式打破代码也会使得使用不同枪支变得简单 想象一个Inventory组件:
广告资源包含不同的guns 每个gun都有自己的rateLimit,有自己的lastFired,有自己的bulletCount,有自己的damage,并自行激活bulletType }。

那么你就打电话给player.shoot();,在里面,它会打电话给inventory.equipped.shoot(); 这个内在的功能将照顾所有射击装备枪的逻辑(因为你inventory.add(Gun);你的枪,inventory.equip(id);你想要的枪。

答案 4 :(得分:1)

您必须将setTimeout的返回值传递给clearTimeout。取消它。

var mcount = 0,timeout;
    function playershoot() {
    if(!game.playerHit){ 
          $(document).keydown(function(e){ 
            switch(e.keyCode){
            case 75: 
            clearTimeout(timeout );
            timeout = setTimeout(function(){
                       console.log(mcount++);
               }, 3000);
            break;
            }
        });
    }

    }
    playershoot();