augu0454
augu0454

Reputation: 45

Moving elements is delayed when I'm using the onKeyDown event

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

Answers (2)

James Thorpe
James Thorpe

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

ebyrob
ebyrob

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

Related Questions