3

当我连续按下 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();

任何建议将被认真考虑!

谢谢

4

5 回答 5

6

1.:setTimeout()返回一个timeoutId可以用 清除的clearTimeout(timeoutId)。你没有这样做......所以,在你的 3 秒延迟之后,所有这些超时都被称为背靠背。

2.:你console.log的被立即执行,因为你没有将它包装在这样的函数中:

setTimeout(function() { console.log(mcount++) }, 3000);
于 2012-09-27T20:38:54.420 回答
4

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

你不能在 Javascript 中“睡觉”,你需要重构你的代码,以便它可以处理事件。对于您的代码,您似乎需要在第一次按键时设置一个标志。然后返回,并且只允许新的按键(即只响应),当标志被清除时。然后可以在一段时间后自动清除该标志setTimeout

于 2012-09-27T20:38:03.580 回答
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 个玩家,每个玩家都有不同的射速。如果您按住空格键,您可以看到这一点。

于 2012-09-27T21:38:51.453 回答
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]; });

在你的游戏循环中,你现在要做一些不同的事情:
你的玩家将自我更新。
在该更新中,它询问键盘是否按下了拍摄键。
如果是,那么它会调用 shoot 方法。

这仍然不是 100%正确,因为玩家不应该关心或知道键盘。
它应该通过某种服务来处理,而不是要求window.Keyboard. 不管...

您的控件现在被包裹在播放器内部——因此您可以定义这些控件是什么,而不是到处询问keyCode

您的事件现在正在做他们应该做的事情:设置密钥并离开。
在您当前的迭代中,每次浏览器触发时,可能是300xkeydown /sec,如果它愿意,该事件还必须调用您的所有播放器逻辑... 300x/sec...

在更大的游戏中,您可以更进一步,用 and 制作组件ControlsHealth每个组件都具有完成自己工作所需的所有属性和方法,仅此而已。

以这种方式分解代码也会使拥有不同的枪支变得非常简单。
想象一个Inventory组件:
库存包含不同的guns.
每个gun人都有自己的rateLimit,有自己的lastFired,有自己的bulletCount,做自己的,自己damage开火bulletType

所以你会打电话player.shoot();,在里面,它会打电话inventory.equipped.shoot();
该内部函数将负责射击装备好的枪的所有逻辑(因为你会inventory.add(Gun);使用你的枪和inventory.equip(id);你想要的枪。

于 2012-09-27T20:45:17.400 回答
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();
于 2012-09-27T20:39:59.320 回答