I need help with keydown and keyup events

I’m working on a game and I’m trying to get the main character to move left and right while playing an animation. The animation plays and the character moves in the correct direction, when I press the arrow keys however the character teleports across the screen really fast, you can just about see the running animation play.

I can get the animation to go smoothly and even the character moving in any direction I want, its only when I try to apply the keyboard events I get this problem.

I’m still a beginner so I could be way off but I think this is happening because I put the code that updates the animation frames (setTimeout) in the same function as the code for the key inputs just can’t find a way around this.

Its not much so I’ll post all the code here. Thanks for any help.

[code]

//Image
//var sx = count;
var sy=64;
var sw=32;
var sh=32;
var dx=0;
var ypos=353;
var dw=32;
var dh=32;

xpos=50;
var count=0;
var count1=0;
var bulletxpos= xpos+27;
var bulletypos= ypos+23;

 var bullets = new Image ();

var shot = new Image ();
bullets.src=“Img/bullet.png”;
shot.src=“Img/shot.png”

function draw() {
//Create Canvas
var canvas = document.getElementById(“canvas”);
var ctx = canvas.getContext(“2d”);

//Draw images on canvas

 var pic= new Image ();
 var bullet=new Image ();

var deku= new Image ();
var img= new Image ();
dekub= new Image ();

pic.src=“Img/Background.png”;
deku.src=“Img/deku.png”;
img.src=“Img/Spritesheet1.png”;
;

//LOAD BACKGROUND
pic.addEventListener(“load”, function () {ctx.drawImage (pic,0,0) }, false);

         //LOAD MAIN CHARACTER
        img.addEventListener ("load", function stand () {ctx.drawImage (img, count, sy, sw, sh, xpos, ypos, dw, dh) }, false);

//BUTTONS

window.addEventListener(“keydown”, checkkey, false);
window.addEventListener(“keydown”, checkkeypress, false);
window.addEventListener(“keyup”, checkup, false);
window.addEventListener (“keyup”, checkkeyup, false);

//RIGHT KEY PRESS
function checkkey (key) {

if (key.keyCode==39) {

xpos=xpos+3;
sy=0;

if (count ==768)
count=0
else count=count+32;
}
}
//LEFT KEY PRESS
function checkkeypress (key) {

if (key.keyCode==37) {
xpos=xpos-3;
sy=32;
if (count ==736)
count=0
else count=count+32;
}
}
//RIGHT KEY RELEASE
function checkup (key) {
if (key.keyCode==39) {
sy=64;
if (count==480)
count=0;

else count=count+32;
}
}

//LEFT KEY RELEASE
function checkkeyup (key) {
if (key.keyCode==37) {
sy=96;
if (count==480)
count=0;

else count=count+32;
}
}

//ANIMATION SPEED
setTimeout(draw, 34);

//STAND AMIMATION
 if (count==480)
count=0; 

else count=count+32;

   

 }


   
        

</script>
[/code]

Hi there,

A couple of notes, you don’t need to use separate events for each type of key action. This will be easier to work with:

window.addEventListener("keydown", keydown, false);
window.addEventListener("keyup", keyup, false);

function keydown(event) {
  if (event.keyCode == 39) {
    moveRight();
  }
  else if (event.keyCode == 37) {
    moveLeft();
  }
}
function keyup(event) {
  if (y.keyCode==39) {
    stopMovingRight();
  }
  else if (key.keyCode==37) {
    stopMovingLeft();
  }
}

function moveRight() {  
}

function moveLeft() {
}

function stopMovingRight() {  
}

function stopMovingLeft() {
}

Set a variable for the speed of movement and use that in your functions.

var moveSpeed = .01;

function moveLeft() {
  xpos -= moveSpeed;
}

Rather than using setTimeout you should probably be using requestAnimationFrame for this.

function loop(timestamp) {
  // draw

  
  window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);

Thank you for the reply. The problem with requestanimationframe is I can’t change the frame rate for my animation. Its too fast.

You can use the technique here to get the time in milliseconds between frames.

In your draw functions you want to multiply the movementSpeed by timeElapsed to get a consistent rate of movement for a smooth animation.

I love you bro! It worked, thanks for the help.

1 Like

OK so I have a new problem. The longer I leave my game open the more the distance increases when I press the left/right keys. So when I open up my game the main characters movements are fine, one minute later and he starts teleporting again.

Can you post another snapshot of the code? It shouldn’t be doing that if your code looks like this:

function moveLeft() {
  xpos -= movementSpeed * timeSinceLastFrame;
}

It sounds like you may be multiplying by totalTotalElapsed, rather than the time since the last render.

Ah I changed it now. To be honest I had trouble understanding the tutorial in the link you sent me so I used another guide to help me.

Var time;
//ANIMATION SPEED
setTimeout(function() {
        requestAnimationFrame(draw);
       
    }, 1000 / fps);
    
    var now = new Date().getTime(),
        dt = now - (time || now);
 
    time = now;
function moveRight() {  
xpos+=moveSpeed*dt;
}

I do all my coding on my phone so I can’t test out keyboard inputs. My brother isn’t home right now so I can’t use his laptop. Do you see any problems with my code?

I just tested it and he still teleports.

Whoa, coding on your phone?!

Here is a working demo of the game loop, draw receives the time in milliseconds between renders.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>
<script type="text/javascript">
function draw(dt) {
  console.log(dt);
}

function loop(timestamp) {
  var now = new Date().getTime();
  var dt = now - time;
  draw(dt);
  time = now;
  window.requestAnimationFrame(loop);
}
var time = new Date().getTime();
window.requestAnimationFrame(loop);
</script>
</body>
</html>

Then you want to use the dt variable for every movement, he shouldn’t teleport then.

function moveLeft(dt) {
  xpos -= movementSpeed * dt;
}

Yeah I’m using an app called “Droidscript”, I should be getting my own laptop soon though.

I hate to keep troubling you but now when I press the left or right arrow keys he completely disappears. Here’s all the code.

<html>
 <head>
   <meta charset="utf-8">
    <body onload="draw ()">
  <script type="application/javascript">
  var moveSpeed=.01;
  
var sy=64;
var sw=32;
var sh=32;
var  dx=0;
var ypos=353;
var  dw=32;
var dh=32;
var time;

  xpos=50;
  var count=0;
  var count1=0;
  var bulletxpos= xpos+27;
  var bulletypos= ypos+23;
  
  
     var bullets = new Image ();
   var shot = new Image ();
   bullets.src="Img/bullet.png";
shot.src="Img/shot.png"



function draw(dt) {
  console.log(dt);


//Create Canvas
 
 var canvas = document.getElementById("canvas");
     
   var ctx = canvas.getContext("2d");
 
  //Draw images on canvas
  
     var pic= new Image ();
     var bullet=new Image ();
   var deku= new Image ();
     var img= new Image ();
     dekub= new Image ();
     

     
 

  
pic.src="Img/Background.png";
deku.src="Img/deku.png";
img.src="Img/Spritesheet1.png";
;

//LOAD BACKGROUND  
pic.addEventListener("load", function () {ctx.drawImage (pic,0,0) }, false);

             //LOAD MAIN CHARACTER
            img.addEventListener ("load", function stand () {ctx.drawImage (img, count, sy, sw, sh, xpos, ypos, dw, dh) }, false);


//BUTTONS

window.addEventListener("keydown", keydown, false);
window.addEventListener("keyup", keyup, false);

function keydown(event) {
  if (event.keyCode == 39) {
    moveRight(dt);
  }
  else if (event.keyCode == 37) {
    moveLeft(dt);
  }
}
function keyup(event) {
  if (y.keyCode==39) {
    stopMovingRight();
  }
  else if (key.keyCode==37) {
    stopMovingLeft();
  }
}

function moveRight(dt) {  
xpos+=moveSpeed * dt;
}


function moveLeft(dt) {
xpos-=moveSpeed*dt;
}

function stopMovingRight() {  
}

function stopMovingLeft() {
}



//ANIMATION SPEED


     //STAND AMIMATION
     if (count==480)
    count=0; 
    
    else count=count+32;
    
      
  
}     //END OF DRAW FUNCTION
   
 
      
function loop(timestamp) {
  var now = new Date().getTime();
  var dt = now - time;
  draw(dt);
  time = now;
  window.requestAnimationFrame(loop);
}
var time = new Date().getTime();
window.requestAnimationFrame(loop);
            
 
    </script>
 </head>

   <canvas id="canvas" width="640" height="400"></canvas>

 </body>
</html>

Deku Blaster(2)1.zip (29.7 KB)

Zip containing my game.

Ok, the main problem is that you’re calling your draw function on every frame, but it’s doing a lot more than draw :slight_smile: e.g. you’re binding the keypress - so when get around to pressing a key you’re running that function thousands of times and it will grind to a halt when you run out of memory.

Here is the crux of the game loop, the loop runs as fast as it can(60fps) and then on each frame you update the state of the world based on the inputs and then draw

function update(dt) {
  // STAND ANIMATION
  count += 32;
  if (count == 480) {
    count = 0;
  }
}

function draw(dt) {
  ctx.drawImage(pic, 0, 0);
  ctx.drawImage(img, count, sy, sw, sh, xpos, ypos, dw, dh);
}

function loop(timestamp) {
  var now = new Date().getTime();
  var dt = now - time;

  update(dt);
  draw(dt);

  time = now;
  window.requestAnimationFrame(loop);
}
var time = new Date().getTime();
window.requestAnimationFrame(loop); 

Rather than keypresses trying to move things they should only save their state changes.

var rightKeyDown = false;
var leftKeyDown = false;

function keydown(event) {
  if (event.keyCode == 39) {
    rightKeyDown = true;
  }
  else if (event.keyCode == 37) {
    leftKeyDown = true;
  }
}
function keyup(event) {
  if (event.keyCode == 39) {
    rightKeyDown = false;
  }
  else if (event.keyCode == 37) {
    leftKeyDown = false;
  }
}

window.addEventListener("keydown", keydown, false);
window.addEventListener("keyup", keyup, false);

And then your update function does the updates.

function update(dt) {
  if (rightKeyDown) {
    xpos += moveSpeed * dt;
  }
  if (leftKeyDown) {
    xpos -= moveSpeed * dt;
  }

  // STAND AMIMATION
  count += 32;
  if (count == 480) {
    count = 0;
  }
}

Putting that all together gives you this

<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
<canvas id="canvas" width="640" height="400"></canvas>
<canvas id="toy" width="18" height="32"></canvas>
<script type="application/javascript">
var moveSpeed=.1;

var sy=64;
var sw=32;
var sh=32;
var ypos=353;
var dw=32;
var dh=32;
var xpos=50;
var count=0;

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

// Preload images
var pic = new Image();
var img=  new Image();
pic.src = "Img/Background.png";
img.src = "Img/Spritesheet1.png";

var rightKeyDown = false;
var leftKeyDown = false;

function keydown(event) {
  if (event.keyCode == 39) {
    rightKeyDown = true;
  }
  else if (event.keyCode == 37) {
    leftKeyDown = true;
  }
}
function keyup(event) {
  if (event.keyCode == 39) {
    rightKeyDown = false;
  }
  else if (event.keyCode == 37) {
    leftKeyDown = false;
  }
}

window.addEventListener("keydown", keydown, false);
window.addEventListener("keyup", keyup, false);

function update(dt) {
  if (rightKeyDown) {
    xpos += moveSpeed * dt;
  }
  if (leftKeyDown) {
    xpos -= moveSpeed * dt;
  }

  // STAND AMIMATION
  count += 32;
  if (count == 480) {
    count = 0;
  }
}

function draw(dt) {
  ctx.drawImage(pic, 0, 0);
  ctx.drawImage(img, count, sy, sw, sh, xpos, ypos, dw, dh);
}

function loop(timestamp) {
  var now = new Date().getTime();
  var dt = now - time;

  update(dt);
  draw(dt);

  time = now;
  window.requestAnimationFrame(loop);
}
var time = new Date().getTime();
window.requestAnimationFrame(loop);

</script>
</body>
</html>

Do yourself a favour and watch https://vimeo.com/105955605 it will teach you a lot about making games in js. Moving to a more Object Oriented approach will help you clean things up and not rely on global variables for all the state.

2 Likes

Hey dude! Sorry this is a little late, but thanks for all the help. My game works fine now, you helped me out more than you know. Stay safe bro.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.