Reputation: 45
I am trying to make an element move when I hold down a key (left or right arrow in this case), but when I hold down a key the movement is delayed by about a second. Am I using the wrong event or is there anything wrong with my code?
I am using the onKeyDown
event to trigger the movement.
<head>
<script>
var objX = 100;
function blockMove(e){
if (e.keyCode == 37) { //move left
objX-=4;
document.getElementById("object").style.left = objX + "px";
} else if (e.keyCode == 39) { //move right
objX+=4;
document.getElementById("object").style.left = objX + "px";
}
}
</script>
</head>
<body onkeydown="blockMove(event)">
<div id=object style="height:10px;width:80px;background-color:red;position:absolute;top:50px;left:100px"></div>
</body>
Upvotes: 0
Views: 414
Reputation: 32202
Rather than relying on the users keyboard repeat rate, which is what's ultimately causing the multiple calls to blockMove
, you should instead use a timer to check if the object should be moving at a consistent rate (every 20ms in my below example). This means it will be a consistent experience for all users, no matter their repeat rate setting.
You then need to keep track of whether the object should be moving. By using the keydown
and keyup
events, we can keep track of whether left and right are currently pressed, then just check those values within your existing blockMove
function:
//object to keep current state of keys
var keys = {
left: false,
right: false
};
function keydown(e) {
//remember "down" state
if (e.keyCode == 37)
keys.left = true;
if (e.keyCode == 39)
keys.right = true;
}
function keyup(e) {
//forget "down" state
if (e.keyCode == 37)
keys.left = false;
if (e.keyCode == 39)
keys.right = false;
}
var objX = 100;
function blockMove(){
//now check the key state, rather than the event object
if (keys.left) { //move left
objX -= 4;
}
if (keys.right) { //move right
objX += 4;
}
document.getElementById("object").style.left = objX + "px";
}
//Call the movement function every 20ms
window.setInterval(blockMove, 20);
<body onkeydown="keydown(event)" onkeyup="keyup(event)">
<div id=object style="height:10px;width:80px;background-color:red;position:absolute;top:50px;left:100px"></div>
</body>
As discussed in the comments below, setInterval
only guarantees a minimum time before a function will be called, and can be subject to throttling. Along with moving DOM objects around, it's fine for learning the basics like this, but at some point you may want to look at drawing directly onto <canvas>
elements and using requestAnimationFrame
for handling the callbacks, as it's designed for animation, unlike setTimeout
/setInterval
.
Upvotes: 2
Reputation: 674
Bear with me, this is kind of long and possibly buggy: (also a spoiler if you want to do it yourself)
<head>
<script>
var objX = 100;
var leftDown = false;
var rightDown = false;
function blockMove(e){
if(e.keyCode == 37 && !leftDown) { //move left
leftDown = true;
objX-=4;
document.getElementById("object").style.left = objX + "px";
}else if(e.keyCode == 39 && !rightDown) { //move right
rightDown = true;
objX+=4;
document.getElementById("object").style.left = objX + "px";
}}
function stopMove(e)
{
if( e.keyCode == 37 )
leftDown = false;
if( e.keyCode == 39 )
rightDown = false;
}
function timer()
{
if( leftDown )
objX -= 4;
if( rightDown )
objX += 4;
document.getElementById("object").style.left = objX + "px";
}
setInterval(timer, 100);
</script>
</head>
<body onkeydown="blockMove(event)" onkeyup="stopMove(event)">
<div id=object
style="height:10px;width:80px;background-color:red;position:absolute;top:360px;left:100px"
></div>
</body>
Upvotes: 1