虽然这里的每个人都是正确的,但他们忽略了你需要在触发事件之前设置延迟,而不是在调用事件上设置延迟......
在你的keydown事件内,设置一个时间戳,为事件设置一个previous-time和current-time。在函数内部,有一个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; }
gun.lastFired = currentTime;
}
function update () {
if (Keyboard[controls.shoot] || gun.charging) { this.shoot(); }
}
function draw (ctx) { }
public_interface = {
shoot : shoot,
damage : function (amt) { isHurt = true; }
draw : draw,
update : update
};
return public_interface;
}());
document.addEventListener("keydown", function (e) {
if (!!Keyboard[e.keyCode]) { return; }
Keyboard[e.keyCode] = e.timeStamp;
});
document.addEventListener("keyup", function (e) { delete Keyboard[e.keyCode]; });
在你的游戏循环中,现在你需要做一些不同的事情:
你的玩家将更新自己。
在这个更新中,它会询问键盘是否按下了射击键。
如果是的话,那么它将调用射击方法。
这仍然不是100%正确的,因为玩家不应该关心或知道键盘。
它应该通过某种服务来处理,而不是请求window.Keyboard
。
无论如何...
现在,你的控制已经包含在玩家内部——因此你可以定义这些控制,而不是到处询问keyCode
。
现在你的事件正在做它们应该做的事情:设置键并离开。
在你目前的迭代中,每当浏览器触发keydown
时,可能是300次/秒,如果它想的话,那个事件也必须调用所有的玩家逻辑... 300次/秒...
在更大的游戏中,你可以进一步采取这一步,将Controls
和Health
组件分别制作出来,每个组件都有它们所需的所有属性和方法,而没有其他东西。
以这种方式分解代码也会使得拥有不同枪支变得非常简单。
想象一下一个Inventory
组件:
库存包含不同的guns
。
每个gun
都有自己的rateLimit
,有自己的lastFired
,有自己的bulletCount
,做自己的damage
,并发射自己的bulletType
。
然后你会调用player.shoot();
,在内部,它将调用inventory.equipped.shoot();
。
那个内部函数将负责所有装备枪支的逻辑(因为你会inventory.add(Gun);
到你的枪支中,并inventory.equip(id);
你想要的枪支)。
setTimeout(alert("DONE NOW"), 86400 * 1000)
(这会立即显示警报,但是要求“等待”一天 :-)) - user166390