While everyone here is right, what they're missing is that you need to put a delay on the firing, not on the event being called...
Inside of your keydown event, set a timestamp, have a previous-time and a current-time for the event.
Inside of the function, have a time_limit.
So when you press the key (or it fires repeatedly), check for:
current_time - last_fired >= rate_limit;
If the current time is more than 3000ms since the last shot, then set the last_fired
timestamp to the current time, and fire your weapon.
EDIT
Consider this trivial example:
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]; });
Inside of your gameloop, you're now going to do things a little differently:
Your player is going to update itself.
Inside of that update, it's asking the Keyboard if it's got the shoot key pressed down.
If it is, then it will call the shoot method.
This still isn't 100% correct, as Player shouldn't care about or know about Keyboard.
It should be handled through a service of some kind, rather than asking for window.Keyboard
.
Regardless...
Your controls are now wrapped inside of the player -- so you can define what those controls are, rather than asking by keyCode
all over the place.
Your events are now doing what they should: setting the key and going away.
In your current iteration, every time the browser fires keydown
, which might be 300x/sec, if it wanted to, that event ALSO has to call all of your player logic... 300x/sec...
In larger games, you could then take this a step further, and make components out of Controls
and Health
, each having all of the properties and all of the methods that they need to do their own job, and nothing else.
Breaking the code up this way would also make it dirt-simple to have different guns.
Imagine an Inventory
component:
The inventory contains different guns
.
Each gun
has its own rateLimit
, has its own lastFired
, has its own bulletCount
, does its own damage
, and fires its own bulletType
.
So then you'd call player.shoot();
, and inside, it would call inventory.equipped.shoot();
.
That inner function would take care of all of the logic for firing the equipped gun (because you'd inventory.add(Gun);
to your guns, and inventory.equip(id);
the gun you want.