I have the following problem:
I'm trying to write a Javascript game, and the character is being controlled by the arrow keys.
The problem is, when one keeps the key pressed, there is a short delay between firing the first keypress
and the repeated keypress
.
Also, when one presses the "right arrow key" and keeps it pressed, and then presses the "up arrow key" the character doesn't move to the top right corner, but stops the moving in the right direction and starts moving up.
This is the code I'm using:
<body onLoad="Load()" onKeyDown="Pressed(event)">
function Pressed(e) { cxc = e.keyCode; if(cxc == 37) Move(-1,0); if(cxc == 38) Move(0,-1); if(cxc == 39) Move(1,0); if(cxc == 40) Move(0,1); }
Does anybody have an idea?
If you want key repeat in a controllable fashion, you will have to implement it yourself, as keypress events are fired dependent on the OS's idea of how keys should repeat. That means there may be variable initial and following delays, and holding down two keys at once will cause only one of them to repeat.
You will have to keep a record of whether each key is currently pressed, and ignore keydown
events when the key is already down. This is because many browsers will fire a keydown
as well as a keypress
event when an autorepeat occurs, and if you're reproducing key repeat yourself you'll need to suppress that.
For example:
// Keyboard input with customisable repeat (set to 0 for no key repeat)
//
function KeyboardController(keys, repeat) {
// Lookup of key codes to timer ID, or null for no repeat
//
var timers= {};
// When key is pressed and we don't already think it's pressed, call the
// key action callback and set a timer to generate another one after a delay
//
document.onkeydown= function(event) {
var key= (event || window.event).keyCode;
if (!(key in keys))
return true;
if (!(key in timers)) {
timers[key]= null;
keys[key]();
if (repeat!==0)
timers[key]= setInterval(keys[key], repeat);
}
return false;
};
// Cancel timeout and mark key as released on keyup
//
document.onkeyup= function(event) {
var key= (event || window.event).keyCode;
if (key in timers) {
if (timers[key]!==null)
clearInterval(timers[key]);
delete timers[key];
}
};
// When window is unfocused we may not get key events. To prevent this
// causing a key to 'get stuck down', cancel all held keys
//
window.onblur= function() {
for (key in timers)
if (timers[key]!==null)
clearInterval(timers[key]);
timers= {};
};
};
then:
// Arrow key movement. Repeat key five times a second
//
KeyboardController({
37: function() { Move(-1, 0); },
38: function() { Move(0, -1); },
39: function() { Move(1, 0); },
40: function() { Move(0, 1); }
}, 200);
Although, most action-based games have a fixed-time main frame loop, which you can tie the key up/down handling into.
I've solved it like this:
var pressedl = 0; var pressedu = 0; var pressedr = 0; var pressedd = 0; function Down(e) { cxc = e.keyCode; if(cxc == 37) pressedl = 1; if(cxc == 38) pressedu = 1; if(cxc == 39) pressedr = 1; if(cxc == 40) pressedd = 1; //alert(cxc); } function Up(e) { cxc = e.keyCode; if(cxc == 37) pressedl = 0; if(cxc == 38) pressedu = 0; if(cxc == 39) pressedr = 0; if(cxc == 40) pressedd = 0; //alert(cxc); }
<body onLoad="Load()" onKeyDown="Down(event)" onKeyUp="Up(event)">
You could start the movement onkeydown and only end it onkeyup?
This is nearly the same as the excellent answer from @bobince
I've amended it slightly to allow individual values for the interval
// Keyboard input with customisable repeat (set to 0 for no key repeat)
// usage
/**
KeyboardController({
32: {interval:0, callback: startGame },
37: {interval:10, callback: function() { padSpeed -= 5; } },
39: {interval:10, callback: function() { padSpeed += 5; } }
});
*/
function KeyboardController(keyset) {
// Lookup of key codes to timer ID, or null for no repeat
//
var timers= {};
// When key is pressed and we don't already think it's pressed, call the
// key action callback and set a timer to generate another one after a delay
//
document.onkeydown= function(event) {
var key= (event || window.event).keyCode;
if (!(key in keyset))
return true;
if (!(key in timers)) {
timers[key]= null;
keyset[key].callback();
if (keyset[key].interval !== 0)
timers[key]= setInterval(keyset[key].callback, keyset[key].interval);
}
return false;
};
// Cancel timeout and mark key as released on keyup
//
document.onkeyup= function(event) {
var key= (event || window.event).keyCode;
if (key in timers) {
if (timers[key]!==null)
clearInterval(timers[key]);
delete timers[key];
}
};
// When window is unfocused we may not get key events. To prevent this
// causing a key to 'get stuck down', cancel all held keys
//
window.onblur= function() {
for (key in timers)
if (timers[key]!==null)
clearInterval(timers[key]);
timers= {};
};
};
I've also got a plan to use setTimeout instead of setInterval for the reasons given in this question: setTimeout or setInterval?
I'll update this answer once I've amended and tested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With